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