150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov/* 250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * Copyright (C) 2010 The Android Open Source Project 350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * 450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * Licensed under the Apache License, Version 2.0 (the "License"); 550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * you may not use this file except in compliance with the License. 650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * You may obtain a copy of the License at 750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * 850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * http://www.apache.org/licenses/LICENSE-2.0 950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * 1050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * Unless required by applicable law or agreed to in writing, software 1150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * distributed under the License is distributed on an "AS IS" BASIS, 1250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * See the License for the specific language governing permissions and 1450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * limitations under the License. 1550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 1650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 1750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganovpackage android.widget; 1850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 19e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganovimport android.annotation.Widget; 2050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganovimport android.app.Service; 2150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganovimport android.content.Context; 22f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganovimport android.content.res.Configuration; 2350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganovimport android.content.res.TypedArray; 2450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganovimport android.database.DataSetObserver; 2550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganovimport android.graphics.Canvas; 2650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganovimport android.graphics.Paint; 2750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganovimport android.graphics.Paint.Align; 2850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganovimport android.graphics.Paint.Style; 2950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganovimport android.graphics.Rect; 3050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganovimport android.graphics.drawable.Drawable; 31e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganovimport android.text.TextUtils; 3250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganovimport android.text.format.DateUtils; 3350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganovimport android.util.AttributeSet; 34e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganovimport android.util.DisplayMetrics; 35e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganovimport android.util.Log; 3650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganovimport android.util.TypedValue; 3750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganovimport android.view.GestureDetector; 3850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganovimport android.view.LayoutInflater; 3950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganovimport android.view.MotionEvent; 4050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganovimport android.view.View; 4150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganovimport android.view.ViewGroup; 428a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganovimport android.view.accessibility.AccessibilityEvent; 438a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganovimport android.view.accessibility.AccessibilityNodeInfo; 4450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganovimport android.widget.AbsListView.OnScrollListener; 4550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 461442da620c117910e7628b36efc32ff962be02b2Svetoslav Ganovimport com.android.internal.R; 471442da620c117910e7628b36efc32ff962be02b2Svetoslav Ganov 48e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganovimport java.text.ParseException; 49e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganovimport java.text.SimpleDateFormat; 5050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganovimport java.util.Calendar; 5150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganovimport java.util.Locale; 52e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganovimport java.util.TimeZone; 5350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 5450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganovimport libcore.icu.LocaleData; 5550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 5650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov/** 57e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * This class is a calendar widget for displaying and selecting dates. The range 58e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * of dates supported by this calendar is configurable. A user can select a date 59e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * by taping on it and can scroll and fling the calendar to a desired date. 60e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * 61e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @attr ref android.R.styleable#CalendarView_showWeekNumber 62e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @attr ref android.R.styleable#CalendarView_firstDayOfWeek 63e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @attr ref android.R.styleable#CalendarView_minDate 64e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @attr ref android.R.styleable#CalendarView_maxDate 65e51f94cfe9f97e13dad0e564dfc92b22e70c296dSvetoslav Ganov * @attr ref android.R.styleable#CalendarView_shownWeekCount 66e51f94cfe9f97e13dad0e564dfc92b22e70c296dSvetoslav Ganov * @attr ref android.R.styleable#CalendarView_selectedWeekBackgroundColor 67e51f94cfe9f97e13dad0e564dfc92b22e70c296dSvetoslav Ganov * @attr ref android.R.styleable#CalendarView_focusedMonthDateColor 68e51f94cfe9f97e13dad0e564dfc92b22e70c296dSvetoslav Ganov * @attr ref android.R.styleable#CalendarView_unfocusedMonthDateColor 69e51f94cfe9f97e13dad0e564dfc92b22e70c296dSvetoslav Ganov * @attr ref android.R.styleable#CalendarView_weekNumberColor 70e51f94cfe9f97e13dad0e564dfc92b22e70c296dSvetoslav Ganov * @attr ref android.R.styleable#CalendarView_weekSeparatorLineColor 71e51f94cfe9f97e13dad0e564dfc92b22e70c296dSvetoslav Ganov * @attr ref android.R.styleable#CalendarView_selectedDateVerticalBar 72e51f94cfe9f97e13dad0e564dfc92b22e70c296dSvetoslav Ganov * @attr ref android.R.styleable#CalendarView_weekDayTextAppearance 73e51f94cfe9f97e13dad0e564dfc92b22e70c296dSvetoslav Ganov * @attr ref android.R.styleable#CalendarView_dateTextAppearance 7450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 75e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov@Widget 76e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganovpublic class CalendarView extends FrameLayout { 7750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 7850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 79e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Tag for logging. 80e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov */ 81e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private static final String LOG_TAG = CalendarView.class.getSimpleName(); 82e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 83e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov /** 84e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Default value whether to show week number. 8550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 86e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private static final boolean DEFAULT_SHOW_WEEK_NUMBER = true; 87e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 88e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov /** 89e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * The number of milliseconds in a day.e 90e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov */ 91e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private static final long MILLIS_IN_DAY = 86400000L; 9250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 9350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 9450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * The number of day in a week. 9550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 96e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private static final int DAYS_PER_WEEK = 7; 9750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 9850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 9950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * The number of milliseconds in a week. 10050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 101e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private static final long MILLIS_IN_WEEK = DAYS_PER_WEEK * MILLIS_IN_DAY; 10250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 10350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 104e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Affects when the month selection will change while scrolling upe 105e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov */ 106e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private static final int SCROLL_HYST_WEEKS = 2; 10750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 10850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 10950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * How long the GoTo fling animation should last. 11050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 111e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private static final int GOTO_SCROLL_DURATION = 1000; 11250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 11350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 11450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * The duration of the adjustment upon a user scroll in milliseconds. 11550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 116e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private static final int ADJUSTMENT_SCROLL_DURATION = 500; 11750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 11850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 11950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * How long to wait after receiving an onScrollStateChanged notification 12050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * before acting on it. 12150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 122e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private static final int SCROLL_CHANGE_DELAY = 40; 12350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 12450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 125e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * String for parsing dates. 12650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 127e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private static final String DATE_FORMAT = "MM/dd/yyyy"; 128e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 129e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov /** 130e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * The default minimal date. 131e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov */ 132e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private static final String DEFAULT_MIN_DATE = "01/01/1900"; 133e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 134e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov /** 135e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * The default maximal date. 136e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov */ 137e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private static final String DEFAULT_MAX_DATE = "01/01/2100"; 138e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 139e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private static final int DEFAULT_SHOWN_WEEK_COUNT = 6; 140e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 141e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private static final int DEFAULT_DATE_TEXT_SIZE = 14; 142e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 143e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private static final int UNSCALED_SELECTED_DATE_VERTICAL_BAR_WIDTH = 6; 144e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 145e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private static final int UNSCALED_WEEK_MIN_VISIBLE_HEIGHT = 12; 146e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 147e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private static final int UNSCALED_LIST_SCROLL_TOP_OFFSET = 2; 148e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 149e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private static final int UNSCALED_BOTTOM_BUFFER = 20; 150e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 151e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private static final int UNSCALED_WEEK_SEPARATOR_LINE_WIDTH = 1; 152e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 153e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private static final int DEFAULT_WEEK_DAY_TEXT_APPEARANCE_RES_ID = -1; 154e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 155e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private final int mWeekSeperatorLineWidth; 156e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 157ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov private int mDateTextSize; 158e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 159ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov private Drawable mSelectedDateVerticalBar; 160e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 161e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private final int mSelectedDateVerticalBarWidth; 162e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 163ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov private int mSelectedWeekBackgroundColor; 164e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 165ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov private int mFocusedMonthDateColor; 166e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 167ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov private int mUnfocusedMonthDateColor; 168e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 169ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov private int mWeekSeparatorLineColor; 170e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 171ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov private int mWeekNumberColor; 172ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov 173ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov private int mWeekDayTextAppearanceResId; 174ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov 175ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov private int mDateTextAppearanceResId; 17650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 17750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 17850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * The top offset of the weeks list. 17950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 180e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private int mListScrollTopOffset = 2; 18150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 18250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 18350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * The visible height of a week view. 18450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 185e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private int mWeekMinVisibleHeight = 12; 18650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 18750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 18850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * The visible height of a week view. 18950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 190e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private int mBottomBuffer = 20; 19150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 19250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 19350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * The number of shown weeks. 19450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 195e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private int mShownWeekCount; 19650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 19750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 19850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * Flag whether to show the week number. 19950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 200e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private boolean mShowWeekNumber; 20150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 20250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 203e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * The number of day per week to be shown. 20450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 205e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private int mDaysPerWeek = 7; 20650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 20750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 20850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * The friction of the week list while flinging. 20950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 210e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private float mFriction = .05f; 21150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 21250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 21350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * Scale for adjusting velocity of the week list while flinging. 21450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 215e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private float mVelocityScale = 0.333f; 21650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 21750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 21850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * The adapter for the weeks list. 21950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 220e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private WeeksAdapter mAdapter; 22150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 22250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 22350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * The weeks list. 22450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 225e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private ListView mListView; 22650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 22750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 22850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * The name of the month to display. 22950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 230e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private TextView mMonthName; 23150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 23250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 23350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * The header with week day names. 23450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 235e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private ViewGroup mDayNamesHeader; 23650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 23750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 23850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * Cached labels for the week names header. 23950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 240e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private String[] mDayLabels; 24150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 24250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 243e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * The first day of the week. 24450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 245e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private int mFirstDayOfWeek; 24650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 24750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 248e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Which month should be displayed/highlighted [0-11]. 24950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 250f537c9b5f15cb5d5ad8197c61beb471ecdc5f1fbKi-Hwan Lee private int mCurrentMonthDisplayed = -1; 25150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 25250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 25350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * Used for tracking during a scroll. 25450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 255e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private long mPreviousScrollPosition; 25650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 25750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 25850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * Used for tracking which direction the view is scrolling. 25950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 260e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private boolean mIsScrollingUp = false; 26150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 26250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 26350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * The previous scroll state of the weeks ListView. 26450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 265e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private int mPreviousScrollState = OnScrollListener.SCROLL_STATE_IDLE; 26650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 26750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 26850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * The current scroll state of the weeks ListView. 26950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 270e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private int mCurrentScrollState = OnScrollListener.SCROLL_STATE_IDLE; 27150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 27250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 27350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * Listener for changes in the selected day. 27450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 275e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private OnDateChangeListener mOnDateChangeListener; 27650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 27750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 27850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * Command for adjusting the position after a scroll/fling. 27950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 280e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private ScrollStateRunnable mScrollStateChangedRunnable = new ScrollStateRunnable(); 28150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 28250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 283f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov * Temporary instance to avoid multiple instantiations. 284f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov */ 285f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov private Calendar mTempDate; 286f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov 287f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov /** 288f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov * The first day of the focused month. 289f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov */ 290f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov private Calendar mFirstDayOfMonth; 291f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov 292f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov /** 29350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * The start date of the range supported by this picker. 29450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 295f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov private Calendar mMinDate; 29650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 29750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 29850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * The end date of the range supported by this picker. 29950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 300f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov private Calendar mMaxDate; 30150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 30250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 303e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Date format for parsing dates. 30450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 305e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private final java.text.DateFormat mDateFormat = new SimpleDateFormat(DATE_FORMAT); 30650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 30750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 308f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov * The current locale. 309f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov */ 310f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov private Locale mCurrentLocale; 311f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov 312f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov /** 31350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * The callback used to indicate the user changes the date. 31450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 315e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public interface OnDateChangeListener { 31650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 31750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 31850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * Called upon change of the selected day. 31950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * 32050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * @param view The view associated with this listener. 32150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * @param year The year that was set. 32250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * @param month The month that was set [0-11]. 32350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * @param dayOfMonth The day of the month that was set. 32450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 325e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public void onSelectedDayChange(CalendarView view, int year, int month, int dayOfMonth); 32650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 32750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 328e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public CalendarView(Context context) { 32950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov this(context, null); 33050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 33150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 332e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public CalendarView(Context context, AttributeSet attrs) { 33350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov this(context, attrs, 0); 33450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 33550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 336e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public CalendarView(Context context, AttributeSet attrs, int defStyle) { 33750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov super(context, attrs, 0); 33850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 339f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov // initialization based on locale 340f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov setCurrentLocale(Locale.getDefault()); 341f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov 342f1189e9a462dcc85918607159c433d9cd23de0bfSvetoslav Ganov TypedArray attributesArray = context.obtainStyledAttributes(attrs, R.styleable.CalendarView, 343f1189e9a462dcc85918607159c433d9cd23de0bfSvetoslav Ganov R.attr.calendarViewStyle, 0); 344e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mShowWeekNumber = attributesArray.getBoolean(R.styleable.CalendarView_showWeekNumber, 345e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov DEFAULT_SHOW_WEEK_NUMBER); 346e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mFirstDayOfWeek = attributesArray.getInt(R.styleable.CalendarView_firstDayOfWeek, 347e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov LocaleData.get(Locale.getDefault()).firstDayOfWeek); 348e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov String minDate = attributesArray.getString(R.styleable.CalendarView_minDate); 349e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (TextUtils.isEmpty(minDate) || !parseDate(minDate, mMinDate)) { 350e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov parseDate(DEFAULT_MIN_DATE, mMinDate); 351e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 352e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov String maxDate = attributesArray.getString(R.styleable.CalendarView_maxDate); 353e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (TextUtils.isEmpty(maxDate) || !parseDate(maxDate, mMaxDate)) { 354e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov parseDate(DEFAULT_MAX_DATE, mMaxDate); 355e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 356f1189e9a462dcc85918607159c433d9cd23de0bfSvetoslav Ganov if (mMaxDate.before(mMinDate)) { 357f1189e9a462dcc85918607159c433d9cd23de0bfSvetoslav Ganov throw new IllegalArgumentException("Max date cannot be before min date."); 358f1189e9a462dcc85918607159c433d9cd23de0bfSvetoslav Ganov } 359e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mShownWeekCount = attributesArray.getInt(R.styleable.CalendarView_shownWeekCount, 360e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov DEFAULT_SHOWN_WEEK_COUNT); 361e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mSelectedWeekBackgroundColor = attributesArray.getColor( 362e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov R.styleable.CalendarView_selectedWeekBackgroundColor, 0); 363e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mFocusedMonthDateColor = attributesArray.getColor( 364e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov R.styleable.CalendarView_focusedMonthDateColor, 0); 365e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mUnfocusedMonthDateColor = attributesArray.getColor( 366e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov R.styleable.CalendarView_unfocusedMonthDateColor, 0); 367e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mWeekSeparatorLineColor = attributesArray.getColor( 368e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov R.styleable.CalendarView_weekSeparatorLineColor, 0); 369e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mWeekNumberColor = attributesArray.getColor(R.styleable.CalendarView_weekNumberColor, 0); 370e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mSelectedDateVerticalBar = attributesArray.getDrawable( 371e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov R.styleable.CalendarView_selectedDateVerticalBar); 372e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 373ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov mDateTextAppearanceResId = attributesArray.getResourceId( 374e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov R.styleable.CalendarView_dateTextAppearance, R.style.TextAppearance_Small); 375ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov updateDateTextSize(); 376e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 377ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov mWeekDayTextAppearanceResId = attributesArray.getResourceId( 378e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov R.styleable.CalendarView_weekDayTextAppearance, 379e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov DEFAULT_WEEK_DAY_TEXT_APPEARANCE_RES_ID); 380e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov attributesArray.recycle(); 381e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 382e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov DisplayMetrics displayMetrics = getResources().getDisplayMetrics(); 383e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mWeekMinVisibleHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 384e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov UNSCALED_WEEK_MIN_VISIBLE_HEIGHT, displayMetrics); 385e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mListScrollTopOffset = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 386e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov UNSCALED_LIST_SCROLL_TOP_OFFSET, displayMetrics); 387e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mBottomBuffer = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 388e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov UNSCALED_BOTTOM_BUFFER, displayMetrics); 389e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mSelectedDateVerticalBarWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 390e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov UNSCALED_SELECTED_DATE_VERTICAL_BAR_WIDTH, displayMetrics); 391e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mWeekSeperatorLineWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 392e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov UNSCALED_WEEK_SEPARATOR_LINE_WIDTH, displayMetrics); 393e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 39422c1c2cd103ef8beadaf0e78c12b22b60ce9cfc3Alan Viverette LayoutInflater layoutInflater = (LayoutInflater) context 39550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov .getSystemService(Service.LAYOUT_INFLATER_SERVICE); 396e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov View content = layoutInflater.inflate(R.layout.calendar_view, null, false); 39750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov addView(content); 39850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 39950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mListView = (ListView) findViewById(R.id.list); 40050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mDayNamesHeader = (ViewGroup) content.findViewById(com.android.internal.R.id.day_names); 40150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mMonthName = (TextView) content.findViewById(com.android.internal.R.id.month_name); 40250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 403ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov setUpHeader(); 40450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov setUpListView(); 40550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov setUpAdapter(); 40650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 407f1189e9a462dcc85918607159c433d9cd23de0bfSvetoslav Ganov // go to today or whichever is close to today min or max date 408e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mTempDate.setTimeInMillis(System.currentTimeMillis()); 409f1189e9a462dcc85918607159c433d9cd23de0bfSvetoslav Ganov if (mTempDate.before(mMinDate)) { 410f1189e9a462dcc85918607159c433d9cd23de0bfSvetoslav Ganov goTo(mMinDate, false, true, true); 411f1189e9a462dcc85918607159c433d9cd23de0bfSvetoslav Ganov } else if (mMaxDate.before(mTempDate)) { 412f1189e9a462dcc85918607159c433d9cd23de0bfSvetoslav Ganov goTo(mMaxDate, false, true, true); 413f1189e9a462dcc85918607159c433d9cd23de0bfSvetoslav Ganov } else { 414f1189e9a462dcc85918607159c433d9cd23de0bfSvetoslav Ganov goTo(mTempDate, false, true, true); 415f1189e9a462dcc85918607159c433d9cd23de0bfSvetoslav Ganov } 416f1189e9a462dcc85918607159c433d9cd23de0bfSvetoslav Ganov 41750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov invalidate(); 41850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 41950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 420ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov /** 421ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * Sets the number of weeks to be shown. 422ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * 423ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * @param count The shown week count. 424414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * 425414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * @attr ref android.R.styleable#CalendarView_shownWeekCount 426ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov */ 427ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov public void setShownWeekCount(int count) { 428ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov if (mShownWeekCount != count) { 429ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov mShownWeekCount = count; 430ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov invalidate(); 431ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov } 432ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov } 433ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov 434ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov /** 435ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * Gets the number of weeks to be shown. 436ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * 437ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * @return The shown week count. 438414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * 439414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * @attr ref android.R.styleable#CalendarView_shownWeekCount 440ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov */ 441ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov public int getShownWeekCount() { 442ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov return mShownWeekCount; 443ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov } 444ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov 445ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov /** 446ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * Sets the background color for the selected week. 447ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * 448ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * @param color The week background color. 449414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * 450414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * @attr ref android.R.styleable#CalendarView_selectedWeekBackgroundColor 451ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov */ 452ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov public void setSelectedWeekBackgroundColor(int color) { 453ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov if (mSelectedWeekBackgroundColor != color) { 454ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov mSelectedWeekBackgroundColor = color; 455ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov final int childCount = mListView.getChildCount(); 456ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov for (int i = 0; i < childCount; i++) { 457ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov WeekView weekView = (WeekView) mListView.getChildAt(i); 458ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov if (weekView.mHasSelectedDay) { 459ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov weekView.invalidate(); 460ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov } 461ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov } 462ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov } 463ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov } 464ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov 465ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov /** 466ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * Gets the background color for the selected week. 467ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * 468ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * @return The week background color. 469414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * 470414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * @attr ref android.R.styleable#CalendarView_selectedWeekBackgroundColor 471ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov */ 472ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov public int getSelectedWeekBackgroundColor() { 473ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov return mSelectedWeekBackgroundColor; 474ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov } 475ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov 476ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov /** 477ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * Sets the color for the dates of the focused month. 478ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * 479ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * @param color The focused month date color. 480414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * 481414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * @attr ref android.R.styleable#CalendarView_focusedMonthDateColor 482ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov */ 483ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov public void setFocusedMonthDateColor(int color) { 484ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov if (mFocusedMonthDateColor != color) { 485ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov mFocusedMonthDateColor = color; 486ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov final int childCount = mListView.getChildCount(); 487ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov for (int i = 0; i < childCount; i++) { 488ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov WeekView weekView = (WeekView) mListView.getChildAt(i); 489ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov if (weekView.mHasFocusedDay) { 490ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov weekView.invalidate(); 491ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov } 492ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov } 493ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov } 494ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov } 495ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov 496ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov /** 497ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * Gets the color for the dates in the focused month. 498ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * 499ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * @return The focused month date color. 500414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * 501414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * @attr ref android.R.styleable#CalendarView_focusedMonthDateColor 502ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov */ 503ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov public int getFocusedMonthDateColor() { 504ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov return mFocusedMonthDateColor; 505ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov } 506ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov 507ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov /** 508ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * Sets the color for the dates of a not focused month. 509ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * 510ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * @param color A not focused month date color. 511414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * 512414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * @attr ref android.R.styleable#CalendarView_unfocusedMonthDateColor 513ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov */ 514ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov public void setUnfocusedMonthDateColor(int color) { 515ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov if (mUnfocusedMonthDateColor != color) { 516ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov mUnfocusedMonthDateColor = color; 517ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov final int childCount = mListView.getChildCount(); 518ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov for (int i = 0; i < childCount; i++) { 519ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov WeekView weekView = (WeekView) mListView.getChildAt(i); 520ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov if (weekView.mHasUnfocusedDay) { 521ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov weekView.invalidate(); 522ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov } 523ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov } 524ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov } 525ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov } 526ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov 527ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov /** 528ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * Gets the color for the dates in a not focused month. 529ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * 530ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * @return A not focused month date color. 531414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * 532414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * @attr ref android.R.styleable#CalendarView_unfocusedMonthDateColor 533ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov */ 534ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov public int getUnfocusedMonthDateColor() { 535ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov return mFocusedMonthDateColor; 536ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov } 537ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov 538ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov /** 539ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * Sets the color for the week numbers. 540ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * 541ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * @param color The week number color. 542414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * 543414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * @attr ref android.R.styleable#CalendarView_weekNumberColor 544ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov */ 545ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov public void setWeekNumberColor(int color) { 546ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov if (mWeekNumberColor != color) { 547ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov mWeekNumberColor = color; 548ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov if (mShowWeekNumber) { 549ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov invalidateAllWeekViews(); 550ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov } 551ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov } 552ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov } 553ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov 554ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov /** 555ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * Gets the color for the week numbers. 556ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * 557ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * @return The week number color. 558414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * 559414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * @attr ref android.R.styleable#CalendarView_weekNumberColor 560ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov */ 561ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov public int getWeekNumberColor() { 562ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov return mWeekNumberColor; 563ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov } 564ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov 565ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov /** 566ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * Sets the color for the separator line between weeks. 567ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * 568ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * @param color The week separator color. 569414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * 570414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * @attr ref android.R.styleable#CalendarView_weekSeparatorLineColor 571ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov */ 572ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov public void setWeekSeparatorLineColor(int color) { 573ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov if (mWeekSeparatorLineColor != color) { 574ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov mWeekSeparatorLineColor = color; 575ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov invalidateAllWeekViews(); 576ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov } 577ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov } 578ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov 579ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov /** 580ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * Gets the color for the separator line between weeks. 581ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * 582ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * @return The week separator color. 583414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * 584414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * @attr ref android.R.styleable#CalendarView_weekSeparatorLineColor 585ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov */ 586ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov public int getWeekSeparatorLineColor() { 587ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov return mWeekSeparatorLineColor; 588ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov } 589ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov 590ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov /** 591ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * Sets the drawable for the vertical bar shown at the beginning and at 592ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * the end of the selected date. 593ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * 594ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * @param resourceId The vertical bar drawable resource id. 595414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * 596414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * @attr ref android.R.styleable#CalendarView_selectedDateVerticalBar 597ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov */ 598ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov public void setSelectedDateVerticalBar(int resourceId) { 599ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov Drawable drawable = getResources().getDrawable(resourceId); 600ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov setSelectedDateVerticalBar(drawable); 601ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov } 602ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov 603ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov /** 604ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * Sets the drawable for the vertical bar shown at the beginning and at 605ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * the end of the selected date. 606ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * 607ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * @param drawable The vertical bar drawable. 608414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * 609414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * @attr ref android.R.styleable#CalendarView_selectedDateVerticalBar 610ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov */ 611ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov public void setSelectedDateVerticalBar(Drawable drawable) { 612ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov if (mSelectedDateVerticalBar != drawable) { 613ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov mSelectedDateVerticalBar = drawable; 614ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov final int childCount = mListView.getChildCount(); 615ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov for (int i = 0; i < childCount; i++) { 616ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov WeekView weekView = (WeekView) mListView.getChildAt(i); 617ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov if (weekView.mHasSelectedDay) { 618ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov weekView.invalidate(); 619ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov } 620ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov } 621ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov } 622ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov } 623ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov 624ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov /** 625ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * Gets the drawable for the vertical bar shown at the beginning and at 626ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * the end of the selected date. 627ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * 628ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * @return The vertical bar drawable. 629ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov */ 630ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov public Drawable getSelectedDateVerticalBar() { 631ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov return mSelectedDateVerticalBar; 632ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov } 633ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov 634ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov /** 635ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * Sets the text appearance for the week day abbreviation of the calendar header. 636ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * 637ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * @param resourceId The text appearance resource id. 638414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * 639414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * @attr ref android.R.styleable#CalendarView_weekDayTextAppearance 640ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov */ 641ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov public void setWeekDayTextAppearance(int resourceId) { 642ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov if (mWeekDayTextAppearanceResId != resourceId) { 643ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov mWeekDayTextAppearanceResId = resourceId; 644ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov setUpHeader(); 645ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov } 646ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov } 647ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov 648ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov /** 649ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * Gets the text appearance for the week day abbreviation of the calendar header. 650ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * 651ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * @return The text appearance resource id. 652414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * 653414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * @attr ref android.R.styleable#CalendarView_weekDayTextAppearance 654ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov */ 655ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov public int getWeekDayTextAppearance() { 656ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov return mWeekDayTextAppearanceResId; 657ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov } 658ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov 659ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov /** 660ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * Sets the text appearance for the calendar dates. 661ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * 662ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * @param resourceId The text appearance resource id. 663414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * 664414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * @attr ref android.R.styleable#CalendarView_dateTextAppearance 665ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov */ 666ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov public void setDateTextAppearance(int resourceId) { 667ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov if (mDateTextAppearanceResId != resourceId) { 668ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov mDateTextAppearanceResId = resourceId; 669ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov updateDateTextSize(); 670ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov invalidateAllWeekViews(); 671ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov } 672ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov } 673ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov 674ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov /** 675ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * Gets the text appearance for the calendar dates. 676ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * 677ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * @return The text appearance resource id. 678414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * 679414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * @attr ref android.R.styleable#CalendarView_dateTextAppearance 680ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov */ 681ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov public int getDateTextAppearance() { 682ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov return mDateTextAppearanceResId; 683ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov } 684ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov 68551c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov @Override 68651c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov public void setEnabled(boolean enabled) { 68751c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov mListView.setEnabled(enabled); 68851c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov } 68951c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov 69051c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov @Override 69151c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov public boolean isEnabled() { 69251c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov return mListView.isEnabled(); 69351c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov } 69451c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov 695f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov @Override 696f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov protected void onConfigurationChanged(Configuration newConfig) { 697f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov super.onConfigurationChanged(newConfig); 698f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov setCurrentLocale(newConfig.locale); 699f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov } 700f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov 7018a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov @Override 7028a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov public void onInitializeAccessibilityEvent(AccessibilityEvent event) { 7038a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov super.onInitializeAccessibilityEvent(event); 7048a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov event.setClassName(CalendarView.class.getName()); 7058a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov } 7068a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov 7078a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov @Override 7088a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { 7098a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov super.onInitializeAccessibilityNodeInfo(info); 7108a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov info.setClassName(CalendarView.class.getName()); 7118a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov } 7128a78fd4d9572dff95432fcc4ba0e87563415b728Svetoslav Ganov 71350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 714e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Gets the minimal date supported by this {@link CalendarView} in milliseconds 715e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * since January 1, 1970 00:00:00 in {@link TimeZone#getDefault()} time 716e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * zone. 717e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * <p> 718e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Note: The default minimal date is 01/01/1900. 719e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * <p> 720e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * 721e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @return The minimal supported date. 722414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * 723414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * @attr ref android.R.styleable#CalendarView_minDate 724e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov */ 725e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public long getMinDate() { 726e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mMinDate.getTimeInMillis(); 727e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 728e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 729e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov /** 730e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Sets the minimal date supported by this {@link CalendarView} in milliseconds 731e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * since January 1, 1970 00:00:00 in {@link TimeZone#getDefault()} time 732e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * zone. 73350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * 734e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param minDate The minimal supported date. 735414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * 736414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * @attr ref android.R.styleable#CalendarView_minDate 737e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov */ 738e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public void setMinDate(long minDate) { 739e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mTempDate.setTimeInMillis(minDate); 740e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (isSameDate(mTempDate, mMinDate)) { 741e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return; 74250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 743e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mMinDate.setTimeInMillis(minDate); 744156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov // make sure the current date is not earlier than 745156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov // the new min date since the latter is used for 746156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov // calculating the indices in the adapter thus 747156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov // avoiding out of bounds error 748156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov Calendar date = mAdapter.mSelectedDate; 749156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov if (date.before(mMinDate)) { 750156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov mAdapter.setSelectedDay(mMinDate); 751156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov } 752e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov // reinitialize the adapter since its range depends on min date 753e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mAdapter.init(); 754e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (date.before(mMinDate)) { 755156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov setDate(mTempDate.getTimeInMillis()); 756e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } else { 757e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov // we go to the current date to force the ListView to query its 758e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov // adapter for the shown views since we have changed the adapter 759e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov // range and the base from which the later calculates item indices 760e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov // note that calling setDate will not work since the date is the same 761e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov goTo(date, false, true, false); 76250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 763e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 764e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 765e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov /** 766e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Gets the maximal date supported by this {@link CalendarView} in milliseconds 767e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * since January 1, 1970 00:00:00 in {@link TimeZone#getDefault()} time 768e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * zone. 769e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * <p> 770e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Note: The default maximal date is 01/01/2100. 771e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * <p> 772e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * 773e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @return The maximal supported date. 774414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * 775414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * @attr ref android.R.styleable#CalendarView_maxDate 776e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov */ 777e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public long getMaxDate() { 778e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mMaxDate.getTimeInMillis(); 779e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 78028104e1de5595a22a6987181b13ddeb192739afdSvetoslav Ganov 781e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov /** 782e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Sets the maximal date supported by this {@link CalendarView} in milliseconds 783e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * since January 1, 1970 00:00:00 in {@link TimeZone#getDefault()} time 784e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * zone. 785e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * 786e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param maxDate The maximal supported date. 787414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * 788414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * @attr ref android.R.styleable#CalendarView_maxDate 789e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov */ 790e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public void setMaxDate(long maxDate) { 791e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mTempDate.setTimeInMillis(maxDate); 792e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (isSameDate(mTempDate, mMaxDate)) { 79328104e1de5595a22a6987181b13ddeb192739afdSvetoslav Ganov return; 79428104e1de5595a22a6987181b13ddeb192739afdSvetoslav Ganov } 795e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mMaxDate.setTimeInMillis(maxDate); 796e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov // reinitialize the adapter since its range depends on max date 797e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mAdapter.init(); 798e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov Calendar date = mAdapter.mSelectedDate; 799e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (date.after(mMaxDate)) { 800e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov setDate(mMaxDate.getTimeInMillis()); 801e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } else { 802e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov // we go to the current date to force the ListView to query its 803e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov // adapter for the shown views since we have changed the adapter 804e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov // range and the base from which the later calculates item indices 805e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov // note that calling setDate will not work since the date is the same 806e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov goTo(date, false, true, false); 807e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 808e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 80928104e1de5595a22a6987181b13ddeb192739afdSvetoslav Ganov 810e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov /** 811e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Sets whether to show the week number. 812e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * 813e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param showWeekNumber True to show the week number. 814414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * 815414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * @attr ref android.R.styleable#CalendarView_showWeekNumber 816e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov */ 817e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public void setShowWeekNumber(boolean showWeekNumber) { 818e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mShowWeekNumber == showWeekNumber) { 819e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return; 820e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 821e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mShowWeekNumber = showWeekNumber; 822e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mAdapter.notifyDataSetChanged(); 823ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov setUpHeader(); 824e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 82528104e1de5595a22a6987181b13ddeb192739afdSvetoslav Ganov 826e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov /** 827e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Gets whether to show the week number. 828e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * 829e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @return True if showing the week number. 830414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * 831414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * @attr ref android.R.styleable#CalendarView_showWeekNumber 832e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov */ 833e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public boolean getShowWeekNumber() { 834e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mShowWeekNumber; 835e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 836e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 837e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov /** 838e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Gets the first day of week. 839e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * 840e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @return The first day of the week conforming to the {@link CalendarView} 841e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * APIs. 842e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @see Calendar#MONDAY 843e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @see Calendar#TUESDAY 844e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @see Calendar#WEDNESDAY 845e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @see Calendar#THURSDAY 846e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @see Calendar#FRIDAY 847e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @see Calendar#SATURDAY 848e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @see Calendar#SUNDAY 849414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * 850414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * @attr ref android.R.styleable#CalendarView_firstDayOfWeek 851e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov */ 852e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public int getFirstDayOfWeek() { 853e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mFirstDayOfWeek; 854e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 855e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 856e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov /** 857e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Sets the first day of week. 858e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * 859e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param firstDayOfWeek The first day of the week conforming to the 860e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link CalendarView} APIs. 861e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @see Calendar#MONDAY 862e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @see Calendar#TUESDAY 863e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @see Calendar#WEDNESDAY 864e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @see Calendar#THURSDAY 865e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @see Calendar#FRIDAY 866e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @see Calendar#SATURDAY 867e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @see Calendar#SUNDAY 868414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * 869414efc3b5f50e2784f4f7c2be3f2c096aef0c6b4Svetoslav Ganov * @attr ref android.R.styleable#CalendarView_firstDayOfWeek 870e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov */ 871e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public void setFirstDayOfWeek(int firstDayOfWeek) { 872e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mFirstDayOfWeek == firstDayOfWeek) { 873e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return; 87450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 875e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mFirstDayOfWeek = firstDayOfWeek; 876e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mAdapter.init(); 877ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov setUpHeader(); 87850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 87950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 88050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 881e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Sets the listener to be notified upon selected date change. 88250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * 883e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param listener The listener to be notified. 88450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 885e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public void setOnDateChangeListener(OnDateChangeListener listener) { 886e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mOnDateChangeListener = listener; 88750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 88850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 88950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 890e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Gets the selected date in milliseconds since January 1, 1970 00:00:00 in 891e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link TimeZone#getDefault()} time zone. 89250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * 893e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @return The selected date. 89450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 895e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public long getDate() { 896e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mAdapter.mSelectedDate.getTimeInMillis(); 89750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 89850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 89950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 900e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Sets the selected date in milliseconds since January 1, 1970 00:00:00 in 901e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link TimeZone#getDefault()} time zone. 902e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * 903e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param date The selected date. 904e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * 905e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @throws IllegalArgumentException of the provided date is before the 906e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * minimal or after the maximal date. 90750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * 908e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @see #setDate(long, boolean, boolean) 90951c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov * @see #setMinDate(long) 91051c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov * @see #setMaxDate(long) 91150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 912e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public void setDate(long date) { 913e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov setDate(date, false, false); 91450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 91550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 91650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 917e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Sets the selected date in milliseconds since January 1, 1970 00:00:00 in 918e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * {@link TimeZone#getDefault()} time zone. 91950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * 920e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param date The date. 921e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param animate Whether to animate the scroll to the current date. 922e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @param center Whether to center the current date even if it is already visible. 923e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * 924e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @throws IllegalArgumentException of the provided date is before the 925e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * minimal or after the maximal date. 926e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * 92751c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov * @see #setMinDate(long) 92851c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov * @see #setMaxDate(long) 929e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov */ 930e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public void setDate(long date, boolean animate, boolean center) { 931e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mTempDate.setTimeInMillis(date); 932e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (isSameDate(mTempDate, mAdapter.mSelectedDate)) { 933e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return; 934e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 935e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov goTo(mTempDate, animate, true, center); 936e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 937e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 938ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov private void updateDateTextSize() { 93922c1c2cd103ef8beadaf0e78c12b22b60ce9cfc3Alan Viverette TypedArray dateTextAppearance = mContext.obtainStyledAttributes( 940ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov mDateTextAppearanceResId, R.styleable.TextAppearance); 941ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov mDateTextSize = dateTextAppearance.getDimensionPixelSize( 942ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov R.styleable.TextAppearance_textSize, DEFAULT_DATE_TEXT_SIZE); 943ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov dateTextAppearance.recycle(); 944ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov } 945ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov 946ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov /** 947ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov * Invalidates all week views. 948ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov */ 949ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov private void invalidateAllWeekViews() { 950ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov final int childCount = mListView.getChildCount(); 951ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov for (int i = 0; i < childCount; i++) { 952ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov View view = mListView.getChildAt(i); 953ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov view.invalidate(); 954ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov } 955ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov } 956ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov 957e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov /** 958f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov * Sets the current locale. 959f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov * 960f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov * @param locale The current locale. 961f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov */ 962f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov private void setCurrentLocale(Locale locale) { 963f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov if (locale.equals(mCurrentLocale)) { 964f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov return; 965f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov } 966f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov 967f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov mCurrentLocale = locale; 968f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov 969f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov mTempDate = getCalendarForLocale(mTempDate, locale); 970f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov mFirstDayOfMonth = getCalendarForLocale(mFirstDayOfMonth, locale); 971f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov mMinDate = getCalendarForLocale(mMinDate, locale); 972f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov mMaxDate = getCalendarForLocale(mMaxDate, locale); 973f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov } 974f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov 975f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov /** 976f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov * Gets a calendar for locale bootstrapped with the value of a given calendar. 977f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov * 978f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov * @param oldCalendar The old calendar. 979f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov * @param locale The locale. 980f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov */ 981f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov private Calendar getCalendarForLocale(Calendar oldCalendar, Locale locale) { 982f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov if (oldCalendar == null) { 983f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov return Calendar.getInstance(locale); 984f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov } else { 985f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov final long currentTimeMillis = oldCalendar.getTimeInMillis(); 986f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov Calendar newCalendar = Calendar.getInstance(locale); 987f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov newCalendar.setTimeInMillis(currentTimeMillis); 988f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov return newCalendar; 989f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov } 990f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov } 991f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov 992f5926962cc665d4a2e6464f9ba9e3e9788496a6fSvetoslav Ganov /** 993e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @return True if the <code>firstDate</code> is the same as the <code> 994e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * secondDate</code>. 99550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 996e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private boolean isSameDate(Calendar firstDate, Calendar secondDate) { 997e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return (firstDate.get(Calendar.DAY_OF_YEAR) == secondDate.get(Calendar.DAY_OF_YEAR) 998e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov && firstDate.get(Calendar.YEAR) == secondDate.get(Calendar.YEAR)); 999e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1000e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 1001e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov /** 1002e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Creates a new adapter if necessary and sets up its parameters. 1003e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov */ 1004e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private void setUpAdapter() { 100550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov if (mAdapter == null) { 100622c1c2cd103ef8beadaf0e78c12b22b60ce9cfc3Alan Viverette mAdapter = new WeeksAdapter(); 100750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mAdapter.registerDataSetObserver(new DataSetObserver() { 100850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov @Override 100950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov public void onChanged() { 1010e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mOnDateChangeListener != null) { 101150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov Calendar selectedDay = mAdapter.getSelectedDay(); 1012e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mOnDateChangeListener.onSelectedDayChange(CalendarView.this, 101350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov selectedDay.get(Calendar.YEAR), 101450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov selectedDay.get(Calendar.MONTH), 101550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov selectedDay.get(Calendar.DAY_OF_MONTH)); 101650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 101750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 101850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov }); 101950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mListView.setAdapter(mAdapter); 102050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 102150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 102250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov // refresh the view with the new parameters 102350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mAdapter.notifyDataSetChanged(); 102450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 102550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 102650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 1027e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Sets up the strings to be used by the header. 102850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 1029ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov private void setUpHeader() { 1030b08e5788a79127df2e2e452f5fb1adab417cb503Fabrice Di Meglio final String[] tinyWeekdayNames = LocaleData.get(Locale.getDefault()).tinyWeekdayNames; 103150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mDayLabels = new String[mDaysPerWeek]; 1032b08e5788a79127df2e2e452f5fb1adab417cb503Fabrice Di Meglio for (int i = 0; i < mDaysPerWeek; i++) { 1033b08e5788a79127df2e2e452f5fb1adab417cb503Fabrice Di Meglio final int j = i + mFirstDayOfWeek; 1034b08e5788a79127df2e2e452f5fb1adab417cb503Fabrice Di Meglio final int calendarDay = (j > Calendar.SATURDAY) ? j - Calendar.SATURDAY : j; 1035b08e5788a79127df2e2e452f5fb1adab417cb503Fabrice Di Meglio mDayLabels[i] = tinyWeekdayNames[calendarDay]; 103650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 1037b08e5788a79127df2e2e452f5fb1adab417cb503Fabrice Di Meglio // Deal with week number 103850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov TextView label = (TextView) mDayNamesHeader.getChildAt(0); 103950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov if (mShowWeekNumber) { 104050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov label.setVisibility(View.VISIBLE); 104150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } else { 104250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov label.setVisibility(View.GONE); 104350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 1044b08e5788a79127df2e2e452f5fb1adab417cb503Fabrice Di Meglio // Deal with day labels 1045b08e5788a79127df2e2e452f5fb1adab417cb503Fabrice Di Meglio final int count = mDayNamesHeader.getChildCount(); 1046b08e5788a79127df2e2e452f5fb1adab417cb503Fabrice Di Meglio for (int i = 0; i < count - 1; i++) { 1047b08e5788a79127df2e2e452f5fb1adab417cb503Fabrice Di Meglio label = (TextView) mDayNamesHeader.getChildAt(i + 1); 1048ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov if (mWeekDayTextAppearanceResId > -1) { 1049ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov label.setTextAppearance(mContext, mWeekDayTextAppearanceResId); 1050e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1051b08e5788a79127df2e2e452f5fb1adab417cb503Fabrice Di Meglio if (i < mDaysPerWeek) { 1052b08e5788a79127df2e2e452f5fb1adab417cb503Fabrice Di Meglio label.setText(mDayLabels[i]); 105350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov label.setVisibility(View.VISIBLE); 105450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } else { 105550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov label.setVisibility(View.GONE); 105650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 105750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 105850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mDayNamesHeader.invalidate(); 105950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 106050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 106150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 1062e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Sets all the required fields for the list view. 106350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 1064e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private void setUpListView() { 1065e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov // Configure the listview 1066e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mListView.setDivider(null); 1067e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mListView.setItemsCanFocus(true); 1068e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mListView.setVerticalScrollBarEnabled(false); 1069e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mListView.setOnScrollListener(new OnScrollListener() { 1070e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public void onScrollStateChanged(AbsListView view, int scrollState) { 1071e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov CalendarView.this.onScrollStateChanged(view, scrollState); 1072e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1073e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 1074e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov public void onScroll( 1075e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov AbsListView view, int firstVisibleItem, int visibleItemCount, 1076e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov int totalItemCount) { 1077e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov CalendarView.this.onScroll(view, firstVisibleItem, visibleItemCount, 1078e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov totalItemCount); 1079e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1080e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov }); 1081e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov // Make the scrolling behavior nicer 1082e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mListView.setFriction(mFriction); 1083e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mListView.setVelocityScale(mVelocityScale); 108450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 108550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 108650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 108750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * This moves to the specified time in the view. If the time is not already 108850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * in range it will move the list so that the first of the month containing 108950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * the time is at the top of the view. If the new time is already in view 109050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * the list will not be scrolled unless forceScroll is true. This time may 109150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * optionally be highlighted as selected as well. 1092a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov * 109350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * @param date The time to move to. 109450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * @param animate Whether to scroll to the given time or just redraw at the 109550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * new location. 109650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * @param setSelected Whether to set the given time as selected. 109750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * @param forceScroll Whether to recenter even if the time is already 109850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * visible. 1099a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov * 1100a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov * @throws IllegalArgumentException of the provided date is before the 1101a911d4a2b1be7e9ea909a579167826e4a5bac1a3Svetoslav Ganov * range start of after the range end. 110250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 1103e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private void goTo(Calendar date, boolean animate, boolean setSelected, boolean forceScroll) { 1104e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (date.before(mMinDate) || date.after(mMaxDate)) { 1105e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov throw new IllegalArgumentException("Time not between " + mMinDate.getTime() 1106e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov + " and " + mMaxDate.getTime()); 110750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 110850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov // Find the first and last entirely visible weeks 110950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov int firstFullyVisiblePosition = mListView.getFirstVisiblePosition(); 111050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov View firstChild = mListView.getChildAt(0); 111150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov if (firstChild != null && firstChild.getTop() < 0) { 111250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov firstFullyVisiblePosition++; 111350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 111450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov int lastFullyVisiblePosition = firstFullyVisiblePosition + mShownWeekCount - 1; 111550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov if (firstChild != null && firstChild.getTop() > mBottomBuffer) { 111650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov lastFullyVisiblePosition--; 111750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 111850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov if (setSelected) { 111950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mAdapter.setSelectedDay(date); 112050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 112150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov // Get the week we're going to 1122e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov int position = getWeeksSinceMinDate(date); 112350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 112450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov // Check if the selected day is now outside of our visible range 112550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov // and if so scroll to the month that contains it 112650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov if (position < firstFullyVisiblePosition || position > lastFullyVisiblePosition 112750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov || forceScroll) { 112850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mFirstDayOfMonth.setTimeInMillis(date.getTimeInMillis()); 112950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mFirstDayOfMonth.set(Calendar.DAY_OF_MONTH, 1); 113050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 113150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov setMonthDisplayed(mFirstDayOfMonth); 1132156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov 1133156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov // the earliest time we can scroll to is the min date 1134156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov if (mFirstDayOfMonth.before(mMinDate)) { 1135156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov position = 0; 1136156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov } else { 1137156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov position = getWeeksSinceMinDate(mFirstDayOfMonth); 1138156f20919b3d5f298f8851215adbf65f8b4dc61bSvetoslav Ganov } 113950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 114050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mPreviousScrollState = OnScrollListener.SCROLL_STATE_FLING; 114150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov if (animate) { 1142e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mListView.smoothScrollToPositionFromTop(position, mListScrollTopOffset, 114350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov GOTO_SCROLL_DURATION); 114450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } else { 1145e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mListView.setSelectionFromTop(position, mListScrollTopOffset); 114650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov // Perform any after scroll operations that are needed 114750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov onScrollStateChanged(mListView, OnScrollListener.SCROLL_STATE_IDLE); 114850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 114950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } else if (setSelected) { 115050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov // Otherwise just set the selection 115150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov setMonthDisplayed(date); 115250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 115350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 115450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 115550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 1156e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Parses the given <code>date</code> and in case of success sets 1157e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * the result to the <code>outDate</code>. 1158e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * 1159e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @return True if the date was parsed. 1160e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov */ 1161e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private boolean parseDate(String date, Calendar outDate) { 1162e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov try { 1163e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov outDate.setTime(mDateFormat.parse(date)); 1164e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return true; 1165e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } catch (ParseException e) { 1166e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov Log.w(LOG_TAG, "Date: " + date + " not in format: " + DATE_FORMAT); 1167e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return false; 1168e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1169e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov } 1170e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov 1171e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov /** 117250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * Called when a <code>view</code> transitions to a new <code>scrollState 117350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * </code>. 117450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 1175e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private void onScrollStateChanged(AbsListView view, int scrollState) { 117650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mScrollStateChangedRunnable.doScrollStateChange(view, scrollState); 117750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 117850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 117950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 118050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * Updates the title and selected month if the <code>view</code> has moved to a new 118150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * month. 118250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 1183e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, 118450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov int totalItemCount) { 118550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov WeekView child = (WeekView) view.getChildAt(0); 118650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov if (child == null) { 118750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov return; 118850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 118950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 119050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov // Figure out where we are 119150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov long currScroll = view.getFirstVisiblePosition() * child.getHeight() - child.getBottom(); 119250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 119350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov // If we have moved since our last call update the direction 119450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov if (currScroll < mPreviousScrollPosition) { 119550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mIsScrollingUp = true; 119650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } else if (currScroll > mPreviousScrollPosition) { 119750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mIsScrollingUp = false; 119850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } else { 119950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov return; 120050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 120150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 120250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov // Use some hysteresis for checking which month to highlight. This 120350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov // causes the month to transition when two full weeks of a month are 120450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov // visible when scrolling up, and when the first day in a month reaches 120550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov // the top of the screen when scrolling down. 120628104e1de5595a22a6987181b13ddeb192739afdSvetoslav Ganov int offset = child.getBottom() < mWeekMinVisibleHeight ? 1 : 0; 120750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov if (mIsScrollingUp) { 120850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov child = (WeekView) view.getChildAt(SCROLL_HYST_WEEKS + offset); 120950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } else if (offset != 0) { 121050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov child = (WeekView) view.getChildAt(offset); 121150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 121250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 121350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov // Find out which month we're moving into 121450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov int month; 121550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov if (mIsScrollingUp) { 121650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov month = child.getMonthOfFirstWeekDay(); 121750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } else { 121850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov month = child.getMonthOfLastWeekDay(); 121950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 122050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 122150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov // And how it relates to our current highlighted month 122250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov int monthDiff; 122350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov if (mCurrentMonthDisplayed == 11 && month == 0) { 122450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov monthDiff = 1; 122550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } else if (mCurrentMonthDisplayed == 0 && month == 11) { 122650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov monthDiff = -1; 122750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } else { 122850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov monthDiff = month - mCurrentMonthDisplayed; 122950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 123050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 123150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov // Only switch months if we're scrolling away from the currently 123250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov // selected month 123350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov if ((!mIsScrollingUp && monthDiff > 0) || (mIsScrollingUp && monthDiff < 0)) { 123450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov Calendar firstDay = child.getFirstDay(); 123550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov if (mIsScrollingUp) { 123650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov firstDay.add(Calendar.DAY_OF_MONTH, -DAYS_PER_WEEK); 123750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } else { 123850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov firstDay.add(Calendar.DAY_OF_MONTH, DAYS_PER_WEEK); 123950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 124050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov setMonthDisplayed(firstDay); 124150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 124250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mPreviousScrollPosition = currScroll; 124350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mPreviousScrollState = mCurrentScrollState; 124450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 124550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 124650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 124750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * Sets the month displayed at the top of this view based on time. Override 124850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * to add custom events when the title is changed. 124950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * 125050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * @param calendar A day in the new focus month. 125150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 1252e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private void setMonthDisplayed(Calendar calendar) { 1253a085179558e38d114e72b136a59912821d65a49aSvetoslav mCurrentMonthDisplayed = calendar.get(Calendar.MONTH); 1254a085179558e38d114e72b136a59912821d65a49aSvetoslav mAdapter.setFocusMonth(mCurrentMonthDisplayed); 1255a085179558e38d114e72b136a59912821d65a49aSvetoslav final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NO_MONTH_DAY 1256a085179558e38d114e72b136a59912821d65a49aSvetoslav | DateUtils.FORMAT_SHOW_YEAR; 1257a085179558e38d114e72b136a59912821d65a49aSvetoslav final long millis = calendar.getTimeInMillis(); 1258a085179558e38d114e72b136a59912821d65a49aSvetoslav String newMonthName = DateUtils.formatDateRange(mContext, millis, millis, flags); 1259a085179558e38d114e72b136a59912821d65a49aSvetoslav mMonthName.setText(newMonthName); 1260a085179558e38d114e72b136a59912821d65a49aSvetoslav mMonthName.invalidate(); 126150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 126250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 126350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 1264e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * @return Returns the number of weeks between the current <code>date</code> 1265e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * and the <code>mMinDate</code>. 126650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 1267e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private int getWeeksSinceMinDate(Calendar date) { 1268e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (date.before(mMinDate)) { 1269e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov throw new IllegalArgumentException("fromDate: " + mMinDate.getTime() 1270e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov + " does not precede toDate: " + date.getTime()); 127150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 127258f51255eb20f9c4d16c11554f372ff92d45fcc7Svetoslav Ganov long endTimeMillis = date.getTimeInMillis() 127358f51255eb20f9c4d16c11554f372ff92d45fcc7Svetoslav Ganov + date.getTimeZone().getOffset(date.getTimeInMillis()); 127458f51255eb20f9c4d16c11554f372ff92d45fcc7Svetoslav Ganov long startTimeMillis = mMinDate.getTimeInMillis() 127558f51255eb20f9c4d16c11554f372ff92d45fcc7Svetoslav Ganov + mMinDate.getTimeZone().getOffset(mMinDate.getTimeInMillis()); 127658f51255eb20f9c4d16c11554f372ff92d45fcc7Svetoslav Ganov long dayOffsetMillis = (mMinDate.get(Calendar.DAY_OF_WEEK) - mFirstDayOfWeek) 127758f51255eb20f9c4d16c11554f372ff92d45fcc7Svetoslav Ganov * MILLIS_IN_DAY; 127858f51255eb20f9c4d16c11554f372ff92d45fcc7Svetoslav Ganov return (int) ((endTimeMillis - startTimeMillis + dayOffsetMillis) / MILLIS_IN_WEEK); 127950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 128050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 128150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 128250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * Command responsible for acting upon scroll state changes. 128350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 1284e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private class ScrollStateRunnable implements Runnable { 128550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov private AbsListView mView; 128650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 128750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov private int mNewState; 128850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 128950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 129050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * Sets up the runnable with a short delay in case the scroll state 129150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * immediately changes again. 129250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * 129350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * @param view The list view that changed state 129450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * @param scrollState The new state it changed to 129550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 129650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov public void doScrollStateChange(AbsListView view, int scrollState) { 129750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mView = view; 129850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mNewState = scrollState; 129950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov removeCallbacks(this); 130050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov postDelayed(this, SCROLL_CHANGE_DELAY); 130150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 130250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 130350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov public void run() { 130450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mCurrentScrollState = mNewState; 130550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov // Fix the position after a scroll or a fling ends 130650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov if (mNewState == OnScrollListener.SCROLL_STATE_IDLE 130750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov && mPreviousScrollState != OnScrollListener.SCROLL_STATE_IDLE) { 130850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov View child = mView.getChildAt(0); 130950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov if (child == null) { 131050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov // The view is no longer visible, just return 131150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov return; 131250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 1313e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov int dist = child.getBottom() - mListScrollTopOffset; 1314e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (dist > mListScrollTopOffset) { 131550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov if (mIsScrollingUp) { 131650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mView.smoothScrollBy(dist - child.getHeight(), ADJUSTMENT_SCROLL_DURATION); 131750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } else { 131850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mView.smoothScrollBy(dist, ADJUSTMENT_SCROLL_DURATION); 131950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 132050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 132150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 1322e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mPreviousScrollState = mNewState; 132350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 132450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 132550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 132650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 132750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * <p> 132850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * This is a specialized adapter for creating a list of weeks with 132950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * selectable days. It can be configured to display the week number, start 133050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * the week on a given day, show a reduced number of days, or display an 133150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * arbitrary number of weeks at a time. 133250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * </p> 133350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 1334e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private class WeeksAdapter extends BaseAdapter implements OnTouchListener { 133522c1c2cd103ef8beadaf0e78c12b22b60ce9cfc3Alan Viverette private final Calendar mSelectedDate = Calendar.getInstance(); 133622c1c2cd103ef8beadaf0e78c12b22b60ce9cfc3Alan Viverette private final GestureDetector mGestureDetector; 133750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 1338e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private int mSelectedWeek; 133950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 1340e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private int mFocusedMonth; 134150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 1342e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private int mTotalWeekCount; 134350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 134422c1c2cd103ef8beadaf0e78c12b22b60ce9cfc3Alan Viverette public WeeksAdapter() { 1345e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mGestureDetector = new GestureDetector(mContext, new CalendarGestureListener()); 134650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov init(); 134750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 134850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 134950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 135050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * Set up the gesture detector and selected time 135150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 1352e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private void init() { 1353e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mSelectedWeek = getWeeksSinceMinDate(mSelectedDate); 1354e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mTotalWeekCount = getWeeksSinceMinDate(mMaxDate); 1355e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mMinDate.get(Calendar.DAY_OF_WEEK) != mFirstDayOfWeek 1356e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov || mMaxDate.get(Calendar.DAY_OF_WEEK) != mFirstDayOfWeek) { 1357e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mTotalWeekCount++; 135828104e1de5595a22a6987181b13ddeb192739afdSvetoslav Ganov } 135922c1c2cd103ef8beadaf0e78c12b22b60ce9cfc3Alan Viverette notifyDataSetChanged(); 136050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 136150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 136250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 136350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * Updates the selected day and related parameters. 1364e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * 136550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * @param selectedDay The time to highlight 136650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 136750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov public void setSelectedDay(Calendar selectedDay) { 1368e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (selectedDay.get(Calendar.DAY_OF_YEAR) == mSelectedDate.get(Calendar.DAY_OF_YEAR) 1369e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov && selectedDay.get(Calendar.YEAR) == mSelectedDate.get(Calendar.YEAR)) { 137050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov return; 137150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 1372e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mSelectedDate.setTimeInMillis(selectedDay.getTimeInMillis()); 1373e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mSelectedWeek = getWeeksSinceMinDate(mSelectedDate); 1374e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mFocusedMonth = mSelectedDate.get(Calendar.MONTH); 137550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov notifyDataSetChanged(); 137650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 137750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 137850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 137950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * @return The selected day of month. 138050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 138150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov public Calendar getSelectedDay() { 1382e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov return mSelectedDate; 138350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 138450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 138550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov @Override 138650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov public int getCount() { 138750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov return mTotalWeekCount; 138850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 138950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 139050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov @Override 139150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov public Object getItem(int position) { 139250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov return null; 139350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 139450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 139550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov @Override 139650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov public long getItemId(int position) { 139750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov return position; 139850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 139950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 140050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov @Override 140150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov public View getView(int position, View convertView, ViewGroup parent) { 140251c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov WeekView weekView = null; 140350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov if (convertView != null) { 140451c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov weekView = (WeekView) convertView; 140550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } else { 140651c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov weekView = new WeekView(mContext); 140750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov android.widget.AbsListView.LayoutParams params = 140851c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov new android.widget.AbsListView.LayoutParams(LayoutParams.WRAP_CONTENT, 140951c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov LayoutParams.WRAP_CONTENT); 141051c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov weekView.setLayoutParams(params); 141151c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov weekView.setClickable(true); 141251c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov weekView.setOnTouchListener(this); 141350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 141450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 141551c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov int selectedWeekDay = (mSelectedWeek == position) ? mSelectedDate.get( 141651c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov Calendar.DAY_OF_WEEK) : -1; 141751c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov weekView.init(position, selectedWeekDay, mFocusedMonth); 141850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 141951c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov return weekView; 142050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 142150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 142250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 142350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * Changes which month is in focus and updates the view. 142450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * 142550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * @param month The month to show as in focus [0-11] 142650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 142750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov public void setFocusMonth(int month) { 1428e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mFocusedMonth == month) { 142950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov return; 143050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 1431e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mFocusedMonth = month; 143250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov notifyDataSetChanged(); 143350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 143450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 143550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov @Override 143650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov public boolean onTouch(View v, MotionEvent event) { 143751c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov if (mListView.isEnabled() && mGestureDetector.onTouchEvent(event)) { 143850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov WeekView weekView = (WeekView) v; 14391a730dcc4fdf78f97b3640f20323be5f2d5c4516Svetoslav Ganov // if we cannot find a day for the given location we are done 14401a730dcc4fdf78f97b3640f20323be5f2d5c4516Svetoslav Ganov if (!weekView.getDayFromLocation(event.getX(), mTempDate)) { 14411a730dcc4fdf78f97b3640f20323be5f2d5c4516Svetoslav Ganov return true; 14421a730dcc4fdf78f97b3640f20323be5f2d5c4516Svetoslav Ganov } 144328104e1de5595a22a6987181b13ddeb192739afdSvetoslav Ganov // it is possible that the touched day is outside the valid range 144428104e1de5595a22a6987181b13ddeb192739afdSvetoslav Ganov // we draw whole weeks but range end can fall not on the week end 1445e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mTempDate.before(mMinDate) || mTempDate.after(mMaxDate)) { 144628104e1de5595a22a6987181b13ddeb192739afdSvetoslav Ganov return true; 144750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 1448e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov onDateTapped(mTempDate); 144950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov return true; 145050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 145150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov return false; 145250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 145350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 145450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 145550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * Maintains the same hour/min/sec but moves the day to the tapped day. 1456e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * 145750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * @param day The day that was tapped 145850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 1459e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private void onDateTapped(Calendar day) { 146050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov setSelectedDay(day); 146128104e1de5595a22a6987181b13ddeb192739afdSvetoslav Ganov setMonthDisplayed(day); 146250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 146350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 146450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 146550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * This is here so we can identify single tap events and set the 146650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * selected day correctly 146750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 1468e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov class CalendarGestureListener extends GestureDetector.SimpleOnGestureListener { 146950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov @Override 147050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov public boolean onSingleTapUp(MotionEvent e) { 147150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov return true; 147250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 147350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 147450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 147550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 147650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 147750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * <p> 147850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * This is a dynamic view for drawing a single week. It can be configured to 147950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * display the week number, start the week on a given day, or show a reduced 148050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * number of days. It is intended for use as a single view within a 148150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * ListView. See {@link WeeksAdapter} for usage. 148250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * </p> 148350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 1484e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private class WeekView extends View { 148550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 1486e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private final Rect mTempRect = new Rect(); 148750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 1488e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private final Paint mDrawPaint = new Paint(); 148999b539f6326a5f0df123b34766becec023bf7a84Svetoslav Ganov 1490e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private final Paint mMonthNumDrawPaint = new Paint(); 149199b539f6326a5f0df123b34766becec023bf7a84Svetoslav Ganov 149250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov // Cache the number strings so we don't have to recompute them each time 1493e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private String[] mDayNumbers; 149450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 149550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov // Quick lookup for checking which days are in the focus month 1496e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private boolean[] mFocusDay; 149750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 1498ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov // Whether this view has a focused day. 1499ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov private boolean mHasFocusedDay; 1500ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov 1501ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov // Whether this view has only focused days. 1502ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov private boolean mHasUnfocusedDay; 1503ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov 150450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov // The first day displayed by this item 1505e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private Calendar mFirstDay; 150650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 150750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov // The month of the first day in this week 1508e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private int mMonthOfFirstWeekDay = -1; 150950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 151050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov // The month of the last day in this week 1511e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private int mLastWeekDayMonth = -1; 151250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 151350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov // The position of this week, equivalent to weeks since the week of Jan 151450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov // 1st, 1900 1515e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private int mWeek = -1; 151650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 151750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov // Quick reference to the width of this view, matches parent 1518e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private int mWidth; 151950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 152050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov // The height this view should draw at in pixels, set by height param 1521e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private int mHeight; 152250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 152350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov // If this view contains the selected day 1524e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private boolean mHasSelectedDay = false; 152550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 152650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov // Which day is selected [0-6] or -1 if no day is selected 152751c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov private int mSelectedDay = -1; 152850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 152950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov // The number of days + a spot for week number if it is displayed 1530e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private int mNumCells; 153150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 153250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov // The left edge of the selected day 1533e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private int mSelectedLeft = -1; 153450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 153550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov // The right edge of the selected day 1536e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private int mSelectedRight = -1; 153750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 153850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov public WeekView(Context context) { 153950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov super(context); 154050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 154150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov // Sets up any standard paints that will be used 1542ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov initilaizePaints(); 154350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 154450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 154550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 154651c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov * Initializes this week view. 154750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * 154851c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov * @param weekNumber The number of the week this view represents. The 154951c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov * week number is a zero based index of the weeks since 155051c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov * {@link CalendarView#getMinDate()}. 155151c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov * @param selectedWeekDay The selected day of the week from 0 to 6, -1 if no 155251c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov * selected day. 155351c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov * @param focusedMonth The month that is currently in focus i.e. 155451c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov * highlighted. 155550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 155651c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov public void init(int weekNumber, int selectedWeekDay, int focusedMonth) { 155751c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov mSelectedDay = selectedWeekDay; 155851c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov mHasSelectedDay = mSelectedDay != -1; 1559e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mNumCells = mShowWeekNumber ? mDaysPerWeek + 1 : mDaysPerWeek; 156051c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov mWeek = weekNumber; 1561e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mTempDate.setTimeInMillis(mMinDate.getTimeInMillis()); 156258f51255eb20f9c4d16c11554f372ff92d45fcc7Svetoslav Ganov 1563e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mTempDate.add(Calendar.WEEK_OF_YEAR, mWeek); 1564e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mTempDate.setFirstDayOfWeek(mFirstDayOfWeek); 156550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 156650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov // Allocate space for caching the day numbers and focus values 156750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mDayNumbers = new String[mNumCells]; 156850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mFocusDay = new boolean[mNumCells]; 156950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 157050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov // If we're showing the week number calculate it based on Monday 157150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov int i = 0; 157299b539f6326a5f0df123b34766becec023bf7a84Svetoslav Ganov if (mShowWeekNumber) { 1573d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio mDayNumbers[0] = String.format(Locale.getDefault(), "%d", 1574d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio mTempDate.get(Calendar.WEEK_OF_YEAR)); 157550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov i++; 157650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 157750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 157850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov // Now adjust our starting day based on the start day of the week 1579e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov int diff = mFirstDayOfWeek - mTempDate.get(Calendar.DAY_OF_WEEK); 1580e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mTempDate.add(Calendar.DAY_OF_MONTH, diff); 158150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 1582e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mFirstDay = (Calendar) mTempDate.clone(); 1583e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mMonthOfFirstWeekDay = mTempDate.get(Calendar.MONTH); 158450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 1585ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov mHasUnfocusedDay = true; 158650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov for (; i < mNumCells; i++) { 1587ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov final boolean isFocusedDay = (mTempDate.get(Calendar.MONTH) == focusedMonth); 1588ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov mFocusDay[i] = isFocusedDay; 1589ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov mHasFocusedDay |= isFocusedDay; 1590ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov mHasUnfocusedDay &= !isFocusedDay; 159128104e1de5595a22a6987181b13ddeb192739afdSvetoslav Ganov // do not draw dates outside the valid range to avoid user confusion 1592e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mTempDate.before(mMinDate) || mTempDate.after(mMaxDate)) { 159328104e1de5595a22a6987181b13ddeb192739afdSvetoslav Ganov mDayNumbers[i] = ""; 159428104e1de5595a22a6987181b13ddeb192739afdSvetoslav Ganov } else { 1595d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio mDayNumbers[i] = String.format(Locale.getDefault(), "%d", 1596d88e3054d08b1f821bb2e27b2647aa16a60d8742Fabrice Di Meglio mTempDate.get(Calendar.DAY_OF_MONTH)); 159728104e1de5595a22a6987181b13ddeb192739afdSvetoslav Ganov } 1598e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mTempDate.add(Calendar.DAY_OF_MONTH, 1); 159950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 160050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov // We do one extra add at the end of the loop, if that pushed us to 160150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov // new month undo it 1602e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov if (mTempDate.get(Calendar.DAY_OF_MONTH) == 1) { 1603e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mTempDate.add(Calendar.DAY_OF_MONTH, -1); 160450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 1605e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mLastWeekDayMonth = mTempDate.get(Calendar.MONTH); 160650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 160750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov updateSelectionPositions(); 160850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 160950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 161050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 16110c6f3795b3c9ee5210e8933deb10d3a5d2cabec9Svetoslav Ganov * Initialize the paint instances. 161250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 1613ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov private void initilaizePaints() { 161450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mDrawPaint.setFakeBoldText(false); 161550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mDrawPaint.setAntiAlias(true); 161650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mDrawPaint.setStyle(Style.FILL); 161750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 161850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mMonthNumDrawPaint.setFakeBoldText(true); 161950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mMonthNumDrawPaint.setAntiAlias(true); 162050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mMonthNumDrawPaint.setStyle(Style.FILL); 162150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mMonthNumDrawPaint.setTextAlign(Align.CENTER); 16220c6f3795b3c9ee5210e8933deb10d3a5d2cabec9Svetoslav Ganov mMonthNumDrawPaint.setTextSize(mDateTextSize); 162350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 162450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 162550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 162650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * Returns the month of the first day in this week. 162750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * 162850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * @return The month the first day of this view is in. 162950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 163050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov public int getMonthOfFirstWeekDay() { 163150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov return mMonthOfFirstWeekDay; 163250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 163350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 163450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 163550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * Returns the month of the last day in this week 163650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * 163750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * @return The month the last day of this view is in 163850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 163950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov public int getMonthOfLastWeekDay() { 164050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov return mLastWeekDayMonth; 164150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 164250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 164350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 164450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * Returns the first day in this view. 164550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * 164650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * @return The first day in the view. 164750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 164850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov public Calendar getFirstDay() { 164950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov return mFirstDay; 165050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 165150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 165250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 165350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * Calculates the day that the given x position is in, accounting for 16541a730dcc4fdf78f97b3640f20323be5f2d5c4516Svetoslav Ganov * week number. 165550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * 16561a730dcc4fdf78f97b3640f20323be5f2d5c4516Svetoslav Ganov * @param x The x position of the touch event. 16571a730dcc4fdf78f97b3640f20323be5f2d5c4516Svetoslav Ganov * @return True if a day was found for the given location. 165850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 16591a730dcc4fdf78f97b3640f20323be5f2d5c4516Svetoslav Ganov public boolean getDayFromLocation(float x, Calendar outCalendar) { 1660550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio final boolean isLayoutRtl = isLayoutRtl(); 1661550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio 1662550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio int start; 1663550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio int end; 1664550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio 1665550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio if (isLayoutRtl) { 1666550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio start = 0; 1667550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio end = mShowWeekNumber ? mWidth - mWidth / mNumCells : mWidth; 1668550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio } else { 1669550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio start = mShowWeekNumber ? mWidth / mNumCells : 0; 1670550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio end = mWidth; 1671550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio } 1672550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio 1673550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio if (x < start || x > end) { 1674e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov outCalendar.clear(); 16751a730dcc4fdf78f97b3640f20323be5f2d5c4516Svetoslav Ganov return false; 167650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 1677550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio 1678550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio // Selection is (x - start) / (pixels/day) which is (x - start) * day / pixels 1679550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio int dayPosition = (int) ((x - start) * mDaysPerWeek / (end - start)); 1680550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio 1681550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio if (isLayoutRtl) { 1682550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio dayPosition = mDaysPerWeek - 1 - dayPosition; 1683550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio } 1684550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio 168550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov outCalendar.setTimeInMillis(mFirstDay.getTimeInMillis()); 168650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov outCalendar.add(Calendar.DAY_OF_MONTH, dayPosition); 1687550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio 16881a730dcc4fdf78f97b3640f20323be5f2d5c4516Svetoslav Ganov return true; 168950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 169050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 169150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov @Override 169250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov protected void onDraw(Canvas canvas) { 169350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov drawBackground(canvas); 1694ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov drawWeekNumbersAndDates(canvas); 1695e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov drawWeekSeparators(canvas); 1696e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov drawSelectedDateVerticalBars(canvas); 169750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 169850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 169950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 170050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * This draws the selection highlight if a day is selected in this week. 170150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * 170250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * @param canvas The canvas to draw on 170350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 1704e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private void drawBackground(Canvas canvas) { 170550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov if (!mHasSelectedDay) { 170650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov return; 170750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 1708e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mDrawPaint.setColor(mSelectedWeekBackgroundColor); 170950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 1710e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mTempRect.top = mWeekSeperatorLineWidth; 171150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mTempRect.bottom = mHeight; 1712550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio 1713550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio final boolean isLayoutRtl = isLayoutRtl(); 1714550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio 1715550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio if (isLayoutRtl) { 1716550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio mTempRect.left = 0; 1717550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio mTempRect.right = mSelectedLeft - 2; 1718550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio } else { 1719550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio mTempRect.left = mShowWeekNumber ? mWidth / mNumCells : 0; 1720550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio mTempRect.right = mSelectedLeft - 2; 1721550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio } 172250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov canvas.drawRect(mTempRect, mDrawPaint); 172350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 1724550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio if (isLayoutRtl) { 1725550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio mTempRect.left = mSelectedRight + 3; 1726550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio mTempRect.right = mShowWeekNumber ? mWidth - mWidth / mNumCells : mWidth; 1727550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio } else { 1728550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio mTempRect.left = mSelectedRight + 3; 1729550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio mTempRect.right = mWidth; 1730550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio } 173150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov canvas.drawRect(mTempRect, mDrawPaint); 173250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 173350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 173450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 1735e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Draws the week and month day numbers for this week. 173650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * 173750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * @param canvas The canvas to draw on 173850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 1739ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov private void drawWeekNumbersAndDates(Canvas canvas) { 1740550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio final float textHeight = mDrawPaint.getTextSize(); 1741550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio final int y = (int) ((mHeight + textHeight) / 2) - mWeekSeperatorLineWidth; 1742550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio final int nDays = mNumCells; 1743550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio final int divisor = 2 * nDays; 174450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 174550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mDrawPaint.setTextAlign(Align.CENTER); 1746ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov mDrawPaint.setTextSize(mDateTextSize); 1747550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio 174850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov int i = 0; 1749550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio 1750550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio if (isLayoutRtl()) { 1751550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio for (; i < nDays - 1; i++) { 1752550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio mMonthNumDrawPaint.setColor(mFocusDay[i] ? mFocusedMonthDateColor 1753550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio : mUnfocusedMonthDateColor); 1754550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio int x = (2 * i + 1) * mWidth / divisor; 1755550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio canvas.drawText(mDayNumbers[nDays - 1 - i], x, y, mMonthNumDrawPaint); 1756550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio } 1757550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio if (mShowWeekNumber) { 1758550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio mDrawPaint.setColor(mWeekNumberColor); 1759550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio int x = mWidth - mWidth / divisor; 1760550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio canvas.drawText(mDayNumbers[0], x, y, mDrawPaint); 1761550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio } 1762550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio } else { 1763550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio if (mShowWeekNumber) { 1764550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio mDrawPaint.setColor(mWeekNumberColor); 1765550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio int x = mWidth / divisor; 1766550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio canvas.drawText(mDayNumbers[0], x, y, mDrawPaint); 1767550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio i++; 1768550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio } 1769550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio for (; i < nDays; i++) { 1770550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio mMonthNumDrawPaint.setColor(mFocusDay[i] ? mFocusedMonthDateColor 1771550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio : mUnfocusedMonthDateColor); 1772550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio int x = (2 * i + 1) * mWidth / divisor; 1773550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio canvas.drawText(mDayNumbers[i], x, y, mMonthNumDrawPaint); 1774550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio } 177550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 177650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 177750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 177850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 1779e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Draws a horizontal line for separating the weeks. 178050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * 178199b539f6326a5f0df123b34766becec023bf7a84Svetoslav Ganov * @param canvas The canvas to draw on. 178250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 1783e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private void drawWeekSeparators(Canvas canvas) { 178499b539f6326a5f0df123b34766becec023bf7a84Svetoslav Ganov // If it is the topmost fully visible child do not draw separator line 178599b539f6326a5f0df123b34766becec023bf7a84Svetoslav Ganov int firstFullyVisiblePosition = mListView.getFirstVisiblePosition(); 178699b539f6326a5f0df123b34766becec023bf7a84Svetoslav Ganov if (mListView.getChildAt(0).getTop() < 0) { 178799b539f6326a5f0df123b34766becec023bf7a84Svetoslav Ganov firstFullyVisiblePosition++; 178899b539f6326a5f0df123b34766becec023bf7a84Svetoslav Ganov } 178999b539f6326a5f0df123b34766becec023bf7a84Svetoslav Ganov if (firstFullyVisiblePosition == mWeek) { 179099b539f6326a5f0df123b34766becec023bf7a84Svetoslav Ganov return; 179199b539f6326a5f0df123b34766becec023bf7a84Svetoslav Ganov } 1792e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mDrawPaint.setColor(mWeekSeparatorLineColor); 1793e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mDrawPaint.setStrokeWidth(mWeekSeperatorLineWidth); 1794550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio float startX; 1795550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio float stopX; 1796550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio if (isLayoutRtl()) { 1797550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio startX = 0; 1798550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio stopX = mShowWeekNumber ? mWidth - mWidth / mNumCells : mWidth; 1799550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio } else { 1800550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio startX = mShowWeekNumber ? mWidth / mNumCells : 0; 1801550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio stopX = mWidth; 1802550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio } 1803550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio canvas.drawLine(startX, 0, stopX, 0, mDrawPaint); 180499b539f6326a5f0df123b34766becec023bf7a84Svetoslav Ganov } 180550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 180699b539f6326a5f0df123b34766becec023bf7a84Svetoslav Ganov /** 1807e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov * Draws the selected date bars if this week has a selected day. 180899b539f6326a5f0df123b34766becec023bf7a84Svetoslav Ganov * 180999b539f6326a5f0df123b34766becec023bf7a84Svetoslav Ganov * @param canvas The canvas to draw on 181099b539f6326a5f0df123b34766becec023bf7a84Svetoslav Ganov */ 1811e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private void drawSelectedDateVerticalBars(Canvas canvas) { 181299b539f6326a5f0df123b34766becec023bf7a84Svetoslav Ganov if (!mHasSelectedDay) { 181399b539f6326a5f0df123b34766becec023bf7a84Svetoslav Ganov return; 181450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 1815e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mSelectedDateVerticalBar.setBounds(mSelectedLeft - mSelectedDateVerticalBarWidth / 2, 1816e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mWeekSeperatorLineWidth, 1817e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mSelectedLeft + mSelectedDateVerticalBarWidth / 2, mHeight); 1818e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mSelectedDateVerticalBar.draw(canvas); 1819e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mSelectedDateVerticalBar.setBounds(mSelectedRight - mSelectedDateVerticalBarWidth / 2, 1820e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mWeekSeperatorLineWidth, 1821e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mSelectedRight + mSelectedDateVerticalBarWidth / 2, mHeight); 1822e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov mSelectedDateVerticalBar.draw(canvas); 182350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 182450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 182550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov @Override 182650f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov protected void onSizeChanged(int w, int h, int oldw, int oldh) { 182750f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov mWidth = w; 182850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov updateSelectionPositions(); 182950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 183050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 183150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov /** 183250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov * This calculates the positions for the selected day lines. 183350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov */ 1834e9730bf3d2dcbea1879f24c18aaf9810ac57084cSvetoslav Ganov private void updateSelectionPositions() { 183550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov if (mHasSelectedDay) { 1836550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio final boolean isLayoutRtl = isLayoutRtl(); 183751c52edad7d40697d7fb2a091f850506fa897643Svetoslav Ganov int selectedPosition = mSelectedDay - mFirstDayOfWeek; 183850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov if (selectedPosition < 0) { 183950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov selectedPosition += 7; 184050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 1841550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio if (mShowWeekNumber && !isLayoutRtl) { 184250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov selectedPosition++; 184350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 1844550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio if (isLayoutRtl) { 1845550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio mSelectedLeft = (mDaysPerWeek - 1 - selectedPosition) * mWidth / mNumCells; 1846550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio 1847550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio } else { 1848550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio mSelectedLeft = selectedPosition * mWidth / mNumCells; 1849550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio } 1850550ea7f5465d95b65b7d02aed67d903c9beeba47Fabrice Di Meglio mSelectedRight = mSelectedLeft + mWidth / mNumCells; 185150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 185250f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 185350f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov 185450f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov @Override 185550f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 1856ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov mHeight = (mListView.getHeight() - mListView.getPaddingTop() - mListView 1857ff37505cb13f96ddec09594517ad6f4fa2fd1defSvetoslav Ganov .getPaddingBottom()) / mShownWeekCount; 185850f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), mHeight); 185950f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 186050f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov } 186150f34d14f6dd3411fdbdb6a7b8b285c2b8fdbf5cSvetoslav Ganov} 1862