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.Resources; 22 import android.database.Cursor; 23 import android.graphics.Rect; 24 import android.graphics.drawable.shapes.RectShape; 25 import android.provider.CalendarContract.Calendars; 26 import android.text.TextUtils; 27 import android.view.LayoutInflater; 28 import android.view.TouchDelegate; 29 import android.view.View; 30 import android.view.View.OnClickListener; 31 import android.view.ViewGroup; 32 import android.widget.AdapterView; 33 import android.widget.BaseAdapter; 34 import android.widget.CheckBox; 35 import android.widget.ListAdapter; 36 import android.widget.TextView; 37 38 import com.android.calendar.CalendarColorPickerDialog; 39 import com.android.calendar.R; 40 import com.android.calendar.Utils; 41 import com.android.calendar.selectcalendars.CalendarColorCache.OnCalendarColorsLoadedListener; 42 43 import java.util.HashMap; 44 45 public class SelectCalendarsSyncAdapter extends BaseAdapter 46 implements ListAdapter, AdapterView.OnItemClickListener, OnCalendarColorsLoadedListener { 47 private static final String TAG = "SelCalsAdapter"; 48 private static final String COLOR_PICKER_DIALOG_TAG = "ColorPickerDialog"; 49 50 private static int COLOR_CHIP_SIZE = 30; 51 private RectShape r = new RectShape(); 52 53 private CalendarColorPickerDialog mColorPickerDialog; 54 private CalendarColorCache mCache; 55 56 private LayoutInflater mInflater; 57 private static final int LAYOUT = R.layout.calendar_sync_item; 58 private CalendarRow[] mData; 59 private HashMap<Long, CalendarRow> mChanges = new HashMap<Long, CalendarRow>(); 60 private int mRowCount = 0; 61 62 private int mIdColumn; 63 private int mNameColumn; 64 private int mColorColumn; 65 private int mSyncedColumn; 66 private int mAccountNameColumn; 67 private int mAccountTypeColumn; 68 69 private boolean mIsTablet; 70 private FragmentManager mFragmentManager; 71 private int mColorViewTouchAreaIncrease; 72 73 74 private final String mSyncedString; 75 private final String mNotSyncedString; 76 77 public class CalendarRow { 78 long id; 79 String displayName; 80 int color; 81 boolean synced; 82 boolean originalSynced; 83 String accountName; 84 String accountType; 85 } 86 87 public SelectCalendarsSyncAdapter(Context context, Cursor c, FragmentManager manager) { 88 super(); 89 initData(c); 90 mCache = new CalendarColorCache(context, this); 91 mFragmentManager = manager; 92 mColorPickerDialog = (CalendarColorPickerDialog) 93 manager.findFragmentByTag(COLOR_PICKER_DIALOG_TAG); 94 mColorViewTouchAreaIncrease = context.getResources() 95 .getDimensionPixelSize(R.dimen.color_view_touch_area_increase); 96 mIsTablet = Utils.getConfigBool(context, R.bool.tablet_config); 97 mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 98 COLOR_CHIP_SIZE *= context.getResources().getDisplayMetrics().density; 99 r.resize(COLOR_CHIP_SIZE, COLOR_CHIP_SIZE); 100 Resources res = context.getResources(); 101 mSyncedString = res.getString(R.string.synced); 102 mNotSyncedString = res.getString(R.string.not_synced); 103 } 104 105 private void initData(Cursor c) { 106 if (c == null) { 107 mRowCount = 0; 108 mData = null; 109 return; 110 } 111 112 mIdColumn = c.getColumnIndexOrThrow(Calendars._ID); 113 mNameColumn = c.getColumnIndexOrThrow(Calendars.CALENDAR_DISPLAY_NAME); 114 mColorColumn = c.getColumnIndexOrThrow(Calendars.CALENDAR_COLOR); 115 mSyncedColumn = c.getColumnIndexOrThrow(Calendars.SYNC_EVENTS); 116 mAccountNameColumn = c.getColumnIndexOrThrow(Calendars.ACCOUNT_NAME); 117 mAccountTypeColumn = c.getColumnIndexOrThrow(Calendars.ACCOUNT_TYPE); 118 119 mRowCount = c.getCount(); 120 mData = new CalendarRow[mRowCount]; 121 c.moveToPosition(-1); 122 int p = 0; 123 while (c.moveToNext()) { 124 long id = c.getLong(mIdColumn); 125 mData[p] = new CalendarRow(); 126 mData[p].id = id; 127 mData[p].displayName = c.getString(mNameColumn); 128 mData[p].color = c.getInt(mColorColumn); 129 mData[p].originalSynced = c.getInt(mSyncedColumn) != 0; 130 mData[p].accountName = c.getString(mAccountNameColumn); 131 mData[p].accountType = c.getString(mAccountTypeColumn); 132 if (mChanges.containsKey(id)) { 133 mData[p].synced = mChanges.get(id).synced; 134 } else { 135 mData[p].synced = mData[p].originalSynced; 136 } 137 p++; 138 } 139 } 140 141 public void changeCursor(Cursor c) { 142 initData(c); 143 notifyDataSetChanged(); 144 } 145 146 @Override 147 public View getView(final int position, View convertView, ViewGroup parent) { 148 if (position >= mRowCount) { 149 return null; 150 } 151 String name = mData[position].displayName; 152 boolean selected = mData[position].synced; 153 int color = Utils.getDisplayColorFromColor(mData[position].color); 154 View view; 155 if (convertView == null) { 156 view = mInflater.inflate(LAYOUT, parent, false); 157 final View delegate = view.findViewById(R.id.color); 158 final View delegateParent = (View) delegate.getParent(); 159 delegateParent.post(new Runnable() { 160 161 @Override 162 public void run() { 163 final Rect r = new Rect(); 164 delegate.getHitRect(r); 165 r.top -= mColorViewTouchAreaIncrease; 166 r.bottom += mColorViewTouchAreaIncrease; 167 r.left -= mColorViewTouchAreaIncrease; 168 r.right += mColorViewTouchAreaIncrease; 169 delegateParent.setTouchDelegate(new TouchDelegate(r, delegate)); 170 } 171 }); 172 } else { 173 view = convertView; 174 } 175 176 view.setTag(mData[position]); 177 178 CheckBox cb = (CheckBox) view.findViewById(R.id.sync); 179 cb.setChecked(selected); 180 181 if (selected) { 182 setText(view, R.id.status, mSyncedString); 183 } else { 184 setText(view, R.id.status, mNotSyncedString); 185 } 186 187 View colorView = view.findViewById(R.id.color); 188 colorView.setEnabled(hasMoreColors(position)); 189 colorView.setBackgroundColor(color); 190 colorView.setOnClickListener(new OnClickListener() { 191 192 @Override 193 public void onClick(View v) { 194 // Purely for sanity check--view should be disabled if account has no more colors 195 if (!hasMoreColors(position)) { 196 return; 197 } 198 199 if (mColorPickerDialog == null) { 200 mColorPickerDialog = CalendarColorPickerDialog.newInstance(mData[position].id, 201 mIsTablet); 202 } else { 203 mColorPickerDialog.setCalendarId(mData[position].id); 204 } 205 mFragmentManager.executePendingTransactions(); 206 if (!mColorPickerDialog.isAdded()) { 207 mColorPickerDialog.show(mFragmentManager, COLOR_PICKER_DIALOG_TAG); 208 } 209 } 210 }); 211 212 setText(view, R.id.calendar, name); 213 return view; 214 } 215 216 private boolean hasMoreColors(int position) { 217 return mCache.hasColors(mData[position].accountName, mData[position].accountType); 218 } 219 220 private static void setText(View view, int id, String text) { 221 if (TextUtils.isEmpty(text)) { 222 return; 223 } 224 TextView textView = (TextView) view.findViewById(id); 225 textView.setText(text); 226 } 227 228 @Override 229 public int getCount() { 230 return mRowCount; 231 } 232 233 @Override 234 public Object getItem(int position) { 235 if (position >= mRowCount) { 236 return null; 237 } 238 CalendarRow item = mData[position]; 239 return item; 240 } 241 242 @Override 243 public long getItemId(int position) { 244 if (position >= mRowCount) { 245 return 0; 246 } 247 return mData[position].id; 248 } 249 250 @Override 251 public boolean hasStableIds() { 252 return true; 253 } 254 255 public int getSynced(int position) { 256 return mData[position].synced ? 1 : 0; 257 } 258 259 @Override 260 public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 261 CalendarRow row = (CalendarRow) view.getTag(); 262 row.synced = !row.synced; 263 264 String status; 265 if (row.synced) { 266 status = mSyncedString; 267 } else { 268 status = mNotSyncedString; 269 } 270 setText(view, R.id.status, status); 271 272 CheckBox cb = (CheckBox) view.findViewById(R.id.sync); 273 cb.setChecked(row.synced); 274 275 // There is some data loss in long -> int, but we should never see it in 276 // practice regarding calendar ids. 277 mChanges.put(row.id, row); 278 } 279 280 public HashMap<Long, CalendarRow> getChanges() { 281 return mChanges; 282 } 283 284 @Override 285 public void onCalendarColorsLoaded() { 286 notifyDataSetChanged(); 287 } 288 } 289