SimpleMonthAdapter.java revision 50eb025c2fea7e364e0be951ce8ba6ca605f901a
1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.widget;
18
19import android.content.Context;
20import android.content.res.ColorStateList;
21import android.view.View;
22import android.view.ViewGroup;
23
24import java.util.Calendar;
25import java.util.HashMap;
26
27/**
28 * An adapter for a list of {@link android.widget.SimpleMonthView} items.
29 */
30class SimpleMonthAdapter extends BaseAdapter implements SimpleMonthView.OnDayClickListener {
31    private final Calendar mMinDate = Calendar.getInstance();
32    private final Calendar mMaxDate = Calendar.getInstance();
33
34    private final Context mContext;
35    private final DatePickerController mController;
36
37    private Calendar mSelectedDay;
38    private ColorStateList mCalendarTextColors;
39
40    public SimpleMonthAdapter(Context context, DatePickerController controller) {
41        mContext = context;
42        mController = controller;
43
44        init();
45        setSelectedDay(mController.getSelectedDay());
46    }
47
48    public void setRange(Calendar min, Calendar max) {
49        mMinDate.setTimeInMillis(min.getTimeInMillis());
50        mMaxDate.setTimeInMillis(max.getTimeInMillis());
51
52        notifyDataSetInvalidated();
53    }
54
55    /**
56     * Updates the selected day and related parameters.
57     *
58     * @param day The day to highlight
59     */
60    public void setSelectedDay(Calendar day) {
61        if (mSelectedDay != day) {
62            mSelectedDay = day;
63            notifyDataSetChanged();
64        }
65    }
66
67    void setCalendarTextColor(ColorStateList colors) {
68        mCalendarTextColors = colors;
69    }
70
71    /**
72     * Set up the gesture detector and selected time
73     */
74    protected void init() {
75        mSelectedDay = Calendar.getInstance();
76    }
77
78    @Override
79    public int getCount() {
80        final int diffYear = mMaxDate.get(Calendar.YEAR) - mMinDate.get(Calendar.YEAR);
81        final int diffMonth = mMaxDate.get(Calendar.MONTH) - mMinDate.get(Calendar.MONTH);
82        return diffMonth + 12 * diffYear + 1;
83    }
84
85    @Override
86    public Object getItem(int position) {
87        return null;
88    }
89
90    @Override
91    public long getItemId(int position) {
92        return position;
93    }
94
95    @Override
96    public boolean hasStableIds() {
97        return true;
98    }
99
100    @SuppressWarnings("unchecked")
101    @Override
102    public View getView(int position, View convertView, ViewGroup parent) {
103        final SimpleMonthView v;
104        if (convertView != null) {
105            v = (SimpleMonthView) convertView;
106        } else {
107            v = new SimpleMonthView(mContext);
108
109            // Set up the new view
110            final AbsListView.LayoutParams params = new AbsListView.LayoutParams(
111                    AbsListView.LayoutParams.MATCH_PARENT, AbsListView.LayoutParams.MATCH_PARENT);
112            v.setLayoutParams(params);
113            v.setClickable(true);
114            v.setOnDayClickListener(this);
115
116            if (mCalendarTextColors != null) {
117                v.setTextColor(mCalendarTextColors);
118            }
119        }
120
121        final int minMonth = mMinDate.get(Calendar.MONTH);
122        final int minYear = mMinDate.get(Calendar.YEAR);
123        final int currentMonth = position + minMonth;
124        final int month = currentMonth % 12;
125        final int year = currentMonth / 12 + minYear;
126        final int selectedDay;
127        if (isSelectedDayInMonth(year, month)) {
128            selectedDay = mSelectedDay.get(Calendar.DAY_OF_MONTH);
129        } else {
130            selectedDay = -1;
131        }
132
133        // Invokes requestLayout() to ensure that the recycled view is set with the appropriate
134        // height/number of weeks before being displayed.
135        v.reuse();
136
137        final int enabledDayRangeStart;
138        if (minMonth == month && minYear == year) {
139            enabledDayRangeStart = mMinDate.get(Calendar.DAY_OF_MONTH);
140        } else {
141            enabledDayRangeStart = 1;
142        }
143
144        final int enabledDayRangeEnd;
145        if (mMaxDate.get(Calendar.MONTH) == month && mMaxDate.get(Calendar.YEAR) == year) {
146            enabledDayRangeEnd = mMaxDate.get(Calendar.DAY_OF_MONTH);
147        } else {
148            enabledDayRangeEnd = 31;
149        }
150
151        v.setMonthParams(selectedDay, month, year, mController.getFirstDayOfWeek(),
152                enabledDayRangeStart, enabledDayRangeEnd);
153        v.invalidate();
154
155        return v;
156    }
157
158    private boolean isSelectedDayInMonth(int year, int month) {
159        return mSelectedDay.get(Calendar.YEAR) == year && mSelectedDay.get(Calendar.MONTH) == month;
160    }
161
162    @Override
163    public void onDayClick(SimpleMonthView view, Calendar day) {
164        if (day != null && isCalendarInRange(day)) {
165            onDaySelected(day);
166        }
167    }
168
169    private boolean isCalendarInRange(Calendar value) {
170        return value.compareTo(mMinDate) >= 0 && value.compareTo(mMaxDate) <= 0;
171    }
172
173    /**
174     * Maintains the same hour/min/sec but moves the day to the tapped day.
175     *
176     * @param day The day that was tapped
177     */
178    private void onDaySelected(Calendar day) {
179        mController.tryVibrate();
180        mController.onDayOfMonthSelected(day.get(Calendar.YEAR), day.get(Calendar.MONTH),
181                day.get(Calendar.DAY_OF_MONTH));
182
183        setSelectedDay(day);
184    }
185}
186