1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.calendar.selectcalendars;
18
19import com.android.calendar.R;
20import com.android.calendar.Utils;
21
22import android.content.Context;
23import android.content.res.Configuration;
24import android.content.res.Resources;
25import android.database.Cursor;
26import android.graphics.drawable.Drawable;
27import android.provider.CalendarContract.Calendars;
28import android.text.TextUtils;
29import android.view.LayoutInflater;
30import android.view.View;
31import android.view.ViewGroup;
32import android.view.ViewGroup.LayoutParams;
33import android.widget.BaseAdapter;
34import android.widget.CheckBox;
35import android.widget.ListAdapter;
36import android.widget.RelativeLayout;
37import android.widget.TextView;
38
39public class SelectCalendarsSimpleAdapter extends BaseAdapter implements ListAdapter {
40    private static final String TAG = "SelectCalendarsAdapter";
41    private static int SELECTED_COLOR_CHIP_SIZE = 16;
42    private static int UNSELECTED_COLOR_CHIP_SIZE = 10;
43    private static int COLOR_CHIP_LEFT_MARGIN = 20;
44    private static int COLOR_CHIP_RIGHT_MARGIN = 8;
45    private static int COLOR_CHIP_TOP_OFFSET = 5;
46    private static int BOTTOM_ITEM_HEIGHT = 64;
47    private static int NORMAL_ITEM_HEIGHT = 48;
48
49    private static final int IS_SELECTED = 1 << 0;
50    private static final int IS_TOP = 1 << 1;
51    private static final int IS_BOTTOM = 1 << 2;
52    private static final int IS_BELOW_SELECTED = 1 << 3;
53
54
55    private LayoutInflater mInflater;
56    Resources mRes;
57    private int mLayout;
58    private int mOrientation;
59    private CalendarRow[] mData;
60    private Cursor mCursor;
61    private int mRowCount = 0;
62
63    private int mIdColumn;
64    private int mNameColumn;
65    private int mColorColumn;
66    private int mVisibleColumn;
67    private int mOwnerAccountColumn;
68    private static float mScale = 0;
69    private int mColorCalendarVisible;
70    private int mColorCalendarHidden;
71    private int mColorCalendarSecondaryVisible;
72    private int mColorCalendarSecondaryHidden;
73
74    private class CalendarRow {
75        long id;
76        String displayName;
77        String ownerAccount;
78        int color;
79        boolean selected;
80    }
81
82    public SelectCalendarsSimpleAdapter(Context context, int layout, Cursor c) {
83        super();
84        mLayout = layout;
85        mOrientation = context.getResources().getConfiguration().orientation;
86        initData(c);
87        mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
88        mRes = context.getResources();
89        mColorCalendarVisible = mRes.getColor(R.color.calendar_visible);
90        mColorCalendarHidden = mRes.getColor(R.color.calendar_hidden);
91        mColorCalendarSecondaryVisible = mRes.getColor(R.color.calendar_secondary_visible);
92        mColorCalendarSecondaryHidden = mRes.getColor(R.color.calendar_secondary_hidden);
93
94        if (mScale == 0) {
95            mScale = mRes.getDisplayMetrics().density;
96            SELECTED_COLOR_CHIP_SIZE *= mScale;
97            UNSELECTED_COLOR_CHIP_SIZE *= mScale;
98            COLOR_CHIP_LEFT_MARGIN *= mScale;
99            COLOR_CHIP_RIGHT_MARGIN *= mScale;
100            COLOR_CHIP_TOP_OFFSET *= mScale;
101            BOTTOM_ITEM_HEIGHT *= mScale;
102            NORMAL_ITEM_HEIGHT *= mScale;
103        }
104    }
105
106    private static class TabletCalendarItemBackgrounds {
107        static private int[] mBackgrounds = null;
108
109        /**
110         * Sets up the background drawables for the calendars list
111         *
112         * @param res The context's resources
113         */
114        static int[] getBackgrounds() {
115            // Not thread safe. Ok if called only from main thread
116            if (mBackgrounds != null) {
117                return mBackgrounds;
118            }
119
120            mBackgrounds = new int[16];
121
122            mBackgrounds[0] = R.drawable.calname_unselected;
123
124            mBackgrounds[IS_SELECTED] = R.drawable.calname_select_underunselected;
125
126            mBackgrounds[IS_SELECTED | IS_BOTTOM] =
127                    R.drawable.calname_bottom_select_underunselected;
128
129            mBackgrounds[IS_SELECTED | IS_BOTTOM | IS_BELOW_SELECTED] =
130                    R.drawable.calname_bottom_select_underselect;
131            mBackgrounds[IS_SELECTED | IS_TOP | IS_BOTTOM | IS_BELOW_SELECTED] = mBackgrounds[
132                    IS_SELECTED | IS_BOTTOM | IS_BELOW_SELECTED];
133            mBackgrounds[IS_SELECTED | IS_TOP | IS_BOTTOM] = mBackgrounds[IS_SELECTED | IS_BOTTOM
134                    | IS_BELOW_SELECTED];
135
136            mBackgrounds[IS_SELECTED | IS_BELOW_SELECTED] = R.drawable.calname_select_underselect;
137            mBackgrounds[IS_SELECTED | IS_TOP | IS_BELOW_SELECTED] = mBackgrounds[IS_SELECTED
138                    | IS_BELOW_SELECTED];
139            mBackgrounds[IS_SELECTED | IS_TOP] = mBackgrounds[IS_SELECTED | IS_BELOW_SELECTED];
140
141            mBackgrounds[IS_BOTTOM] = R.drawable.calname_bottom_unselected;
142
143            mBackgrounds[IS_BOTTOM | IS_BELOW_SELECTED] =
144                    R.drawable.calname_bottom_unselected_underselect;
145            mBackgrounds[IS_TOP | IS_BOTTOM | IS_BELOW_SELECTED] = mBackgrounds[IS_BOTTOM
146                    | IS_BELOW_SELECTED];
147            mBackgrounds[IS_TOP | IS_BOTTOM] = mBackgrounds[IS_BOTTOM | IS_BELOW_SELECTED];
148
149            mBackgrounds[IS_BELOW_SELECTED] = R.drawable.calname_unselected_underselect;
150            mBackgrounds[IS_TOP | IS_BELOW_SELECTED] = mBackgrounds[IS_BELOW_SELECTED];
151            mBackgrounds[IS_TOP] = mBackgrounds[IS_BELOW_SELECTED];
152            return mBackgrounds;
153        }
154    }
155
156    private void initData(Cursor c) {
157        if (mCursor != null && c != mCursor) {
158            mCursor.close();
159        }
160        if (c == null) {
161            mCursor = c;
162            mRowCount = 0;
163            mData = null;
164            return;
165        }
166        // TODO create a broadcast listener for ACTION_PROVIDER_CHANGED to update the cursor
167        mCursor = c;
168        mIdColumn = c.getColumnIndexOrThrow(Calendars._ID);
169        mNameColumn = c.getColumnIndexOrThrow(Calendars.CALENDAR_DISPLAY_NAME);
170        mColorColumn = c.getColumnIndexOrThrow(Calendars.CALENDAR_COLOR);
171        mVisibleColumn = c.getColumnIndexOrThrow(Calendars.VISIBLE);
172        mOwnerAccountColumn = c.getColumnIndexOrThrow(Calendars.OWNER_ACCOUNT);
173
174        mRowCount = c.getCount();
175        mData = new CalendarRow[(c.getCount())];
176        c.moveToPosition(-1);
177        int p = 0;
178        while (c.moveToNext()) {
179            mData[p] = new CalendarRow();
180            mData[p].id = c.getLong(mIdColumn);
181            mData[p].displayName = c.getString(mNameColumn);
182            mData[p].color = c.getInt(mColorColumn);
183            mData[p].selected = c.getInt(mVisibleColumn) != 0;
184            mData[p].ownerAccount = c.getString(mOwnerAccountColumn);
185            p++;
186        }
187    }
188
189    public void changeCursor(Cursor c) {
190        initData(c);
191        notifyDataSetChanged();
192    }
193
194    public View getView(int position, View convertView, ViewGroup parent) {
195        if (position >= mRowCount) {
196            return null;
197        }
198        String name = mData[position].displayName;
199        boolean selected = mData[position].selected;
200
201        int color = Utils.getDisplayColorFromColor(mData[position].color);
202        View view;
203        if (convertView == null) {
204            view = mInflater.inflate(mLayout, parent, false);
205        } else {
206            view = convertView;
207        }
208
209        TextView calendarName = (TextView) view.findViewById(R.id.calendar);
210        calendarName.setText(name);
211
212        View colorView = view.findViewById(R.id.color);
213        colorView.setBackgroundColor(color);
214
215        CheckBox syncCheckBox = (CheckBox) view.findViewById(R.id.sync);
216        if (syncCheckBox != null) {
217            // Full screen layout
218            syncCheckBox.setChecked(selected);
219
220            int textColor;
221            if (selected) {
222                textColor = mColorCalendarVisible;
223            } else {
224                textColor = mColorCalendarHidden;
225            }
226            calendarName.setTextColor(textColor);
227            LayoutParams layoutParam = calendarName.getLayoutParams();
228
229            TextView secondaryText = (TextView) view.findViewById(R.id.status);
230            if (!TextUtils.isEmpty(mData[position].ownerAccount)
231                    && !mData[position].ownerAccount.equals(name)
232                    && !mData[position].ownerAccount.endsWith("calendar.google.com")) {
233                int secondaryColor;
234                if (selected) {
235                    secondaryColor = mColorCalendarSecondaryVisible;
236                } else {
237                    secondaryColor = mColorCalendarSecondaryHidden;
238                }
239                secondaryText.setText(mData[position].ownerAccount);
240                secondaryText.setTextColor(secondaryColor);
241                secondaryText.setVisibility(View.VISIBLE);
242                layoutParam.height = LayoutParams.WRAP_CONTENT;
243            } else {
244                secondaryText.setVisibility(View.GONE);
245                layoutParam.height = LayoutParams.MATCH_PARENT;
246            }
247
248            calendarName.setLayoutParams(layoutParam);
249
250        } else {
251            // Tablet layout
252            RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
253                    SELECTED_COLOR_CHIP_SIZE, SELECTED_COLOR_CHIP_SIZE);
254            params.leftMargin = COLOR_CHIP_LEFT_MARGIN;
255            params.rightMargin = COLOR_CHIP_RIGHT_MARGIN;
256            // This offset is needed because the assets include the bottom of the
257            // previous item
258            params.topMargin = COLOR_CHIP_TOP_OFFSET;
259            if (!selected) {
260                params.height = UNSELECTED_COLOR_CHIP_SIZE;
261                params.width = UNSELECTED_COLOR_CHIP_SIZE;
262                params.leftMargin += (SELECTED_COLOR_CHIP_SIZE - UNSELECTED_COLOR_CHIP_SIZE) / 2;
263                params.topMargin += (SELECTED_COLOR_CHIP_SIZE - UNSELECTED_COLOR_CHIP_SIZE) / 2;
264            }
265            colorView.setLayoutParams(params);
266
267            Drawable bg = getBackground(position, selected);
268            view.setBackgroundDrawable(bg);
269            ViewGroup.LayoutParams newParams = view.getLayoutParams();
270            if (position == mData.length - 1) {
271                newParams.height = BOTTOM_ITEM_HEIGHT;
272            } else {
273                newParams.height = NORMAL_ITEM_HEIGHT;
274            }
275            view.setLayoutParams(newParams);
276            CheckBox visibleCheckBox = (CheckBox) view.findViewById(R.id.visible_check_box);
277            if (visibleCheckBox != null) {
278                visibleCheckBox.setChecked(selected);
279            }
280        }
281        view.invalidate();
282        return view;
283    }
284
285    /**
286     * @param position position of the calendar item
287     * @param selected whether it is selected or not
288     * @return the drawable to use for this view
289     */
290    protected Drawable getBackground(int position, boolean selected) {
291        int bg;
292        bg = selected ? IS_SELECTED : 0;
293        bg |= (position == 0 && mOrientation == Configuration.ORIENTATION_LANDSCAPE) ? IS_TOP : 0;
294        bg |= position == mData.length - 1 ? IS_BOTTOM : 0;
295        bg |= (position > 0 && mData[position - 1].selected) ? IS_BELOW_SELECTED : 0;
296        return mRes.getDrawable(TabletCalendarItemBackgrounds.getBackgrounds()[bg]);
297    }
298
299    public int getCount() {
300        return mRowCount;
301    }
302
303    public Object getItem(int position) {
304        if (position >= mRowCount) {
305            return null;
306        }
307        CalendarRow item = mData[position];
308        return item;
309    }
310
311    public long getItemId(int position) {
312        if (position >= mRowCount) {
313            return 0;
314        }
315        return mData[position].id;
316    }
317
318    public void setVisible(int position, int visible) {
319        mData[position].selected = visible != 0;
320        notifyDataSetChanged();
321    }
322
323    public int getVisible(int position) {
324        return mData[position].selected ? 1 : 0;
325    }
326
327    @Override
328    public boolean hasStableIds() {
329        return true;
330    }
331}
332