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 static final String TAG = "SimpleMonthAdapter";
32
33    private final Context mContext;
34    private final DatePickerController mController;
35    private Calendar mSelectedDay;
36
37    private ColorStateList mCalendarTextColors;
38
39    public SimpleMonthAdapter(Context context, DatePickerController controller) {
40        mContext = context;
41        mController = controller;
42        init();
43        setSelectedDay(mController.getSelectedDay());
44    }
45
46    /**
47     * Updates the selected day and related parameters.
48     *
49     * @param day The day to highlight
50     */
51    public void setSelectedDay(Calendar day) {
52        if (mSelectedDay != day) {
53            mSelectedDay = day;
54            notifyDataSetChanged();
55        }
56    }
57
58    void setCalendarTextColor(ColorStateList colors) {
59        mCalendarTextColors = colors;
60    }
61
62    /**
63     * Set up the gesture detector and selected time
64     */
65    protected void init() {
66        mSelectedDay = Calendar.getInstance();
67    }
68
69    @Override
70    public int getCount() {
71        final int diffYear = mController.getMaxYear() - mController.getMinYear();
72        final int diffMonth = 1 + mController.getMaxMonth() - mController.getMinMonth()
73                + 12 * diffYear;
74        return diffMonth;
75    }
76
77    @Override
78    public Object getItem(int position) {
79        return null;
80    }
81
82    @Override
83    public long getItemId(int position) {
84        return position;
85    }
86
87    @Override
88    public boolean hasStableIds() {
89        return true;
90    }
91
92    @SuppressWarnings("unchecked")
93    @Override
94    public View getView(int position, View convertView, ViewGroup parent) {
95        SimpleMonthView v;
96        HashMap<String, Integer> drawingParams = null;
97        if (convertView != null) {
98            v = (SimpleMonthView) convertView;
99            // We store the drawing parameters in the view so it can be recycled
100            drawingParams = (HashMap<String, Integer>) v.getTag();
101        } else {
102            v = new SimpleMonthView(mContext);
103            // Set up the new view
104            AbsListView.LayoutParams params = new AbsListView.LayoutParams(
105                    AbsListView.LayoutParams.MATCH_PARENT, AbsListView.LayoutParams.MATCH_PARENT);
106            v.setLayoutParams(params);
107            v.setClickable(true);
108            v.setOnDayClickListener(this);
109            if (mCalendarTextColors != null) {
110                v.setTextColor(mCalendarTextColors);
111            }
112        }
113        if (drawingParams == null) {
114            drawingParams = new HashMap<String, Integer>();
115        } else {
116            drawingParams.clear();
117        }
118        final int currentMonth = position + mController.getMinMonth();
119        final int month = currentMonth % 12;
120        final int year = currentMonth / 12 + mController.getMinYear();
121
122        int selectedDay = -1;
123        if (isSelectedDayInMonth(year, month)) {
124            selectedDay = mSelectedDay.get(Calendar.DAY_OF_MONTH);
125        }
126
127        // Invokes requestLayout() to ensure that the recycled view is set with the appropriate
128        // height/number of weeks before being displayed.
129        v.reuse();
130
131        final int enabledDayRangeStart;
132        if (mController.getMinMonth() == month && mController.getMinYear() == year) {
133            enabledDayRangeStart = mController.getMinDay();
134        } else {
135            enabledDayRangeStart = 1;
136        }
137
138        final int enabledDayRangeEnd;
139        if (mController.getMaxMonth() == month && mController.getMaxYear() == year) {
140            enabledDayRangeEnd = mController.getMaxDay();
141        } else {
142            enabledDayRangeEnd = 31;
143        }
144
145        v.setMonthParams(selectedDay, month, year, mController.getFirstDayOfWeek(),
146                enabledDayRangeStart, enabledDayRangeEnd);
147        v.invalidate();
148
149        return v;
150    }
151
152    private boolean isSelectedDayInMonth(int year, int month) {
153        return mSelectedDay.get(Calendar.YEAR) == year && mSelectedDay.get(Calendar.MONTH) == month;
154    }
155
156    @Override
157    public void onDayClick(SimpleMonthView view, Calendar day) {
158        if (day != null) {
159            onDayTapped(day);
160        }
161    }
162
163    /**
164     * Maintains the same hour/min/sec but moves the day to the tapped day.
165     *
166     * @param day The day that was tapped
167     */
168    protected void onDayTapped(Calendar day) {
169        mController.tryVibrate();
170        mController.onDayOfMonthSelected(day.get(Calendar.YEAR), day.get(Calendar.MONTH),
171                day.get(Calendar.DAY_OF_MONTH));
172        setSelectedDay(day);
173    }
174}
175