CalendarSyncTestingBase.java revision 090d33dc85fe791ff0a9876b19770428cd678e03
1/* 2 * Copyright (C) 2009 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.providers.calendar; 18 19import android.content.ContentResolver; 20import android.content.ContentUris; 21import android.content.ContentValues; 22import android.content.Context; 23import android.database.Cursor; 24import android.net.Uri; 25import android.text.format.DateUtils; 26import android.text.format.Time; 27import android.provider.Calendar; 28import android.test.SyncBaseInstrumentation; 29import android.util.Log; 30import com.google.android.collect.Maps; 31import com.google.android.googlelogin.GoogleLoginServiceBlockingHelper; 32import com.google.android.googlelogin.GoogleLoginServiceNotFoundException; 33 34import java.util.HashSet; 35import java.util.Map; 36import java.util.Set; 37 38public class CalendarSyncTestingBase extends SyncBaseInstrumentation { 39 protected Context mTargetContext; 40 protected String mAccount; 41 protected ContentResolver mResolver; 42 protected Uri mEventsUri = Uri.parse("content://calendar/events"); 43 44 static final String TAG = "calendar"; 45 static final String DEFAULT_TIMEZONE = "America/Los_Angeles"; 46 static final Set<String> EVENT_COLUMNS_TO_SKIP = new HashSet<String>(); 47 static final Set<String> ATTENDEES_COLUMNS_TO_SKIP = new HashSet<String>(); 48 static final Set<String> CALENDARS_COLUMNS_TO_SKIP = new HashSet<String>(); 49 static final Set<String> INSTANCES_COLUMNS_TO_SKIP = new HashSet<String>(); 50 51 static { 52 EVENT_COLUMNS_TO_SKIP.add(Calendar.Events._ID); 53 EVENT_COLUMNS_TO_SKIP.add(Calendar.Events._SYNC_TIME); 54 EVENT_COLUMNS_TO_SKIP.add(Calendar.Events._SYNC_VERSION); 55 EVENT_COLUMNS_TO_SKIP.add(Calendar.Events._SYNC_LOCAL_ID); 56 EVENT_COLUMNS_TO_SKIP.add(Calendar.Events._SYNC_DIRTY); 57 EVENT_COLUMNS_TO_SKIP.add(Calendar.Events._SYNC_MARK); 58 ATTENDEES_COLUMNS_TO_SKIP.add(Calendar.Attendees._ID); 59 CALENDARS_COLUMNS_TO_SKIP.add(Calendar.Calendars._ID); 60 CALENDARS_COLUMNS_TO_SKIP.add(Calendar.Calendars._SYNC_TIME); 61 CALENDARS_COLUMNS_TO_SKIP.add(Calendar.Calendars._SYNC_VERSION); 62 CALENDARS_COLUMNS_TO_SKIP.add(Calendar.Calendars._SYNC_LOCAL_ID); 63 CALENDARS_COLUMNS_TO_SKIP.add(Calendar.Calendars._SYNC_DIRTY); 64 CALENDARS_COLUMNS_TO_SKIP.add(Calendar.Calendars._SYNC_MARK); 65 INSTANCES_COLUMNS_TO_SKIP.add(Calendar.Instances._ID); 66 } 67 68 @Override 69 protected void setUp() throws Exception { 70 super.setUp(); 71 mTargetContext = getInstrumentation().getTargetContext(); 72 mAccount = getAccount(); 73 mResolver = mTargetContext.getContentResolver(); 74 } 75 76 /** 77 * A simple method that syncs the calendar provider. 78 * @throws Exception 79 */ 80 protected void syncCalendar() throws Exception { 81 cancelSyncsandDisableAutoSync(); 82 syncProvider(Calendar.CONTENT_URI, mAccount, Calendar.AUTHORITY); 83 } 84 85 /** 86 * Creates a new event in the default calendar. 87 * @param event Event to be created. 88 * @return Uri of the created event. 89 * @throws Exception 90 */ 91 protected Uri insertEvent(EventInfo event) throws Exception { 92 Log.v("FOO", "Get Default Calendar Id"); 93 return insertEvent(getDefaultCalendarId(), event); 94 } 95 96 /** 97 * Creates a new event in the given calendarId. 98 * @param calendarId Calendar to be used. 99 * @param event Event to be created. 100 * @return Uri of the event created. 101 * @throws Exception 102 */ 103 protected Uri insertEvent(int calendarId, EventInfo event) throws Exception{ 104 ContentValues m = new ContentValues(); 105 m.put(Calendar.Events.CALENDAR_ID, calendarId); 106 m.put(Calendar.Events.TITLE, event.mTitle); 107 m.put(Calendar.Events.DTSTART, event.mDtstart); 108 m.put(Calendar.Events.ALL_DAY, event.mAllDay ? 1 : 0); 109 110 if (event.mRrule == null) { 111 // This is a normal event 112 m.put(Calendar.Events.DTEND, event.mDtend); 113 } else { 114 // This is a repeating event 115 m.put(Calendar.Events.RRULE, event.mRrule); 116 m.put(Calendar.Events.DURATION, event.mDuration); 117 } 118 119 if (event.mDescription != null) { 120 m.put(Calendar.Events.DESCRIPTION, event.mDescription); 121 } 122 if (event.mTimezone != null) { 123 m.put(Calendar.Events.EVENT_TIMEZONE, event.mTimezone); 124 } 125 126 Log.v("FOO", "Test Calendar Event"); 127 Uri url = mResolver.insert(mEventsUri, m); 128 Log.v("FOO", "Insert Calendar Event"); 129 syncCalendar(); 130 Log.v("FOO", "Test Sync Calendar"); 131 return url; 132 } 133 134 /** 135 * Edits the given event. 136 * @param eventId EventID of the event to be edited. 137 * @param event Edited event details. 138 * @throws Exception 139 */ 140 protected void editEvent(long eventId, EventInfo event) throws Exception { 141 ContentValues values = new ContentValues(); 142 values.put(Calendar.Events.TITLE, event.mTitle); 143 values.put(Calendar.Events.DTSTART, event.mDtstart); 144 values.put(Calendar.Events.DTEND, event.mDtend); 145 values.put(Calendar.Events.ALL_DAY, event.mAllDay ? 1 : 0); 146 147 if (event.mDescription != null) { 148 values.put(Calendar.Events.DESCRIPTION, event.mDescription); 149 } 150 151 Uri uri = ContentUris.withAppendedId(Calendar.Events.CONTENT_URI, eventId); 152 mResolver.update(uri, values, null, null); 153 syncCalendar(); 154 } 155 156 /** 157 * Deletes a given event. 158 * @param uri 159 * @throws Exception 160 */ 161 protected void deleteEvent(Uri uri) throws Exception { 162 mResolver.delete(uri, null, null); 163 syncCalendar(); 164 } 165 166 /** 167 * Inserts a new calendar. 168 * @param name 169 * @param timezone 170 * @param calendarUrl 171 * @throws Exception 172 */ 173 protected void insertCalendar(String name, String timezone, String calendarUrl) 174 throws Exception { 175 ContentValues values = new ContentValues(); 176 177 values.put(Calendar.Calendars._SYNC_ACCOUNT, getAccount()); 178 values.put(Calendar.Calendars.URL, calendarUrl); 179 values.put(Calendar.Calendars.NAME, name); 180 values.put(Calendar.Calendars.DISPLAY_NAME, name); 181 values.put(Calendar.Calendars.SYNC_EVENTS, 1); 182 values.put(Calendar.Calendars.SELECTED, 1); 183 values.put(Calendar.Calendars.HIDDEN, 0); 184 values.put(Calendar.Calendars.COLOR, "0xff123456" /* blue */); 185 values.put(Calendar.Calendars.ACCESS_LEVEL, Calendar.Calendars.OWNER_ACCESS); 186 values.put(Calendar.Calendars.TIMEZONE, timezone); 187 mResolver.insert(Calendar.Calendars.CONTENT_URI, values); 188 syncCalendar(); 189 } 190 191 /** 192 * Returns a fresh count of events. 193 * @return 194 */ 195 protected int getEventsCount() { 196 Cursor cursor; 197 cursor = mResolver.query(mEventsUri, null, null, null, null); 198 return cursor.getCount(); 199 } 200 201 /** 202 * Returns the ID of the default calendar. 203 * @return 204 */ 205 protected int getDefaultCalendarId() { 206 Cursor calendarsCursor; 207 calendarsCursor = mResolver.query(Calendar.Calendars.CONTENT_URI, null, null, null, null); 208 calendarsCursor.moveToNext(); 209 return calendarsCursor.getInt(calendarsCursor.getColumnIndex("_id")); 210 } 211 212 /** 213 * This class stores all the useful information about an event. 214 */ 215 protected class EventInfo { 216 String mTitle; 217 String mDescription; 218 String mTimezone; 219 boolean mAllDay; 220 long mDtstart; 221 long mDtend; 222 String mRrule; 223 String mDuration; 224 String mOriginalTitle; 225 long mOriginalInstance; 226 int mSyncId; 227 228 // Constructor for normal events, using the default timezone 229 public EventInfo(String title, String startDate, String endDate, 230 boolean allDay) { 231 init(title, startDate, endDate, allDay, DEFAULT_TIMEZONE); 232 } 233 234 public EventInfo(String title, long startDate, long endDate, 235 boolean allDay) { 236 mTitle = title; 237 mTimezone = DEFAULT_TIMEZONE; 238 mDtstart = startDate; 239 mDtend = endDate; 240 mDuration = null; 241 mRrule = null; 242 mAllDay = allDay; 243 } 244 245 public EventInfo(String title, long startDate, long endDate, 246 boolean allDay, String description) { 247 mTitle = title; 248 mTimezone = DEFAULT_TIMEZONE; 249 mDtstart = startDate; 250 mDtend = endDate; 251 mDuration = null; 252 mRrule = null; 253 mAllDay = allDay; 254 mDescription = description; 255 } 256 257 // Constructor for normal events, specifying the timezone 258 public EventInfo(String title, String startDate, String endDate, 259 boolean allDay, String timezone) { 260 init(title, startDate, endDate, allDay, timezone); 261 } 262 263 public void init(String title, String startDate, String endDate, 264 boolean allDay, String timezone) { 265 mTitle = title; 266 Time time = new Time(); 267 if (allDay) { 268 time.timezone = Time.TIMEZONE_UTC; 269 } else if (timezone != null) { 270 time.timezone = timezone; 271 } 272 mTimezone = time.timezone; 273 time.parse3339(startDate); 274 mDtstart = time.toMillis(false /* use isDst */); 275 time.parse3339(endDate); 276 mDtend = time.toMillis(false /* use isDst */); 277 mDuration = null; 278 mRrule = null; 279 mAllDay = allDay; 280 } 281 282 /** 283 * Constructor for repeating events, using the default time zone. 284 * @param title 285 * @param description 286 * @param startDate 287 * @param endDate 288 * @param rrule 289 * @param allDay 290 */ 291 public EventInfo(String title, String description, String startDate, String endDate, 292 String rrule, boolean allDay) { 293 init(title, description, startDate, endDate, rrule, allDay, DEFAULT_TIMEZONE); 294 } 295 296 /** 297 * Constructor for repeating events, using the specific time zone. 298 * @param title 299 * @param description 300 * @param startDate 301 * @param endDate 302 * @param rrule 303 * @param allDay 304 * @param timezone 305 */ 306 public EventInfo(String title, String description, String startDate, String endDate, 307 String rrule, boolean allDay, String timezone) { 308 init(title, description, startDate, endDate, rrule, allDay, timezone); 309 } 310 311 public void init(String title, String description, String startDate, String endDate, 312 String rrule, boolean allDay, String timezone) { 313 mTitle = title; 314 mDescription = description; 315 Time time = new Time(); 316 if (allDay) { 317 time.timezone = Time.TIMEZONE_UTC; 318 } else if (timezone != null) { 319 time.timezone = timezone; 320 } 321 mTimezone = time.timezone; 322 time.parse3339(startDate); 323 mDtstart = time.toMillis(false /* use isDst */); 324 if (endDate != null) { 325 time.parse3339(endDate); 326 mDtend = time.toMillis(false /* use isDst */); 327 } 328 if (allDay) { 329 long days = 1; 330 if (endDate != null) { 331 days = (mDtend - mDtstart) / DateUtils.DAY_IN_MILLIS; 332 } 333 mDuration = "P" + days + "D"; 334 } else { 335 long seconds = (mDtend - mDtstart) / DateUtils.SECOND_IN_MILLIS; 336 mDuration = "P" + seconds + "S"; 337 } 338 mRrule = rrule; 339 mAllDay = allDay; 340 } 341 342 // Constructor for recurrence exceptions, using the default timezone 343 public EventInfo(String originalTitle, String originalInstance, String title, 344 String description, String startDate, String endDate, boolean allDay) { 345 init(originalTitle, originalInstance, 346 title, description, startDate, endDate, allDay, DEFAULT_TIMEZONE); 347 } 348 349 public void init(String originalTitle, String originalInstance, 350 String title, String description, String startDate, String endDate, 351 boolean allDay, String timezone) { 352 mOriginalTitle = originalTitle; 353 Time time = new Time(timezone); 354 time.parse3339(originalInstance); 355 mOriginalInstance = time.toMillis(false /* use isDst */); 356 init(title, description, startDate, endDate, null /* rrule */, allDay, timezone); 357 } 358 } 359 360 /** 361 * Returns the default account on the device. 362 * @return 363 */ 364 protected String getAccount() { 365 try { 366 return GoogleLoginServiceBlockingHelper.getAccount(mTargetContext, false); 367 } catch (GoogleLoginServiceNotFoundException e) { 368 Log.e("SyncCalendarTest", "Could not find Google login service", e); 369 return null; 370 } 371 } 372 373 /** 374 * Compares two cursors 375 */ 376 protected void compareCursors(Cursor cursor1, Cursor cursor2, 377 Set<String> columnsToSkip, String tableName) { 378 String[] cols = cursor1.getColumnNames(); 379 int length = cols.length; 380 381 assertEquals(tableName + " count failed to match", cursor1.getCount(), 382 cursor2.getCount()); 383 Map<String, String> row = Maps.newHashMap(); 384 while (cursor1.moveToNext() && cursor2.moveToNext()) { 385 for (int i = 0; i < length; i++) { 386 String col = cols[i]; 387 if (columnsToSkip != null && columnsToSkip.contains(col)) { 388 continue; 389 } 390 row.put(col, cursor1.getString(i)); 391 392 assertEquals("Row: " + row + " Table: " + tableName + ": " + cols[i] + 393 " failed to match", cursor1.getString(i), 394 cursor2.getString(i)); 395 } 396 } 397 } 398} 399