19f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff/*
29f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff * Copyright (C) 2009 The Android Open Source Project
39f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff *
49f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff * Licensed under the Apache License, Version 2.0 (the "License");
59f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff * you may not use this file except in compliance with the License.
69f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff * You may obtain a copy of the License at
79f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff *
89f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff *      http://www.apache.org/licenses/LICENSE-2.0
99f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff *
109f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff * Unless required by applicable law or agreed to in writing, software
119f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff * distributed under the License is distributed on an "AS IS" BASIS,
129f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff * See the License for the specific language governing permissions and
149f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff * limitations under the License
159f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff */
169f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
179f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriffpackage com.android.providers.calendar;
189f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
199f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriffimport android.accounts.Account;
209f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriffimport android.content.ContentResolver;
219f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriffimport android.content.ContentValues;
229f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriffimport android.content.Context;
239f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriffimport android.database.Cursor;
249f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriffimport android.database.DatabaseUtils;
259f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriffimport android.database.sqlite.SQLiteDatabase;
26a6357118c223d00ed722ecd40ecdda92d705d211Erikimport android.database.sqlite.SQLiteException;
279f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriffimport android.database.sqlite.SQLiteOpenHelper;
289f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriffimport android.os.Bundle;
29b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErikimport android.provider.CalendarContract;
30b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErikimport android.provider.CalendarContract.Attendees;
312f251c778c06d21ed7693a70f4a1268ff929242eRoboErikimport android.provider.CalendarContract.Calendars;
322f251c778c06d21ed7693a70f4a1268ff929242eRoboErikimport android.provider.CalendarContract.Colors;
33b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErikimport android.provider.CalendarContract.Events;
34b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErikimport android.provider.CalendarContract.Reminders;
35d5aa3cc17ecda3d72882d9a2e6c48577892df903Ken Shirriffimport android.provider.SyncStateContract;
367b40dde3168f4af2c757cb43955aa3bfe1668666Erikimport android.text.TextUtils;
37ae4f20e120d3107cef20be860a612c9c23816295Erikimport android.text.format.Time;
389f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriffimport android.util.Log;
39470aa5bc291ca33d51dda356f38ac2954026da9aAlon Albertimport com.android.common.content.SyncStateContentProviderHelper;
40470aa5bc291ca33d51dda356f38ac2954026da9aAlon Albertimport com.google.common.annotations.VisibleForTesting;
419f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
42d39cfe09aa7e752cdc7512ae58d90d49d4b5ef9eKen Shirriffimport java.io.UnsupportedEncodingException;
43162c7c9bbd53b623fbe913b376e7f7f42915bb59Marc Blankimport java.net.URLDecoder;
44315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglioimport java.util.TimeZone;
45d39cfe09aa7e752cdc7512ae58d90d49d4b5ef9eKen Shirriff
469f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff/**
479f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff * Database helper for calendar. Designed as a singleton to make sure that all
489f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff * {@link android.content.ContentProvider} users get the same reference.
499f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff */
509f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff/* package */ class CalendarDatabaseHelper extends SQLiteOpenHelper {
5181d904d66bd746c077cc0baa6cf1f51fe030eac4Mason Tang
529f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    private static final String TAG = "CalendarDatabaseHelper";
539f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
5481d904d66bd746c077cc0baa6cf1f51fe030eac4Mason Tang    private static final boolean LOGD = false;
5581d904d66bd746c077cc0baa6cf1f51fe030eac4Mason Tang
56ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff    private static final String DATABASE_NAME = "calendar.db";
579f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
587b40dde3168f4af2c757cb43955aa3bfe1668666Erik    private static final int DAY_IN_SECONDS = 24 * 60 * 60;
597b40dde3168f4af2c757cb43955aa3bfe1668666Erik
609f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    // Note: if you update the version number, you must also update the code
619f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    // in upgradeDatabase() to modify the database (gracefully, if possible).
62c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik    // Versions under 100 cover through Froyo, 1xx version are for Gingerbread,
63c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik    // 2xx for Honeycomb, and 3xx for ICS. For future versions bump this to the
64c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik    // next hundred at each major release.
652f251c778c06d21ed7693a70f4a1268ff929242eRoboErik    static final int DATABASE_VERSION = 308;
669f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
67d5aa3cc17ecda3d72882d9a2e6c48577892df903Ken Shirriff    private static final int PRE_FROYO_SYNC_STATE_VERSION = 3;
68d5aa3cc17ecda3d72882d9a2e6c48577892df903Ken Shirriff
699ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert    // columns used to duplicate an event row
7002f97c538fc46a08d857d2c807c76fd0eec12493RoboErik    private static final String LAST_SYNCED_EVENT_COLUMNS =
7102f97c538fc46a08d857d2c807c76fd0eec12493RoboErik            Events._SYNC_ID + "," +
7202f97c538fc46a08d857d2c807c76fd0eec12493RoboErik            Events.CALENDAR_ID + "," +
7302f97c538fc46a08d857d2c807c76fd0eec12493RoboErik            Events.TITLE + "," +
7402f97c538fc46a08d857d2c807c76fd0eec12493RoboErik            Events.EVENT_LOCATION + "," +
7502f97c538fc46a08d857d2c807c76fd0eec12493RoboErik            Events.DESCRIPTION + "," +
7602f97c538fc46a08d857d2c807c76fd0eec12493RoboErik            Events.EVENT_COLOR + "," +
77387535fec9f646e0b7acb82d5354f2b5ebee4395RoboErik            Events.EVENT_COLOR_KEY + "," +
7802f97c538fc46a08d857d2c807c76fd0eec12493RoboErik            Events.STATUS + "," +
7902f97c538fc46a08d857d2c807c76fd0eec12493RoboErik            Events.SELF_ATTENDEE_STATUS + "," +
8002f97c538fc46a08d857d2c807c76fd0eec12493RoboErik            Events.DTSTART + "," +
8102f97c538fc46a08d857d2c807c76fd0eec12493RoboErik            Events.DTEND + "," +
8202f97c538fc46a08d857d2c807c76fd0eec12493RoboErik            Events.EVENT_TIMEZONE + "," +
8302f97c538fc46a08d857d2c807c76fd0eec12493RoboErik            Events.EVENT_END_TIMEZONE + "," +
8402f97c538fc46a08d857d2c807c76fd0eec12493RoboErik            Events.DURATION + "," +
8502f97c538fc46a08d857d2c807c76fd0eec12493RoboErik            Events.ALL_DAY + "," +
8602f97c538fc46a08d857d2c807c76fd0eec12493RoboErik            Events.ACCESS_LEVEL + "," +
8702f97c538fc46a08d857d2c807c76fd0eec12493RoboErik            Events.AVAILABILITY + "," +
8802f97c538fc46a08d857d2c807c76fd0eec12493RoboErik            Events.HAS_ALARM + "," +
8902f97c538fc46a08d857d2c807c76fd0eec12493RoboErik            Events.HAS_EXTENDED_PROPERTIES + "," +
9002f97c538fc46a08d857d2c807c76fd0eec12493RoboErik            Events.RRULE + "," +
9102f97c538fc46a08d857d2c807c76fd0eec12493RoboErik            Events.RDATE + "," +
9202f97c538fc46a08d857d2c807c76fd0eec12493RoboErik            Events.EXRULE + "," +
9302f97c538fc46a08d857d2c807c76fd0eec12493RoboErik            Events.EXDATE + "," +
9402f97c538fc46a08d857d2c807c76fd0eec12493RoboErik            Events.ORIGINAL_SYNC_ID + "," +
9502f97c538fc46a08d857d2c807c76fd0eec12493RoboErik            Events.ORIGINAL_ID + "," +
9602f97c538fc46a08d857d2c807c76fd0eec12493RoboErik            Events.ORIGINAL_INSTANCE_TIME + "," +
9702f97c538fc46a08d857d2c807c76fd0eec12493RoboErik            Events.ORIGINAL_ALL_DAY + "," +
9802f97c538fc46a08d857d2c807c76fd0eec12493RoboErik            Events.LAST_DATE + "," +
9902f97c538fc46a08d857d2c807c76fd0eec12493RoboErik            Events.HAS_ATTENDEE_DATA + "," +
10002f97c538fc46a08d857d2c807c76fd0eec12493RoboErik            Events.GUESTS_CAN_MODIFY + "," +
10102f97c538fc46a08d857d2c807c76fd0eec12493RoboErik            Events.GUESTS_CAN_INVITE_OTHERS + "," +
10202f97c538fc46a08d857d2c807c76fd0eec12493RoboErik            Events.GUESTS_CAN_SEE_GUESTS + "," +
10302f97c538fc46a08d857d2c807c76fd0eec12493RoboErik            Events.ORGANIZER;
1049ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert
1059ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert    // columns used to duplicate a reminder row
10602f97c538fc46a08d857d2c807c76fd0eec12493RoboErik    private static final String LAST_SYNCED_REMINDER_COLUMNS =
107470aa5bc291ca33d51dda356f38ac2954026da9aAlon Albert            Reminders.MINUTES + "," +
108470aa5bc291ca33d51dda356f38ac2954026da9aAlon Albert            Reminders.METHOD;
1099ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert
1109ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert    // columns used to duplicate an attendee row
11102f97c538fc46a08d857d2c807c76fd0eec12493RoboErik    private static final String LAST_SYNCED_ATTENDEE_COLUMNS =
112470aa5bc291ca33d51dda356f38ac2954026da9aAlon Albert            Attendees.ATTENDEE_NAME + "," +
113470aa5bc291ca33d51dda356f38ac2954026da9aAlon Albert            Attendees.ATTENDEE_EMAIL + "," +
114470aa5bc291ca33d51dda356f38ac2954026da9aAlon Albert            Attendees.ATTENDEE_STATUS + "," +
115470aa5bc291ca33d51dda356f38ac2954026da9aAlon Albert            Attendees.ATTENDEE_RELATIONSHIP + "," +
116470aa5bc291ca33d51dda356f38ac2954026da9aAlon Albert            Attendees.ATTENDEE_TYPE;
1179ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert
1189ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert    // columns used to duplicate an extended property row
11902f97c538fc46a08d857d2c807c76fd0eec12493RoboErik    private static final String LAST_SYNCED_EXTENDED_PROPERTY_COLUMNS =
120b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik            CalendarContract.ExtendedProperties.NAME + "," +
121b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik            CalendarContract.ExtendedProperties.VALUE;
1229ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert
1237cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio    public interface Tables {
1247cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        public static final String CALENDARS = "Calendars";
1257cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        public static final String EVENTS = "Events";
1267cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        public static final String EVENTS_RAW_TIMES = "EventsRawTimes";
1277cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        public static final String INSTANCES = "Instances";
1287cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        public static final String ATTENDEES = "Attendees";
1297cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        public static final String REMINDERS = "Reminders";
1307cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        public static final String CALENDAR_ALERTS = "CalendarAlerts";
1317cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        public static final String EXTENDED_PROPERTIES = "ExtendedProperties";
1327cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        public static final String CALENDAR_META_DATA = "CalendarMetaData";
1337cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        public static final String CALENDAR_CACHE = "CalendarCache";
1347cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        public static final String SYNC_STATE = "_sync_state";
1357cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        public static final String SYNC_STATE_META = "_sync_state_metadata";
1362f251c778c06d21ed7693a70f4a1268ff929242eRoboErik        public static final String COLORS = "Colors";
1377cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio    }
1387cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio
1397cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio    public interface Views {
140bcba82631ab0ee16efe58f0e0b0b9c18d93a6fd2Andy McFadden        public static final String EVENTS = "view_events";
1417cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio    }
1427cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio
143d5aa3cc17ecda3d72882d9a2e6c48577892df903Ken Shirriff    // Copied from SyncStateContentProviderHelper.  Don't really want to make them public there.
144d5aa3cc17ecda3d72882d9a2e6c48577892df903Ken Shirriff    private static final String SYNC_STATE_META_VERSION_COLUMN = "version";
145d5aa3cc17ecda3d72882d9a2e6c48577892df903Ken Shirriff
1467cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio    // This needs to be done when all the tables are already created
1477cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio    private static final String EVENTS_CLEANUP_TRIGGER_SQL =
1487cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio            "DELETE FROM " + Tables.INSTANCES +
149b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                " WHERE "+ CalendarContract.Instances.EVENT_ID + "=" +
150b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                    "old." + CalendarContract.Events._ID + ";" +
1517cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio            "DELETE FROM " + Tables.EVENTS_RAW_TIMES +
152b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                " WHERE " + CalendarContract.EventsRawTimes.EVENT_ID + "=" +
153b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                    "old." + CalendarContract.Events._ID + ";" +
1547cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio            "DELETE FROM " + Tables.ATTENDEES +
155b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                " WHERE " + CalendarContract.Attendees.EVENT_ID + "=" +
156b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                    "old." + CalendarContract.Events._ID + ";" +
1577cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio            "DELETE FROM " + Tables.REMINDERS +
158b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                " WHERE " + CalendarContract.Reminders.EVENT_ID + "=" +
159b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                    "old." + CalendarContract.Events._ID + ";" +
1607cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio            "DELETE FROM " + Tables.CALENDAR_ALERTS +
161b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                " WHERE " + CalendarContract.CalendarAlerts.EVENT_ID + "=" +
162b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                    "old." + CalendarContract.Events._ID + ";" +
1637cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio            "DELETE FROM " + Tables.EXTENDED_PROPERTIES +
164b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                " WHERE " + CalendarContract.ExtendedProperties.EVENT_ID + "=" +
165b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                    "old." + CalendarContract.Events._ID + ";";
1667cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio
16734c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik    // This ensures any exceptions based on an event get their original_sync_id
16834c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik    // column set when an the _sync_id is set.
16934c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik    private static final String EVENTS_ORIGINAL_SYNC_TRIGGER_SQL =
17034c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik            "UPDATE " + Tables.EVENTS +
17134c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik                " SET " + Events.ORIGINAL_SYNC_ID + "=new." + Events._SYNC_ID +
17234c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik                " WHERE " + Events.ORIGINAL_ID + "=old." + Events._ID + ";";
17334c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik
17434c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik    private static final String SYNC_ID_UPDATE_TRIGGER_NAME = "original_sync_update";
17534c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik    private static final String CREATE_SYNC_ID_UPDATE_TRIGGER =
17634c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik            "CREATE TRIGGER " + SYNC_ID_UPDATE_TRIGGER_NAME + " UPDATE OF " + Events._SYNC_ID +
17734c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik            " ON " + Tables.EVENTS +
17834c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik            " BEGIN " +
17934c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik                EVENTS_ORIGINAL_SYNC_TRIGGER_SQL +
18034c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik            " END";
18134c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik
1827cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio    private static final String CALENDAR_CLEANUP_TRIGGER_SQL = "DELETE FROM " + Tables.EVENTS +
183b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik            " WHERE " + CalendarContract.Events.CALENDAR_ID + "=" +
184b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                "old." + CalendarContract.Events._ID + ";";
1857cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio
1862f251c778c06d21ed7693a70f4a1268ff929242eRoboErik    private static final String CALENDAR_UPDATE_COLOR_TRIGGER_SQL = "UPDATE " + Tables.CALENDARS
1872f251c778c06d21ed7693a70f4a1268ff929242eRoboErik            + " SET calendar_color=(SELECT " + Colors.COLOR + " FROM " + Tables.COLORS + " WHERE "
1882f251c778c06d21ed7693a70f4a1268ff929242eRoboErik            + Colors.ACCOUNT_NAME + "=" + "new." + Calendars.ACCOUNT_NAME + " AND "
1892f251c778c06d21ed7693a70f4a1268ff929242eRoboErik            + Colors.ACCOUNT_TYPE + "=" + "new." + Calendars.ACCOUNT_TYPE + " AND "
190387535fec9f646e0b7acb82d5354f2b5ebee4395RoboErik            + Colors.COLOR_KEY + "=" + "new." + Calendars.CALENDAR_COLOR_KEY + ") "
1912f251c778c06d21ed7693a70f4a1268ff929242eRoboErik            + " WHERE " + Calendars._ID + "=" + "old." + Calendars._ID
1922f251c778c06d21ed7693a70f4a1268ff929242eRoboErik            + ";";
1932f251c778c06d21ed7693a70f4a1268ff929242eRoboErik    private static final String CALENDAR_COLOR_UPDATE_TRIGGER_NAME = "calendar_color_update";
1942f251c778c06d21ed7693a70f4a1268ff929242eRoboErik    private static final String CREATE_CALENDAR_COLOR_UPDATE_TRIGGER = "CREATE TRIGGER "
195387535fec9f646e0b7acb82d5354f2b5ebee4395RoboErik            + CALENDAR_COLOR_UPDATE_TRIGGER_NAME + " UPDATE OF " + Calendars.CALENDAR_COLOR_KEY
196387535fec9f646e0b7acb82d5354f2b5ebee4395RoboErik            + " ON " + Tables.CALENDARS + " WHEN new." + Calendars.CALENDAR_COLOR_KEY
1972f251c778c06d21ed7693a70f4a1268ff929242eRoboErik            + " NOT NULL BEGIN " + CALENDAR_UPDATE_COLOR_TRIGGER_SQL + " END";
1982f251c778c06d21ed7693a70f4a1268ff929242eRoboErik
1992f251c778c06d21ed7693a70f4a1268ff929242eRoboErik    private static final String EVENT_UPDATE_COLOR_TRIGGER_SQL = "UPDATE " + Tables.EVENTS
2002f251c778c06d21ed7693a70f4a1268ff929242eRoboErik            + " SET eventColor=(SELECT " + Colors.COLOR + " FROM " + Tables.COLORS + " WHERE "
2012f251c778c06d21ed7693a70f4a1268ff929242eRoboErik            + Colors.ACCOUNT_NAME + "=" + "(SELECT " + Calendars.ACCOUNT_NAME + " FROM "
2022f251c778c06d21ed7693a70f4a1268ff929242eRoboErik            + Tables.CALENDARS + " WHERE " + Calendars._ID + "=new." + Events.CALENDAR_ID
2032f251c778c06d21ed7693a70f4a1268ff929242eRoboErik            + ") AND " + Colors.ACCOUNT_TYPE + "=" + "(SELECT " + Calendars.ACCOUNT_TYPE + " FROM "
2042f251c778c06d21ed7693a70f4a1268ff929242eRoboErik            + Tables.CALENDARS + " WHERE " + Calendars._ID + "=new." + Events.CALENDAR_ID
205387535fec9f646e0b7acb82d5354f2b5ebee4395RoboErik            + ") AND " + Colors.COLOR_KEY + "=" + "new." + Events.EVENT_COLOR_KEY + ") "
2062f251c778c06d21ed7693a70f4a1268ff929242eRoboErik            + " WHERE " + Events._ID + "=" + "old." + Events._ID + ";";
2072f251c778c06d21ed7693a70f4a1268ff929242eRoboErik    private static final String EVENT_COLOR_UPDATE_TRIGGER_NAME = "event_color_update";
2082f251c778c06d21ed7693a70f4a1268ff929242eRoboErik    private static final String CREATE_EVENT_COLOR_UPDATE_TRIGGER = "CREATE TRIGGER "
209387535fec9f646e0b7acb82d5354f2b5ebee4395RoboErik            + EVENT_COLOR_UPDATE_TRIGGER_NAME + " UPDATE OF " + Events.EVENT_COLOR_KEY + " ON "
210387535fec9f646e0b7acb82d5354f2b5ebee4395RoboErik            + Tables.EVENTS + " WHEN new." + Events.EVENT_COLOR_KEY + " NOT NULL BEGIN "
2112f251c778c06d21ed7693a70f4a1268ff929242eRoboErik            + EVENT_UPDATE_COLOR_TRIGGER_SQL + " END";
2122f251c778c06d21ed7693a70f4a1268ff929242eRoboErik
213935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden    /** Selects rows from Attendees for which the event_id refers to a nonexistent Event */
214935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden    private static final String WHERE_ATTENDEES_ORPHANS =
215935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            Attendees.EVENT_ID + " IN (SELECT " + Attendees.EVENT_ID + " FROM " +
216935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            Tables.ATTENDEES + " LEFT OUTER JOIN " + Tables.EVENTS + " ON " +
217935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            Attendees.EVENT_ID + "=" + Tables.EVENTS + "." + Events._ID +
218935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            " WHERE " + Tables.EVENTS + "." + Events._ID + " IS NULL)";
219935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden    /** Selects rows from Reminders for which the event_id refers to a nonexistent Event */
220935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden    private static final String WHERE_REMINDERS_ORPHANS =
221935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            Reminders.EVENT_ID + " IN (SELECT " + Reminders.EVENT_ID + " FROM " +
222935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            Tables.REMINDERS + " LEFT OUTER JOIN " + Tables.EVENTS + " ON " +
223935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            Reminders.EVENT_ID + "=" + Tables.EVENTS + "." + Events._ID +
224935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            " WHERE " + Tables.EVENTS + "." + Events._ID + " IS NULL)";
225935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden
2261b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio    private static final String SCHEMA_HTTPS = "https://";
2271b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio    private static final String SCHEMA_HTTP = "http://";
2281b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio
2299f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    private final SyncStateContentProviderHelper mSyncState;
2309f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
2319f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    private static CalendarDatabaseHelper sSingleton = null;
2329f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
2339f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    private DatabaseUtils.InsertHelper mCalendarsInserter;
2342f251c778c06d21ed7693a70f4a1268ff929242eRoboErik    private DatabaseUtils.InsertHelper mColorsInserter;
2359f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    private DatabaseUtils.InsertHelper mEventsInserter;
2369f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    private DatabaseUtils.InsertHelper mEventsRawTimesInserter;
2379f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    private DatabaseUtils.InsertHelper mInstancesInserter;
2389f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    private DatabaseUtils.InsertHelper mAttendeesInserter;
2399f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    private DatabaseUtils.InsertHelper mRemindersInserter;
2409f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    private DatabaseUtils.InsertHelper mCalendarAlertsInserter;
2419f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    private DatabaseUtils.InsertHelper mExtendedPropertiesInserter;
2429f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
2439f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    public long calendarsInsert(ContentValues values) {
2449f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff        return mCalendarsInserter.insert(values);
2459f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    }
2469f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
2472f251c778c06d21ed7693a70f4a1268ff929242eRoboErik    public long colorsInsert(ContentValues values) {
2482f251c778c06d21ed7693a70f4a1268ff929242eRoboErik        return mColorsInserter.insert(values);
2492f251c778c06d21ed7693a70f4a1268ff929242eRoboErik    }
2502f251c778c06d21ed7693a70f4a1268ff929242eRoboErik
2519f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    public long eventsInsert(ContentValues values) {
2529f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff        return mEventsInserter.insert(values);
2539f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    }
2549f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
2559f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    public long eventsRawTimesInsert(ContentValues values) {
2569f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff        return mEventsRawTimesInserter.insert(values);
2579f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    }
2589f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
2599f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    public long eventsRawTimesReplace(ContentValues values) {
2609f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff        return mEventsRawTimesInserter.replace(values);
2619f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    }
2629f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
2639f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    public long instancesInsert(ContentValues values) {
2649f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff        return mInstancesInserter.insert(values);
2659f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    }
2669f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
267c874ed5c6cc0fcc6ac06ae7d20db0eab7d749608Ken Shirriff    public long instancesReplace(ContentValues values) {
268c874ed5c6cc0fcc6ac06ae7d20db0eab7d749608Ken Shirriff        return mInstancesInserter.replace(values);
269c874ed5c6cc0fcc6ac06ae7d20db0eab7d749608Ken Shirriff    }
270c874ed5c6cc0fcc6ac06ae7d20db0eab7d749608Ken Shirriff
2719f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    public long attendeesInsert(ContentValues values) {
2729f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff        return mAttendeesInserter.insert(values);
2739f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    }
2749f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
2759f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    public long remindersInsert(ContentValues values) {
2769f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff        return mRemindersInserter.insert(values);
2779f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    }
2789f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
2799f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    public long calendarAlertsInsert(ContentValues values) {
2809f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff        return mCalendarAlertsInserter.insert(values);
2819f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    }
2829f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
2839f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    public long extendedPropertiesInsert(ContentValues values) {
2849f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff        return mExtendedPropertiesInserter.insert(values);
2859f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    }
2869f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
2879f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    public static synchronized CalendarDatabaseHelper getInstance(Context context) {
2889f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff        if (sSingleton == null) {
2899f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff            sSingleton = new CalendarDatabaseHelper(context);
2909f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff        }
2919f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff        return sSingleton;
2929f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    }
2939f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
2949f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    /**
2959f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff     * Private constructor, callers except unit tests should obtain an instance through
2969f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff     * {@link #getInstance(android.content.Context)} instead.
2979f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff     */
2987e3ec5f2025164fca508f81a5a01940bc912e064Ken Shirriff    /* package */ CalendarDatabaseHelper(Context context) {
2999f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff        super(context, DATABASE_NAME, null, DATABASE_VERSION);
30081d904d66bd746c077cc0baa6cf1f51fe030eac4Mason Tang        if (LOGD) Log.d(TAG, "Creating OpenHelper");
3019f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
3029f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff        mSyncState = new SyncStateContentProviderHelper();
3039f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    }
3049f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
3059f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    @Override
3069f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    public void onOpen(SQLiteDatabase db) {
3079f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff        mSyncState.onDatabaseOpened(db);
3089f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
3097cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        mCalendarsInserter = new DatabaseUtils.InsertHelper(db, Tables.CALENDARS);
3102f251c778c06d21ed7693a70f4a1268ff929242eRoboErik        mColorsInserter = new DatabaseUtils.InsertHelper(db, Tables.COLORS);
3117cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        mEventsInserter = new DatabaseUtils.InsertHelper(db, Tables.EVENTS);
3127cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        mEventsRawTimesInserter = new DatabaseUtils.InsertHelper(db, Tables.EVENTS_RAW_TIMES);
3137cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        mInstancesInserter = new DatabaseUtils.InsertHelper(db, Tables.INSTANCES);
3147cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        mAttendeesInserter = new DatabaseUtils.InsertHelper(db, Tables.ATTENDEES);
3157cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        mRemindersInserter = new DatabaseUtils.InsertHelper(db, Tables.REMINDERS);
3167cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        mCalendarAlertsInserter = new DatabaseUtils.InsertHelper(db, Tables.CALENDAR_ALERTS);
3179f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff        mExtendedPropertiesInserter =
3187cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio                new DatabaseUtils.InsertHelper(db, Tables.EXTENDED_PROPERTIES);
3199f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    }
3209f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
321d5aa3cc17ecda3d72882d9a2e6c48577892df903Ken Shirriff    /*
322d5aa3cc17ecda3d72882d9a2e6c48577892df903Ken Shirriff     * Upgrade sync state table if necessary.  Note that the data bundle
323d5aa3cc17ecda3d72882d9a2e6c48577892df903Ken Shirriff     * in the table is not upgraded.
324d5aa3cc17ecda3d72882d9a2e6c48577892df903Ken Shirriff     *
325d5aa3cc17ecda3d72882d9a2e6c48577892df903Ken Shirriff     * The sync state used to be stored with version 3, but now uses the
326d5aa3cc17ecda3d72882d9a2e6c48577892df903Ken Shirriff     * same sync state code as contacts, which is version 1.  This code
327d5aa3cc17ecda3d72882d9a2e6c48577892df903Ken Shirriff     * upgrades from 3 to 1 if necessary.  (Yes, the numbers are unfortunately
328d5aa3cc17ecda3d72882d9a2e6c48577892df903Ken Shirriff     * backwards.)
329d5aa3cc17ecda3d72882d9a2e6c48577892df903Ken Shirriff     *
330d5aa3cc17ecda3d72882d9a2e6c48577892df903Ken Shirriff     * This code is only called when upgrading from an old calendar version,
331d5aa3cc17ecda3d72882d9a2e6c48577892df903Ken Shirriff     * so there is no problem if sync state version 3 gets used again in the
332d5aa3cc17ecda3d72882d9a2e6c48577892df903Ken Shirriff     * future.
333d5aa3cc17ecda3d72882d9a2e6c48577892df903Ken Shirriff     */
334d5aa3cc17ecda3d72882d9a2e6c48577892df903Ken Shirriff    private void upgradeSyncState(SQLiteDatabase db) {
335d5aa3cc17ecda3d72882d9a2e6c48577892df903Ken Shirriff        long version = DatabaseUtils.longForQuery(db,
336d5aa3cc17ecda3d72882d9a2e6c48577892df903Ken Shirriff                 "SELECT " + SYNC_STATE_META_VERSION_COLUMN
3377cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio                 + " FROM " + Tables.SYNC_STATE_META,
338d5aa3cc17ecda3d72882d9a2e6c48577892df903Ken Shirriff                 null);
339d5aa3cc17ecda3d72882d9a2e6c48577892df903Ken Shirriff        if (version == PRE_FROYO_SYNC_STATE_VERSION) {
340d5aa3cc17ecda3d72882d9a2e6c48577892df903Ken Shirriff            Log.i(TAG, "Upgrading calendar sync state table");
341d5aa3cc17ecda3d72882d9a2e6c48577892df903Ken Shirriff            db.execSQL("CREATE TEMPORARY TABLE state_backup(_sync_account TEXT, "
342d5aa3cc17ecda3d72882d9a2e6c48577892df903Ken Shirriff                    + "_sync_account_type TEXT, data TEXT);");
343d5aa3cc17ecda3d72882d9a2e6c48577892df903Ken Shirriff            db.execSQL("INSERT INTO state_backup SELECT _sync_account, _sync_account_type, data"
344d5aa3cc17ecda3d72882d9a2e6c48577892df903Ken Shirriff                    + " FROM "
3457cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio                    + Tables.SYNC_STATE
346d5aa3cc17ecda3d72882d9a2e6c48577892df903Ken Shirriff                    + " WHERE _sync_account is not NULL and _sync_account_type is not NULL;");
3477cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio            db.execSQL("DROP TABLE " + Tables.SYNC_STATE + ";");
348d5aa3cc17ecda3d72882d9a2e6c48577892df903Ken Shirriff            mSyncState.onDatabaseOpened(db);
3497cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio            db.execSQL("INSERT INTO " + Tables.SYNC_STATE + "("
350d5aa3cc17ecda3d72882d9a2e6c48577892df903Ken Shirriff                    + SyncStateContract.Columns.ACCOUNT_NAME + ","
351d5aa3cc17ecda3d72882d9a2e6c48577892df903Ken Shirriff                    + SyncStateContract.Columns.ACCOUNT_TYPE + ","
352d5aa3cc17ecda3d72882d9a2e6c48577892df903Ken Shirriff                    + SyncStateContract.Columns.DATA
353d5aa3cc17ecda3d72882d9a2e6c48577892df903Ken Shirriff                    + ") SELECT _sync_account, _sync_account_type, data from state_backup;");
354d5aa3cc17ecda3d72882d9a2e6c48577892df903Ken Shirriff            db.execSQL("DROP TABLE state_backup;");
355d5aa3cc17ecda3d72882d9a2e6c48577892df903Ken Shirriff        } else {
356d5aa3cc17ecda3d72882d9a2e6c48577892df903Ken Shirriff            // Wrong version to upgrade.
357d5aa3cc17ecda3d72882d9a2e6c48577892df903Ken Shirriff            // Don't need to do anything more here because mSyncState.onDatabaseOpened() will blow
358d5aa3cc17ecda3d72882d9a2e6c48577892df903Ken Shirriff            // away and recreate  the database (which will result in a resync).
359d5aa3cc17ecda3d72882d9a2e6c48577892df903Ken Shirriff            Log.w(TAG, "upgradeSyncState: current version is " + version + ", skipping upgrade.");
360d5aa3cc17ecda3d72882d9a2e6c48577892df903Ken Shirriff        }
361d5aa3cc17ecda3d72882d9a2e6c48577892df903Ken Shirriff    }
362d5aa3cc17ecda3d72882d9a2e6c48577892df903Ken Shirriff
3639f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    @Override
3649f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    public void onCreate(SQLiteDatabase db) {
365a6357118c223d00ed722ecd40ecdda92d705d211Erik        bootstrapDB(db);
366a6357118c223d00ed722ecd40ecdda92d705d211Erik    }
367a6357118c223d00ed722ecd40ecdda92d705d211Erik
368a6357118c223d00ed722ecd40ecdda92d705d211Erik    private void bootstrapDB(SQLiteDatabase db) {
3699f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff        Log.i(TAG, "Bootstrapping database");
3709f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
3719f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff        mSyncState.createDatabase(db);
3729f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
3732f251c778c06d21ed7693a70f4a1268ff929242eRoboErik        createColorsTable(db);
3742f251c778c06d21ed7693a70f4a1268ff929242eRoboErik
3751b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio        createCalendarsTable(db);
3769f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
377c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik        createEventsTable(db);
3789f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
3797cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        db.execSQL("CREATE TABLE " + Tables.EVENTS_RAW_TIMES + " (" +
380b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.EventsRawTimes._ID + " INTEGER PRIMARY KEY," +
381b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.EventsRawTimes.EVENT_ID + " INTEGER NOT NULL," +
382b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.EventsRawTimes.DTSTART_2445 + " TEXT," +
383b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.EventsRawTimes.DTEND_2445 + " TEXT," +
384b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.EventsRawTimes.ORIGINAL_INSTANCE_TIME_2445 + " TEXT," +
385b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.EventsRawTimes.LAST_DATE_2445 + " TEXT," +
386b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                "UNIQUE (" + CalendarContract.EventsRawTimes.EVENT_ID + ")" +
3879f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff                ");");
3889f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
3897cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        db.execSQL("CREATE TABLE " + Tables.INSTANCES + " (" +
390b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Instances._ID + " INTEGER PRIMARY KEY," +
391b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Instances.EVENT_ID + " INTEGER," +
392b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Instances.BEGIN + " INTEGER," +         // UTC millis
393b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Instances.END + " INTEGER," +           // UTC millis
394b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Instances.START_DAY + " INTEGER," +      // Julian start day
395b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Instances.END_DAY + " INTEGER," +        // Julian end day
396b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Instances.START_MINUTE + " INTEGER," +   // minutes from midnight
397b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Instances.END_MINUTE + " INTEGER," +     // minutes from midnight
3987cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio                "UNIQUE (" +
399b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                    CalendarContract.Instances.EVENT_ID + ", " +
400b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                    CalendarContract.Instances.BEGIN + ", " +
401b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                    CalendarContract.Instances.END + ")" +
4029f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff                ");");
4039f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
4047cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        db.execSQL("CREATE INDEX instancesStartDayIndex ON " + Tables.INSTANCES + " (" +
405b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Instances.START_DAY +
4069f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff                ");");
4079f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
4081599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio        createCalendarMetaDataTable(db);
4099f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
410315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio        createCalendarCacheTable(db, null);
411ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio
4127cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        db.execSQL("CREATE TABLE " + Tables.ATTENDEES + " (" +
413b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Attendees._ID + " INTEGER PRIMARY KEY," +
414b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Attendees.EVENT_ID + " INTEGER," +
415b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Attendees.ATTENDEE_NAME + " TEXT," +
416b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Attendees.ATTENDEE_EMAIL + " TEXT," +
417b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Attendees.ATTENDEE_STATUS + " INTEGER," +
418b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Attendees.ATTENDEE_RELATIONSHIP + " INTEGER," +
419b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Attendees.ATTENDEE_TYPE + " INTEGER" +
4209f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff                ");");
4219f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
4227cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        db.execSQL("CREATE INDEX attendeesEventIdIndex ON " + Tables.ATTENDEES + " (" +
423b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Attendees.EVENT_ID +
4249f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff                ");");
4259f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
4267cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        db.execSQL("CREATE TABLE " + Tables.REMINDERS + " (" +
427b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Reminders._ID + " INTEGER PRIMARY KEY," +
428b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Reminders.EVENT_ID + " INTEGER," +
429b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Reminders.MINUTES + " INTEGER," +
430b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Reminders.METHOD + " INTEGER NOT NULL" +
431b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                " DEFAULT " + CalendarContract.Reminders.METHOD_DEFAULT +
4329f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff                ");");
4339f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
4347cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        db.execSQL("CREATE INDEX remindersEventIdIndex ON " + Tables.REMINDERS + " (" +
435b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Reminders.EVENT_ID +
4369f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff                ");");
4379f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
4387e3ec5f2025164fca508f81a5a01940bc912e064Ken Shirriff         // This table stores the Calendar notifications that have gone off.
4397cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        db.execSQL("CREATE TABLE " + Tables.CALENDAR_ALERTS + " (" +
440b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.CalendarAlerts._ID + " INTEGER PRIMARY KEY," +
441b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.CalendarAlerts.EVENT_ID + " INTEGER," +
442b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.CalendarAlerts.BEGIN + " INTEGER NOT NULL," +      // UTC millis
443b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.CalendarAlerts.END + " INTEGER NOT NULL," +        // UTC millis
444b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.CalendarAlerts.ALARM_TIME + " INTEGER NOT NULL," + // UTC millis
445d5f4742d7ba16d791edd9fd33a1a2a42eeac709bRoboErik                // UTC millis
446b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.CalendarAlerts.CREATION_TIME + " INTEGER NOT NULL DEFAULT 0," +
447d5f4742d7ba16d791edd9fd33a1a2a42eeac709bRoboErik                // UTC millis
448b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.CalendarAlerts.RECEIVED_TIME + " INTEGER NOT NULL DEFAULT 0," +
449d5f4742d7ba16d791edd9fd33a1a2a42eeac709bRoboErik                // UTC millis
450b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.CalendarAlerts.NOTIFY_TIME + " INTEGER NOT NULL DEFAULT 0," +
451b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.CalendarAlerts.STATE + " INTEGER NOT NULL," +
452b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.CalendarAlerts.MINUTES + " INTEGER," +
4537cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio                "UNIQUE (" +
454b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                    CalendarContract.CalendarAlerts.ALARM_TIME + ", " +
455b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                    CalendarContract.CalendarAlerts.BEGIN + ", " +
456b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                    CalendarContract.CalendarAlerts.EVENT_ID + ")" +
4579f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff                ");");
4589f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
4597cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        db.execSQL("CREATE INDEX calendarAlertsEventIdIndex ON " + Tables.CALENDAR_ALERTS + " (" +
460b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.CalendarAlerts.EVENT_ID +
4619f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff                ");");
4629f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
4637cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        db.execSQL("CREATE TABLE " + Tables.EXTENDED_PROPERTIES + " (" +
464b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.ExtendedProperties._ID + " INTEGER PRIMARY KEY," +
465b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.ExtendedProperties.EVENT_ID + " INTEGER," +
466b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.ExtendedProperties.NAME + " TEXT," +
467b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.ExtendedProperties.VALUE + " TEXT" +
4689f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff                ");");
4699f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
4707cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        db.execSQL("CREATE INDEX extendedPropertiesEventIdIndex ON " + Tables.EXTENDED_PROPERTIES
4717cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio                + " (" +
472b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.ExtendedProperties.EVENT_ID +
4739f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff                ");");
4749f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
4757cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        createEventsView(db);
4767cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio
4779f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff        // Trigger to remove data tied to an event when we delete that event.
4787cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        db.execSQL("CREATE TRIGGER events_cleanup_delete DELETE ON " + Tables.EVENTS + " " +
4799f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff                "BEGIN " +
4807cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio                EVENTS_CLEANUP_TRIGGER_SQL +
4819f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff                "END");
4829f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
4832f251c778c06d21ed7693a70f4a1268ff929242eRoboErik        // Triggers to update the color stored in an event or a calendar when
4842f251c778c06d21ed7693a70f4a1268ff929242eRoboErik        // the color_index is changed.
4852f251c778c06d21ed7693a70f4a1268ff929242eRoboErik        createColorsTriggers(db);
4862f251c778c06d21ed7693a70f4a1268ff929242eRoboErik
48734c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik        // Trigger to update exceptions when an original event updates its
48834c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik        // _sync_id
48934c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik        db.execSQL(CREATE_SYNC_ID_UPDATE_TRIGGER);
49034c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik
491470aa5bc291ca33d51dda356f38ac2954026da9aAlon Albert        scheduleSync(null /* all accounts */, false, null);
4929f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    }
4939f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
494c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik    private void createEventsTable(SQLiteDatabase db) {
495bcba82631ab0ee16efe58f0e0b0b9c18d93a6fd2Andy McFadden        // IMPORTANT: when adding new columns, be sure to update ALLOWED_IN_EXCEPTION and
496bcba82631ab0ee16efe58f0e0b0b9c18d93a6fd2Andy McFadden        // DONT_CLONE_INTO_EXCEPTION in CalendarProvider2.
497bcba82631ab0ee16efe58f0e0b0b9c18d93a6fd2Andy McFadden        //
498c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik        // TODO: do we need both dtend and duration?
49902f97c538fc46a08d857d2c807c76fd0eec12493RoboErik        // **When updating this be sure to also update LAST_SYNCED_EVENT_COLUMNS
500c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik        db.execSQL("CREATE TABLE " + Tables.EVENTS + " (" +
501935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden                CalendarContract.Events._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
502b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Events._SYNC_ID + " TEXT," +
503b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Events.DIRTY + " INTEGER," +
504b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Events.LAST_SYNCED + " INTEGER DEFAULT 0," +
505b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Events.CALENDAR_ID + " INTEGER NOT NULL," +
506b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Events.TITLE + " TEXT," +
507b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Events.EVENT_LOCATION + " TEXT," +
508b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Events.DESCRIPTION + " TEXT," +
509b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Events.EVENT_COLOR + " INTEGER," +
510387535fec9f646e0b7acb82d5354f2b5ebee4395RoboErik                CalendarContract.Events.EVENT_COLOR_KEY + " TEXT," +
511b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Events.STATUS + " INTEGER," +
512b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Events.SELF_ATTENDEE_STATUS + " INTEGER NOT NULL DEFAULT 0," +
513c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                // dtstart in millis since epoch
514b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Events.DTSTART + " INTEGER," +
515c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                // dtend in millis since epoch
516b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Events.DTEND + " INTEGER," +
517c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                // timezone for event
518b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Events.EVENT_TIMEZONE + " TEXT," +
519b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Events.DURATION + " TEXT," +
520b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Events.ALL_DAY + " INTEGER NOT NULL DEFAULT 0," +
521b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Events.ACCESS_LEVEL + " INTEGER NOT NULL DEFAULT 0," +
522b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Events.AVAILABILITY + " INTEGER NOT NULL DEFAULT 0," +
523b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Events.HAS_ALARM + " INTEGER NOT NULL DEFAULT 0," +
524b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Events.HAS_EXTENDED_PROPERTIES + " INTEGER NOT NULL DEFAULT 0," +
525b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Events.RRULE + " TEXT," +
526b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Events.RDATE + " TEXT," +
527b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Events.EXRULE + " TEXT," +
528b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Events.EXDATE + " TEXT," +
529b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Events.ORIGINAL_ID + " INTEGER," +
53034c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik                // ORIGINAL_SYNC_ID is the _sync_id of recurring event
531b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Events.ORIGINAL_SYNC_ID + " TEXT," +
53234c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik                // originalInstanceTime is in millis since epoch
533b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Events.ORIGINAL_INSTANCE_TIME + " INTEGER," +
534b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Events.ORIGINAL_ALL_DAY + " INTEGER," +
53534c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik                // lastDate is in millis since epoch
536b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Events.LAST_DATE + " INTEGER," +
537b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Events.HAS_ATTENDEE_DATA + " INTEGER NOT NULL DEFAULT 0," +
538b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Events.GUESTS_CAN_MODIFY + " INTEGER NOT NULL DEFAULT 0," +
539b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Events.GUESTS_CAN_INVITE_OTHERS + " INTEGER NOT NULL DEFAULT 1," +
540b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Events.GUESTS_CAN_SEE_GUESTS + " INTEGER NOT NULL DEFAULT 1," +
541b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Events.ORGANIZER + " STRING," +
542b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Events.DELETED + " INTEGER NOT NULL DEFAULT 0," +
54334c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik                // timezone for event with allDay events are in local timezone
544b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Events.EVENT_END_TIMEZONE + " TEXT," +
54502f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                // SYNC_DATAX columns are available for use by sync adapters
546b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Events.SYNC_DATA1 + " TEXT," +
547b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Events.SYNC_DATA2 + " TEXT," +
548b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Events.SYNC_DATA3 + " TEXT," +
549b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Events.SYNC_DATA4 + " TEXT," +
550b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Events.SYNC_DATA5 + " TEXT," +
551b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Events.SYNC_DATA6 + " TEXT," +
552b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Events.SYNC_DATA7 + " TEXT," +
553b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Events.SYNC_DATA8 + " TEXT," +
554b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Events.SYNC_DATA9 + " TEXT," +
555b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Events.SYNC_DATA10 + " TEXT" + ");");
55602f97c538fc46a08d857d2c807c76fd0eec12493RoboErik
55702f97c538fc46a08d857d2c807c76fd0eec12493RoboErik        // **When updating this be sure to also update LAST_SYNCED_EVENT_COLUMNS
55834c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik
55934c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik        db.execSQL("CREATE INDEX eventsCalendarIdIndex ON " + Tables.EVENTS + " ("
560b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Events.CALENDAR_ID + ");");
56134c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik    }
56234c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik
5632f251c778c06d21ed7693a70f4a1268ff929242eRoboErik    private void createEventsTable307(SQLiteDatabase db) {
5642f251c778c06d21ed7693a70f4a1268ff929242eRoboErik        db.execSQL("CREATE TABLE Events ("
5652f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "_id INTEGER PRIMARY KEY AUTOINCREMENT,"
5662f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "_sync_id TEXT,"
5672f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "dirty INTEGER,"
5682f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "lastSynced INTEGER DEFAULT 0,"
5692f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "calendar_id INTEGER NOT NULL,"
5702f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "title TEXT,"
5712f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "eventLocation TEXT,"
5722f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "description TEXT,"
5732f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "eventColor INTEGER,"
5742f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "eventStatus INTEGER,"
5752f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "selfAttendeeStatus INTEGER NOT NULL DEFAULT 0,"
5762f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                // dtstart in millis since epoch
5772f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "dtstart INTEGER,"
5782f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                // dtend in millis since epoch
5792f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "dtend INTEGER,"
5802f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                // timezone for event
5812f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "eventTimezone TEXT,"
5822f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "duration TEXT,"
5832f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "allDay INTEGER NOT NULL DEFAULT 0,"
5842f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "accessLevel INTEGER NOT NULL DEFAULT 0,"
5852f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "availability INTEGER NOT NULL DEFAULT 0,"
5862f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "hasAlarm INTEGER NOT NULL DEFAULT 0,"
5872f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "hasExtendedProperties INTEGER NOT NULL DEFAULT 0,"
5882f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "rrule TEXT,"
5892f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "rdate TEXT,"
5902f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "exrule TEXT,"
5912f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "exdate TEXT,"
5922f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "original_id INTEGER,"
5932f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                // ORIGINAL_SYNC_ID is the _sync_id of recurring event
5942f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "original_sync_id TEXT,"
5952f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                // originalInstanceTime is in millis since epoch
5962f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "originalInstanceTime INTEGER,"
5972f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "originalAllDay INTEGER,"
5982f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                // lastDate is in millis since epoch
5992f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "lastDate INTEGER,"
6002f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "hasAttendeeData INTEGER NOT NULL DEFAULT 0,"
6012f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "guestsCanModify INTEGER NOT NULL DEFAULT 0,"
6022f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "guestsCanInviteOthers INTEGER NOT NULL DEFAULT 1,"
6032f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "guestsCanSeeGuests INTEGER NOT NULL DEFAULT 1,"
6042f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "organizer STRING,"
6052f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "deleted INTEGER NOT NULL DEFAULT 0,"
6062f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                // timezone for event with allDay events are in local timezone
6072f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "eventEndTimezone TEXT,"
6082f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                // SYNC_DATAX columns are available for use by sync adapters
6092f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "sync_data1 TEXT,"
6102f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "sync_data2 TEXT,"
6112f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "sync_data3 TEXT,"
6122f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "sync_data4 TEXT,"
6132f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "sync_data5 TEXT,"
6142f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "sync_data6 TEXT,"
6152f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "sync_data7 TEXT,"
6162f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "sync_data8 TEXT,"
6172f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "sync_data9 TEXT,"
6182f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "sync_data10 TEXT);");
6192f251c778c06d21ed7693a70f4a1268ff929242eRoboErik
6202f251c778c06d21ed7693a70f4a1268ff929242eRoboErik        // **When updating this be sure to also update LAST_SYNCED_EVENT_COLUMNS
6212f251c778c06d21ed7693a70f4a1268ff929242eRoboErik
6222f251c778c06d21ed7693a70f4a1268ff929242eRoboErik        db.execSQL("CREATE INDEX eventsCalendarIdIndex ON Events (calendar_id);");
6232f251c778c06d21ed7693a70f4a1268ff929242eRoboErik    }
6242f251c778c06d21ed7693a70f4a1268ff929242eRoboErik
62534c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik    // TODO Remove this method after merging all ICS upgrades
62634c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik    private void createEventsTable300(SQLiteDatabase db) {
62702f97c538fc46a08d857d2c807c76fd0eec12493RoboErik        db.execSQL("CREATE TABLE Events (" +
62802f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "_id INTEGER PRIMARY KEY," +
62902f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "_sync_id TEXT," +
63002f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "_sync_version TEXT," +
63134c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik                // sync time in UTC
63202f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "_sync_time TEXT,"  +
63302f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "_sync_local_id INTEGER," +
63402f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "dirty INTEGER," +
63534c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik                // sync mark to filter out new rows
63602f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "_sync_mark INTEGER," +
63702f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "calendar_id INTEGER NOT NULL," +
63802f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "htmlUri TEXT," +
63902f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "title TEXT," +
64002f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "eventLocation TEXT," +
64102f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "description TEXT," +
64202f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "eventStatus INTEGER," +
64302f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "selfAttendeeStatus INTEGER NOT NULL DEFAULT 0," +
64402f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "commentsUri TEXT," +
64534c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik                // dtstart in millis since epoch
64602f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "dtstart INTEGER," +
64734c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik                // dtend in millis since epoch
64802f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "dtend INTEGER," +
64934c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik                // timezone for event
65002f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "eventTimezone TEXT," +
65102f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "duration TEXT," +
65202f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "allDay INTEGER NOT NULL DEFAULT 0," +
65302f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "accessLevel INTEGER NOT NULL DEFAULT 0," +
65402f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "availability INTEGER NOT NULL DEFAULT 0," +
65502f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "hasAlarm INTEGER NOT NULL DEFAULT 0," +
65602f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "hasExtendedProperties INTEGER NOT NULL DEFAULT 0," +
65702f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "rrule TEXT," +
65802f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "rdate TEXT," +
65902f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "exrule TEXT," +
66002f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "exdate TEXT," +
661c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                // originalEvent is the _sync_id of recurring event
66202f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "original_sync_id TEXT," +
663c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                // originalInstanceTime is in millis since epoch
66402f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "originalInstanceTime INTEGER," +
66502f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "originalAllDay INTEGER," +
666c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                // lastDate is in millis since epoch
66702f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "lastDate INTEGER," +
66802f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "hasAttendeeData INTEGER NOT NULL DEFAULT 0," +
66902f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "guestsCanModify INTEGER NOT NULL DEFAULT 0," +
67002f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "guestsCanInviteOthers INTEGER NOT NULL DEFAULT 1," +
67102f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "guestsCanSeeGuests INTEGER NOT NULL DEFAULT 1," +
67202f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "organizer STRING," +
67302f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "deleted INTEGER NOT NULL DEFAULT 0," +
674c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                // timezone for event with allDay events are in local timezone
67502f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "eventEndTimezone TEXT," +
676c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                // syncAdapterData is available for use by sync adapters
67702f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "sync_data1 TEXT);");
678c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik
67902f97c538fc46a08d857d2c807c76fd0eec12493RoboErik        db.execSQL("CREATE INDEX eventsCalendarIdIndex ON Events (calendar_id);");
680c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik    }
681c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik
6829ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert    private void createCalendarsTable303(SQLiteDatabase db) {
6839ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert        db.execSQL("CREATE TABLE " + Tables.CALENDARS + " (" +
6849ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                "_id INTEGER PRIMARY KEY," +
6859ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                "account_name TEXT," +
6869ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                "account_type TEXT," +
6879ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                "_sync_id TEXT," +
6889ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                "_sync_version TEXT," +
6899ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                "_sync_time TEXT," +  // UTC
6909ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                "dirty INTEGER," +
6919ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                "name TEXT," +
6929ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                "displayName TEXT," +
6939ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                "calendar_color INTEGER," +
6949ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                "access_level INTEGER," +
6959ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                "visible INTEGER NOT NULL DEFAULT 1," +
6969ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                "sync_events INTEGER NOT NULL DEFAULT 0," +
6979ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                "calendar_location TEXT," +
6989ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                "calendar_timezone TEXT," +
6999ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                "ownerAccount TEXT, " +
7009ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                "canOrganizerRespond INTEGER NOT NULL DEFAULT 1," +
7019ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                "canModifyTimeZone INTEGER DEFAULT 1," +
7029ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                "maxReminders INTEGER DEFAULT 5," +
703bf986d8deeeed9566e0badeba89d4800533cbca6Andy McFadden                "allowedReminders TEXT DEFAULT '0,1'," +
7049ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                "deleted INTEGER NOT NULL DEFAULT 0," +
7059ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                "cal_sync1 TEXT," +
7069ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                "cal_sync2 TEXT," +
7079ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                "cal_sync3 TEXT," +
7089ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                "cal_sync4 TEXT," +
7099ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                "cal_sync5 TEXT," +
7109ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                "cal_sync6 TEXT" +
7119ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                ");");
7129ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert
7139ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert        // Trigger to remove a calendar's events when we delete the calendar
7149ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert        db.execSQL("CREATE TRIGGER calendar_cleanup DELETE ON " + Tables.CALENDARS + " " +
7159ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                "BEGIN " +
7169ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                CALENDAR_CLEANUP_TRIGGER_SQL +
7179ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                "END");
7189ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert    }
7199ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert
7202f251c778c06d21ed7693a70f4a1268ff929242eRoboErik    private void createColorsTable(SQLiteDatabase db) {
7212f251c778c06d21ed7693a70f4a1268ff929242eRoboErik
7222f251c778c06d21ed7693a70f4a1268ff929242eRoboErik        db.execSQL("CREATE TABLE " + Tables.COLORS + " (" +
7232f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                CalendarContract.Colors._ID + " INTEGER PRIMARY KEY," +
7242f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                CalendarContract.Colors.ACCOUNT_NAME + " TEXT NOT NULL," +
7252f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                CalendarContract.Colors.ACCOUNT_TYPE + " TEXT NOT NULL," +
7262f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                CalendarContract.Colors.DATA + " TEXT," +
7272f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                CalendarContract.Colors.COLOR_TYPE + " INTEGER NOT NULL," +
728387535fec9f646e0b7acb82d5354f2b5ebee4395RoboErik                CalendarContract.Colors.COLOR_KEY + " TEXT NOT NULL," +
7292f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                CalendarContract.Colors.COLOR + " INTEGER NOT NULL" +
7302f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                ");");
7312f251c778c06d21ed7693a70f4a1268ff929242eRoboErik    }
7322f251c778c06d21ed7693a70f4a1268ff929242eRoboErik
7332f251c778c06d21ed7693a70f4a1268ff929242eRoboErik    public void createColorsTriggers(SQLiteDatabase db) {
7342f251c778c06d21ed7693a70f4a1268ff929242eRoboErik        db.execSQL(CREATE_EVENT_COLOR_UPDATE_TRIGGER);
7352f251c778c06d21ed7693a70f4a1268ff929242eRoboErik        db.execSQL(CREATE_CALENDAR_COLOR_UPDATE_TRIGGER);
7362f251c778c06d21ed7693a70f4a1268ff929242eRoboErik    }
7372f251c778c06d21ed7693a70f4a1268ff929242eRoboErik
7381b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio    private void createCalendarsTable(SQLiteDatabase db) {
7391b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio        db.execSQL("CREATE TABLE " + Tables.CALENDARS + " (" +
740b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Calendars._ID + " INTEGER PRIMARY KEY," +
741b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Calendars.ACCOUNT_NAME + " TEXT," +
742b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Calendars.ACCOUNT_TYPE + " TEXT," +
743b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Calendars._SYNC_ID + " TEXT," +
744b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Calendars.DIRTY + " INTEGER," +
745b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Calendars.NAME + " TEXT," +
746b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Calendars.CALENDAR_DISPLAY_NAME + " TEXT," +
747b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Calendars.CALENDAR_COLOR + " INTEGER," +
748387535fec9f646e0b7acb82d5354f2b5ebee4395RoboErik                CalendarContract.Calendars.CALENDAR_COLOR_KEY + " TEXT," +
749b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Calendars.CALENDAR_ACCESS_LEVEL + " INTEGER," +
750b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Calendars.VISIBLE + " INTEGER NOT NULL DEFAULT 1," +
751b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Calendars.SYNC_EVENTS + " INTEGER NOT NULL DEFAULT 0," +
752b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Calendars.CALENDAR_LOCATION + " TEXT," +
753b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Calendars.CALENDAR_TIME_ZONE + " TEXT," +
754b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Calendars.OWNER_ACCOUNT + " TEXT, " +
755b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Calendars.CAN_ORGANIZER_RESPOND + " INTEGER NOT NULL DEFAULT 1," +
756b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Calendars.CAN_MODIFY_TIME_ZONE + " INTEGER DEFAULT 1," +
757b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Calendars.CAN_PARTIALLY_UPDATE + " INTEGER DEFAULT 0," +
758b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Calendars.MAX_REMINDERS + " INTEGER DEFAULT 5," +
759bf986d8deeeed9566e0badeba89d4800533cbca6Andy McFadden                CalendarContract.Calendars.ALLOWED_REMINDERS + " TEXT DEFAULT '0,1'," +
7602f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                CalendarContract.Calendars.ALLOWED_AVAILABILITY + " TEXT DEFAULT '0,1'," +
7612f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                CalendarContract.Calendars.ALLOWED_ATTENDEE_TYPES + " TEXT DEFAULT '0,1,2'," +
762b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Calendars.DELETED + " INTEGER NOT NULL DEFAULT 0," +
763b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Calendars.CAL_SYNC1 + " TEXT," +
764b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Calendars.CAL_SYNC2 + " TEXT," +
765b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Calendars.CAL_SYNC3 + " TEXT," +
766b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Calendars.CAL_SYNC4 + " TEXT," +
767b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Calendars.CAL_SYNC5 + " TEXT," +
768b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Calendars.CAL_SYNC6 + " TEXT," +
769b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Calendars.CAL_SYNC7 + " TEXT," +
770b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Calendars.CAL_SYNC8 + " TEXT," +
771b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Calendars.CAL_SYNC9 + " TEXT," +
772b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.Calendars.CAL_SYNC10 + " TEXT" +
773fa332ecedc0c340109811552407142f6e4f600b2RoboErik                ");");
774fa332ecedc0c340109811552407142f6e4f600b2RoboErik
775fa332ecedc0c340109811552407142f6e4f600b2RoboErik        // Trigger to remove a calendar's events when we delete the calendar
776fa332ecedc0c340109811552407142f6e4f600b2RoboErik        db.execSQL("CREATE TRIGGER calendar_cleanup DELETE ON " + Tables.CALENDARS + " " +
777fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "BEGIN " +
778fa332ecedc0c340109811552407142f6e4f600b2RoboErik                CALENDAR_CLEANUP_TRIGGER_SQL +
779fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "END");
780fa332ecedc0c340109811552407142f6e4f600b2RoboErik    }
781fa332ecedc0c340109811552407142f6e4f600b2RoboErik
7822f251c778c06d21ed7693a70f4a1268ff929242eRoboErik    private void createCalendarsTable305(SQLiteDatabase db) {
7832f251c778c06d21ed7693a70f4a1268ff929242eRoboErik        db.execSQL("CREATE TABLE Calendars (" +
7842f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                "_id INTEGER PRIMARY KEY," +
7852f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                "account_name TEXT," +
7862f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                "account_type TEXT," +
7872f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                "_sync_id TEXT," +
7882f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                "dirty INTEGER," +
7892f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                "name TEXT," +
7902f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                "calendar_displayName TEXT," +
7912f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                "calendar_color INTEGER," +
7922f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                "calendar_access_level INTEGER," +
7932f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                "visible INTEGER NOT NULL DEFAULT 1," +
7942f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                "sync_events INTEGER NOT NULL DEFAULT 0," +
7952f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                "calendar_location TEXT," +
7962f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                "calendar_timezone TEXT," +
7972f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                "ownerAccount TEXT, " +
7982f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                "canOrganizerRespond INTEGER NOT NULL DEFAULT 1," +
7992f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                "canModifyTimeZone INTEGER DEFAULT 1," +
8002f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                "canPartiallyUpdate INTEGER DEFAULT 0," +
8012f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                "maxReminders INTEGER DEFAULT 5," +
8022f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                "allowedReminders TEXT DEFAULT '0,1'," +
8032f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                "deleted INTEGER NOT NULL DEFAULT 0," +
8042f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                "cal_sync1 TEXT," +
8052f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                "cal_sync2 TEXT," +
8062f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                "cal_sync3 TEXT," +
8072f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                "cal_sync4 TEXT," +
8082f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                "cal_sync5 TEXT," +
8092f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                "cal_sync6 TEXT," +
8102f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                "cal_sync7 TEXT," +
8112f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                "cal_sync8 TEXT," +
8122f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                "cal_sync9 TEXT," +
8132f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                "cal_sync10 TEXT" +
8142f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                ");");
8152f251c778c06d21ed7693a70f4a1268ff929242eRoboErik
8162f251c778c06d21ed7693a70f4a1268ff929242eRoboErik        // Trigger to remove a calendar's events when we delete the calendar
8172f251c778c06d21ed7693a70f4a1268ff929242eRoboErik        db.execSQL("CREATE TRIGGER calendar_cleanup DELETE ON Calendars " +
8182f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                "BEGIN " +
8192f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                "DELETE FROM Events WHERE calendar_id=old._id;" +
8202f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                "END");
8212f251c778c06d21ed7693a70f4a1268ff929242eRoboErik    }
8222f251c778c06d21ed7693a70f4a1268ff929242eRoboErik
823fa332ecedc0c340109811552407142f6e4f600b2RoboErik    private void createCalendarsTable300(SQLiteDatabase db) {
824fa332ecedc0c340109811552407142f6e4f600b2RoboErik        db.execSQL("CREATE TABLE " + Tables.CALENDARS + " (" +
825fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "_id INTEGER PRIMARY KEY," +
826fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "account_name TEXT," +
827fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "account_type TEXT," +
828fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "_sync_id TEXT," +
829fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "_sync_version TEXT," +
830fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "_sync_time TEXT," +  // UTC
831fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "dirty INTEGER," +
832fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "name TEXT," +
833fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "displayName TEXT," +
834fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "calendar_color INTEGER," +
835fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "access_level INTEGER," +
836fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "visible INTEGER NOT NULL DEFAULT 1," +
837fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "sync_events INTEGER NOT NULL DEFAULT 0," +
838fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "calendar_location TEXT," +
839fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "calendar_timezone TEXT," +
840fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "ownerAccount TEXT, " +
841fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "canOrganizerRespond INTEGER NOT NULL DEFAULT 1," +
842fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "canModifyTimeZone INTEGER DEFAULT 1," +
843fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "maxReminders INTEGER DEFAULT 5," +
844fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "allowedReminders TEXT DEFAULT '0,1,2'," +
845fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "deleted INTEGER NOT NULL DEFAULT 0," +
846fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "sync1 TEXT," +
847fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "sync2 TEXT," +
848fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "sync3 TEXT," +
849fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "sync4 TEXT," +
850fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "sync5 TEXT," +
851fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "sync6 TEXT" +
8521b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio                ");");
8531b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio
8541b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio        // Trigger to remove a calendar's events when we delete the calendar
8551b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio        db.execSQL("CREATE TRIGGER calendar_cleanup DELETE ON " + Tables.CALENDARS + " " +
8561b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio                "BEGIN " +
8571b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio                CALENDAR_CLEANUP_TRIGGER_SQL +
8581b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio                "END");
8591b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio    }
8601b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio
861c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik    private void createCalendarsTable205(SQLiteDatabase db) {
862c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik        db.execSQL("CREATE TABLE Calendars (" +
863c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "_id INTEGER PRIMARY KEY," +
864c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "_sync_account TEXT," +
865c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "_sync_account_type TEXT," +
866c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "_sync_id TEXT," +
867c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "_sync_version TEXT," +
868c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "_sync_time TEXT," +  // UTC
869c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "_sync_dirty INTEGER," +
870c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "name TEXT," +
871c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "displayName TEXT," +
872c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "color INTEGER," +
873c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "access_level INTEGER," +
874c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "visible INTEGER NOT NULL DEFAULT 1," +
875c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "sync_events INTEGER NOT NULL DEFAULT 0," +
876c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "location TEXT," +
877c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "timezone TEXT," +
878c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "ownerAccount TEXT, " +
879c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "canOrganizerRespond INTEGER NOT NULL DEFAULT 1," +
880c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "canModifyTimeZone INTEGER DEFAULT 1, " +
881c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "maxReminders INTEGER DEFAULT 5," +
882c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "deleted INTEGER NOT NULL DEFAULT 0," +
883c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "sync1 TEXT," +
884c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "sync2 TEXT," +
885c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "sync3 TEXT," +
886c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "sync4 TEXT," +
887c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "sync5 TEXT," +
888c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "sync6 TEXT" +
889c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                ");");
890c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik
891c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik        createCalendarsCleanup200(db);
892c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik    }
893c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik
894180076a810558478f55ade53ebef0a2ddfa6bbc0Andy McFadden    private void createCalendarsTable202(SQLiteDatabase db) {
8952cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("CREATE TABLE Calendars (" +
8962cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_id INTEGER PRIMARY KEY," +
8972cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_account TEXT," +
8982cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_account_type TEXT," +
8992cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_id TEXT," +
9002cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_version TEXT," +
9012cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_time TEXT," +  // UTC
9022cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_local_id INTEGER," +
9032cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_dirty INTEGER," +
9042cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_mark INTEGER," + // Used to filter out new rows
9052cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "name TEXT," +
9062cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "displayName TEXT," +
9072cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "color INTEGER," +
9082cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "access_level INTEGER," +
9092cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "selected INTEGER NOT NULL DEFAULT 1," +
9102cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "sync_events INTEGER NOT NULL DEFAULT 0," +
9112cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "location TEXT," +
9122cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "timezone TEXT," +
9132cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "ownerAccount TEXT, " +
9142cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "organizerCanRespond INTEGER NOT NULL DEFAULT 1," +
9152cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "deleted INTEGER NOT NULL DEFAULT 0," +
9162cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "sync1 TEXT," +
9172cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "sync2 TEXT," +
9182cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "sync3 TEXT," +
9192cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "sync4 TEXT," +
9202cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "sync5 TEXT" +
9212cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                ");");
9222cff10f1a005bd7302245d4c680cf851193c3a97RoboErik
9234067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden        createCalendarsCleanup200(db);
9242cff10f1a005bd7302245d4c680cf851193c3a97RoboErik    }
9252cff10f1a005bd7302245d4c680cf851193c3a97RoboErik
9262cff10f1a005bd7302245d4c680cf851193c3a97RoboErik    private void createCalendarsTable200(SQLiteDatabase db) {
9272cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("CREATE TABLE Calendars (" +
9282cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_id INTEGER PRIMARY KEY," +
9292cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_account TEXT," +
9302cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_account_type TEXT," +
9312cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_id TEXT," +
9322cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_version TEXT," +
9332cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_time TEXT," +  // UTC
9342cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_local_id INTEGER," +
9352cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_dirty INTEGER," +
9362cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_mark INTEGER," + // Used to filter out new rows
9372cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "name TEXT," +
9382cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "displayName TEXT," +
9392cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "hidden INTEGER NOT NULL DEFAULT 0," +
9402cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "color INTEGER," +
9412cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "access_level INTEGER," +
9422cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "selected INTEGER NOT NULL DEFAULT 1," +
9432cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "sync_events INTEGER NOT NULL DEFAULT 0," +
9442cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "location TEXT," +
9452cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "timezone TEXT," +
9462cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "ownerAccount TEXT, " +
9472cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "organizerCanRespond INTEGER NOT NULL DEFAULT 1," +
9482cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "deleted INTEGER NOT NULL DEFAULT 0," +
9492cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "sync1 TEXT," +
9502cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "sync2 TEXT," +
9512cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "sync3 TEXT" +
9522cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                ");");
9532cff10f1a005bd7302245d4c680cf851193c3a97RoboErik
9544067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden        createCalendarsCleanup200(db);
9554067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden    }
9564067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden
9574067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden    /** Trigger to remove a calendar's events when we delete the calendar */
9584067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden    private void createCalendarsCleanup200(SQLiteDatabase db) {
9592cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("CREATE TRIGGER calendar_cleanup DELETE ON Calendars " +
9602cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "BEGIN " +
9612cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "DELETE FROM Events WHERE calendar_id=old._id;" +
9622cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "END");
9632cff10f1a005bd7302245d4c680cf851193c3a97RoboErik    }
9642cff10f1a005bd7302245d4c680cf851193c3a97RoboErik
9651599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio    private void createCalendarMetaDataTable(SQLiteDatabase db) {
9667cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        db.execSQL("CREATE TABLE " + Tables.CALENDAR_META_DATA + " (" +
967b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.CalendarMetaData._ID + " INTEGER PRIMARY KEY," +
968b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.CalendarMetaData.LOCAL_TIMEZONE + " TEXT," +
969b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.CalendarMetaData.MIN_INSTANCE + " INTEGER," +      // UTC millis
970b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                CalendarContract.CalendarMetaData.MAX_INSTANCE + " INTEGER" +       // UTC millis
9711599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio                ");");
9721599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio    }
9731599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio
9742cff10f1a005bd7302245d4c680cf851193c3a97RoboErik    private void createCalendarMetaDataTable59(SQLiteDatabase db) {
9752cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("CREATE TABLE CalendarMetaData (" +
9762cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_id INTEGER PRIMARY KEY," +
9772cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "localTimezone TEXT," +
9782cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "minInstance INTEGER," +      // UTC millis
9792cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "maxInstance INTEGER" +       // UTC millis
9802cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                ");");
9812cff10f1a005bd7302245d4c680cf851193c3a97RoboErik    }
9822cff10f1a005bd7302245d4c680cf851193c3a97RoboErik
983315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio    private void createCalendarCacheTable(SQLiteDatabase db, String oldTimezoneDbVersion) {
984754b6d0e96c7df4cb649a48cde21b72c3dcedf4aErik        // This is a hack because versioning skipped version number 61 of schema
985754b6d0e96c7df4cb649a48cde21b72c3dcedf4aErik        // TODO after version 70 this can be removed
9867cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        db.execSQL("DROP TABLE IF EXISTS " + Tables.CALENDAR_CACHE + ";");
987754b6d0e96c7df4cb649a48cde21b72c3dcedf4aErik
988754b6d0e96c7df4cb649a48cde21b72c3dcedf4aErik        // IF NOT EXISTS should be normal pattern for table creation
9897cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        db.execSQL("CREATE TABLE IF NOT EXISTS " + Tables.CALENDAR_CACHE + " (" +
9907cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio                CalendarCache.COLUMN_NAME_ID + " INTEGER PRIMARY KEY," +
9917cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio                CalendarCache.COLUMN_NAME_KEY + " TEXT NOT NULL," +
9927cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio                CalendarCache.COLUMN_NAME_VALUE + " TEXT" +
993ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio                ");");
994ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio
995315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio        initCalendarCacheTable(db, oldTimezoneDbVersion);
9962cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        updateCalendarCacheTable(db);
997b492524403ca34b0cb03bfad6456909494479925Fabrice Di Meglio    }
998b492524403ca34b0cb03bfad6456909494479925Fabrice Di Meglio
999315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio    private void initCalendarCacheTable(SQLiteDatabase db, String oldTimezoneDbVersion) {
1000315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio        String timezoneDbVersion = (oldTimezoneDbVersion != null) ?
1001315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio                oldTimezoneDbVersion : CalendarCache.DEFAULT_TIMEZONE_DATABASE_VERSION;
1002315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio
1003315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio        // Set the default timezone database version
1004258fc0a0054d6aba8556921c270379cea6bf3de1Fabrice Di Meglio        db.execSQL("INSERT OR REPLACE INTO " + Tables.CALENDAR_CACHE +
1005258fc0a0054d6aba8556921c270379cea6bf3de1Fabrice Di Meglio                " (" + CalendarCache.COLUMN_NAME_ID + ", " +
1006258fc0a0054d6aba8556921c270379cea6bf3de1Fabrice Di Meglio                CalendarCache.COLUMN_NAME_KEY + ", " +
1007258fc0a0054d6aba8556921c270379cea6bf3de1Fabrice Di Meglio                CalendarCache.COLUMN_NAME_VALUE + ") VALUES (" +
1008b492524403ca34b0cb03bfad6456909494479925Fabrice Di Meglio                CalendarCache.KEY_TIMEZONE_DATABASE_VERSION.hashCode() + "," +
1009470aa5bc291ca33d51dda356f38ac2954026da9aAlon Albert                "'" + CalendarCache.KEY_TIMEZONE_DATABASE_VERSION + "'," +
1010315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio                "'" + timezoneDbVersion + "'" +
1011315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio                ");");
1012315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio    }
1013315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio
10142cff10f1a005bd7302245d4c680cf851193c3a97RoboErik    private void updateCalendarCacheTable(SQLiteDatabase db) {
1015315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio        // Define the default timezone type for Instances timezone management
1016258fc0a0054d6aba8556921c270379cea6bf3de1Fabrice Di Meglio        db.execSQL("INSERT INTO " + Tables.CALENDAR_CACHE +
1017258fc0a0054d6aba8556921c270379cea6bf3de1Fabrice Di Meglio                " (" + CalendarCache.COLUMN_NAME_ID + ", " +
1018258fc0a0054d6aba8556921c270379cea6bf3de1Fabrice Di Meglio                CalendarCache.COLUMN_NAME_KEY + ", " +
1019258fc0a0054d6aba8556921c270379cea6bf3de1Fabrice Di Meglio                CalendarCache.COLUMN_NAME_VALUE + ") VALUES (" +
1020315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio                CalendarCache.KEY_TIMEZONE_TYPE.hashCode() + "," +
1021315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio                "'" + CalendarCache.KEY_TIMEZONE_TYPE + "',"  +
1022315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio                "'" + CalendarCache.TIMEZONE_TYPE_AUTO + "'" +
1023315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio                ");");
1024315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio
1025315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio        String defaultTimezone = TimeZone.getDefault().getID();
1026315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio
1027315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio        // Define the default timezone for Instances
1028258fc0a0054d6aba8556921c270379cea6bf3de1Fabrice Di Meglio        db.execSQL("INSERT INTO " + Tables.CALENDAR_CACHE +
1029258fc0a0054d6aba8556921c270379cea6bf3de1Fabrice Di Meglio                " (" + CalendarCache.COLUMN_NAME_ID + ", " +
1030258fc0a0054d6aba8556921c270379cea6bf3de1Fabrice Di Meglio                CalendarCache.COLUMN_NAME_KEY + ", " +
1031258fc0a0054d6aba8556921c270379cea6bf3de1Fabrice Di Meglio                CalendarCache.COLUMN_NAME_VALUE + ") VALUES (" +
1032315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio                CalendarCache.KEY_TIMEZONE_INSTANCES.hashCode() + "," +
1033315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio                "'" + CalendarCache.KEY_TIMEZONE_INSTANCES + "',"  +
1034315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio                "'" + defaultTimezone + "'" +
1035315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio                ");");
1036315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio
1037315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio        // Define the default previous timezone for Instances
1038258fc0a0054d6aba8556921c270379cea6bf3de1Fabrice Di Meglio        db.execSQL("INSERT INTO " + Tables.CALENDAR_CACHE +
1039258fc0a0054d6aba8556921c270379cea6bf3de1Fabrice Di Meglio                " (" + CalendarCache.COLUMN_NAME_ID + ", " +
1040258fc0a0054d6aba8556921c270379cea6bf3de1Fabrice Di Meglio                CalendarCache.COLUMN_NAME_KEY + ", " +
1041258fc0a0054d6aba8556921c270379cea6bf3de1Fabrice Di Meglio                CalendarCache.COLUMN_NAME_VALUE + ") VALUES (" +
1042315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio                CalendarCache.KEY_TIMEZONE_INSTANCES_PREVIOUS.hashCode() + "," +
1043315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio                "'" + CalendarCache.KEY_TIMEZONE_INSTANCES_PREVIOUS + "',"  +
1044315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio                "'" + defaultTimezone + "'" +
1045ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio                ");");
1046ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio    }
1047ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio
10482cff10f1a005bd7302245d4c680cf851193c3a97RoboErik    private void initCalendarCacheTable203(SQLiteDatabase db, String oldTimezoneDbVersion) {
10492cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        String timezoneDbVersion = (oldTimezoneDbVersion != null) ?
10502cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                oldTimezoneDbVersion : "2009s";
10512cff10f1a005bd7302245d4c680cf851193c3a97RoboErik
10522cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        // Set the default timezone database version
10532cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("INSERT OR REPLACE INTO CalendarCache" +
10542cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                " (_id, " +
10552cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "key, " +
10562cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "value) VALUES (" +
10572cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "timezoneDatabaseVersion".hashCode() + "," +
10582cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "'timezoneDatabaseVersion',"  +
10592cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "'" + timezoneDbVersion + "'" +
10602cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                ");");
10612cff10f1a005bd7302245d4c680cf851193c3a97RoboErik    }
10622cff10f1a005bd7302245d4c680cf851193c3a97RoboErik
10632cff10f1a005bd7302245d4c680cf851193c3a97RoboErik    private void updateCalendarCacheTableTo203(SQLiteDatabase db) {
10642cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        // Define the default timezone type for Instances timezone management
10652cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("INSERT INTO CalendarCache" +
10662cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                " (_id, key, value) VALUES (" +
10672cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "timezoneType".hashCode() + "," +
10682cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "'timezoneType',"  +
10692cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "'auto'" +
10702cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                ");");
10712cff10f1a005bd7302245d4c680cf851193c3a97RoboErik
10722cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        String defaultTimezone = TimeZone.getDefault().getID();
10732cff10f1a005bd7302245d4c680cf851193c3a97RoboErik
10742cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        // Define the default timezone for Instances
10752cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("INSERT INTO CalendarCache" +
10762cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                " (_id, key, value) VALUES (" +
10772cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "timezoneInstances".hashCode() + "," +
10782cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "'timezoneInstances',"  +
10792cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "'" + defaultTimezone + "'" +
10802cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                ");");
10812cff10f1a005bd7302245d4c680cf851193c3a97RoboErik
10822cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        // Define the default previous timezone for Instances
10832cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("INSERT INTO CalendarCache" +
10842cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                " (_id, key, value) VALUES (" +
10852cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "timezoneInstancesPrevious".hashCode() + "," +
10862cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "'timezoneInstancesPrevious',"  +
10872cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "'" + defaultTimezone + "'" +
10882cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                ");");
10892cff10f1a005bd7302245d4c680cf851193c3a97RoboErik    }
10902cff10f1a005bd7302245d4c680cf851193c3a97RoboErik
1091935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden    /**
1092935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden     * Removes orphaned data from the database.  Specifically:
1093935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden     * <ul>
1094935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden     * <li>Attendees with an event_id for a nonexistent Event
1095935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden     * <li>Reminders with an event_id for a nonexistent Event
1096935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden     * </ul>
1097935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden     */
1098935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden    static void removeOrphans(SQLiteDatabase db) {
1099935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden        if (false) {        // debug mode
1100935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            String SELECT_ATTENDEES_ORPHANS = "SELECT " +
1101935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden                    Attendees._ID + ", " + Attendees.EVENT_ID + " FROM " + Tables.ATTENDEES +
1102935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden                    " WHERE " + WHERE_ATTENDEES_ORPHANS;
1103935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden
1104935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            Cursor cursor = null;
1105935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            try {
1106935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden                Log.i(TAG, "Attendees orphans:");
1107935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden                cursor = db.rawQuery(SELECT_ATTENDEES_ORPHANS, null);
1108935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden                DatabaseUtils.dumpCursor(cursor);
1109935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            } finally {
1110935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden                if (cursor != null) {
1111935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden                    cursor.close();
1112935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden                }
1113935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            }
1114935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden
1115935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            String SELECT_REMINDERS_ORPHANS = "SELECT " +
1116935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden                    Attendees._ID + ", " + Reminders.EVENT_ID + " FROM " + Tables.REMINDERS +
1117935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden                    " WHERE " + WHERE_REMINDERS_ORPHANS;
1118935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            cursor = null;
1119935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            try {
1120935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden                Log.i(TAG, "Reminders orphans:");
1121935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden                cursor = db.rawQuery(SELECT_REMINDERS_ORPHANS, null);
1122935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden                DatabaseUtils.dumpCursor(cursor);
1123935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            } finally {
1124935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden                if (cursor != null) {
1125935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden                    cursor.close();
1126935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden                }
1127935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            }
1128935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden
1129935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            return;
1130935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden        }
1131935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden
1132935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden        Log.d(TAG, "Checking for orphaned entries");
1133935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden        int count;
1134935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden
1135935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden        count = db.delete(Tables.ATTENDEES, WHERE_ATTENDEES_ORPHANS, null);
1136935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden        if (count != 0) {
1137935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            Log.i(TAG, "Deleted " + count + " orphaned Attendees");
1138935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden        }
1139935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden
1140935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden        count = db.delete(Tables.REMINDERS, WHERE_REMINDERS_ORPHANS, null);
1141935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden        if (count != 0) {
1142935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            Log.i(TAG, "Deleted " + count + " orphaned Reminders");
1143935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden        }
1144935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden    }
1145935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden
1146935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden
11479f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    @Override
11489f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
11497544af675ce2fd78f33198e5e9194f2bc7bd129fAndy McFadden        Log.i(TAG, "Upgrading DB from version " + oldVersion + " to " + newVersion);
11507544af675ce2fd78f33198e5e9194f2bc7bd129fAndy McFadden        long startWhen = System.nanoTime();
11517544af675ce2fd78f33198e5e9194f2bc7bd129fAndy McFadden
1152ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        if (oldVersion < 49) {
11539f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff            dropTables(db);
11549f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff            mSyncState.createDatabase(db);
11559f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff            return; // this was lossy
11569f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff        }
11579f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
11581599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio        // From schema versions 59 to version 66, the CalendarMetaData table definition had lost
11591599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio        // the primary key leading to having the CalendarMetaData with multiple rows instead of
11601599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio        // only one. The Instance table was then corrupted (during Instance expansion we are using
11611599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio        // the localTimezone, minInstance and maxInstance from CalendarMetaData table.
11621599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio        // This boolean helps us tracking the need to recreate the CalendarMetaData table and
11631599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio        // clear the Instance table (and thus force an Instance expansion).
1164679d544f38aa33d00c12884b987d8f8af2a6a6d3Fabrice Di Meglio        boolean recreateMetaDataAndInstances = (oldVersion >= 59 && oldVersion <= 66);
11652cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        boolean createEventsView = false;
11661599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio
1167a6357118c223d00ed722ecd40ecdda92d705d211Erik        try {
1168a6357118c223d00ed722ecd40ecdda92d705d211Erik            if (oldVersion < 51) {
1169a6357118c223d00ed722ecd40ecdda92d705d211Erik                upgradeToVersion51(db); // From 50 or 51
1170a6357118c223d00ed722ecd40ecdda92d705d211Erik                oldVersion = 51;
1171a6357118c223d00ed722ecd40ecdda92d705d211Erik            }
1172a6357118c223d00ed722ecd40ecdda92d705d211Erik            if (oldVersion == 51) {
1173a6357118c223d00ed722ecd40ecdda92d705d211Erik                upgradeToVersion52(db);
1174a6357118c223d00ed722ecd40ecdda92d705d211Erik                oldVersion += 1;
1175a6357118c223d00ed722ecd40ecdda92d705d211Erik            }
1176a6357118c223d00ed722ecd40ecdda92d705d211Erik            if (oldVersion == 52) {
1177a6357118c223d00ed722ecd40ecdda92d705d211Erik                upgradeToVersion53(db);
1178a6357118c223d00ed722ecd40ecdda92d705d211Erik                oldVersion += 1;
1179a6357118c223d00ed722ecd40ecdda92d705d211Erik            }
1180a6357118c223d00ed722ecd40ecdda92d705d211Erik            if (oldVersion == 53) {
1181a6357118c223d00ed722ecd40ecdda92d705d211Erik                upgradeToVersion54(db);
1182a6357118c223d00ed722ecd40ecdda92d705d211Erik                oldVersion += 1;
1183a6357118c223d00ed722ecd40ecdda92d705d211Erik            }
1184a6357118c223d00ed722ecd40ecdda92d705d211Erik            if (oldVersion == 54) {
1185a6357118c223d00ed722ecd40ecdda92d705d211Erik                upgradeToVersion55(db);
1186a6357118c223d00ed722ecd40ecdda92d705d211Erik                oldVersion += 1;
1187a6357118c223d00ed722ecd40ecdda92d705d211Erik            }
1188a6357118c223d00ed722ecd40ecdda92d705d211Erik            if (oldVersion == 55 || oldVersion == 56) {
1189a6357118c223d00ed722ecd40ecdda92d705d211Erik                // Both require resync, so just schedule it once
1190a6357118c223d00ed722ecd40ecdda92d705d211Erik                upgradeResync(db);
1191a6357118c223d00ed722ecd40ecdda92d705d211Erik            }
1192a6357118c223d00ed722ecd40ecdda92d705d211Erik            if (oldVersion == 55) {
1193a6357118c223d00ed722ecd40ecdda92d705d211Erik                upgradeToVersion56(db);
1194a6357118c223d00ed722ecd40ecdda92d705d211Erik                oldVersion += 1;
1195a6357118c223d00ed722ecd40ecdda92d705d211Erik            }
1196a6357118c223d00ed722ecd40ecdda92d705d211Erik            if (oldVersion == 56) {
1197a6357118c223d00ed722ecd40ecdda92d705d211Erik                upgradeToVersion57(db);
1198a6357118c223d00ed722ecd40ecdda92d705d211Erik                oldVersion += 1;
1199a6357118c223d00ed722ecd40ecdda92d705d211Erik            }
1200a6357118c223d00ed722ecd40ecdda92d705d211Erik            if (oldVersion == 57) {
1201a6357118c223d00ed722ecd40ecdda92d705d211Erik                // Changes are undone upgrading to 60, so don't do anything.
1202a6357118c223d00ed722ecd40ecdda92d705d211Erik                oldVersion += 1;
1203a6357118c223d00ed722ecd40ecdda92d705d211Erik            }
1204a6357118c223d00ed722ecd40ecdda92d705d211Erik            if (oldVersion == 58) {
1205a6357118c223d00ed722ecd40ecdda92d705d211Erik                upgradeToVersion59(db);
1206a6357118c223d00ed722ecd40ecdda92d705d211Erik                oldVersion += 1;
1207a6357118c223d00ed722ecd40ecdda92d705d211Erik            }
1208a6357118c223d00ed722ecd40ecdda92d705d211Erik            if (oldVersion == 59) {
1209a6357118c223d00ed722ecd40ecdda92d705d211Erik                upgradeToVersion60(db);
12102cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                createEventsView = true;
1211a6357118c223d00ed722ecd40ecdda92d705d211Erik                oldVersion += 1;
1212a6357118c223d00ed722ecd40ecdda92d705d211Erik            }
1213a6357118c223d00ed722ecd40ecdda92d705d211Erik            if (oldVersion == 60) {
1214a6357118c223d00ed722ecd40ecdda92d705d211Erik                upgradeToVersion61(db);
1215a6357118c223d00ed722ecd40ecdda92d705d211Erik                oldVersion += 1;
1216a6357118c223d00ed722ecd40ecdda92d705d211Erik            }
1217a6357118c223d00ed722ecd40ecdda92d705d211Erik            if (oldVersion == 61) {
1218a6357118c223d00ed722ecd40ecdda92d705d211Erik                upgradeToVersion62(db);
1219a6357118c223d00ed722ecd40ecdda92d705d211Erik                oldVersion += 1;
1220a6357118c223d00ed722ecd40ecdda92d705d211Erik            }
1221a6357118c223d00ed722ecd40ecdda92d705d211Erik            if (oldVersion == 62) {
12222cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                createEventsView = true;
1223a6357118c223d00ed722ecd40ecdda92d705d211Erik                oldVersion += 1;
1224a6357118c223d00ed722ecd40ecdda92d705d211Erik            }
1225a6357118c223d00ed722ecd40ecdda92d705d211Erik            if (oldVersion == 63) {
1226a6357118c223d00ed722ecd40ecdda92d705d211Erik                upgradeToVersion64(db);
1227a6357118c223d00ed722ecd40ecdda92d705d211Erik                oldVersion += 1;
1228a6357118c223d00ed722ecd40ecdda92d705d211Erik            }
1229a6357118c223d00ed722ecd40ecdda92d705d211Erik            if (oldVersion == 64) {
12302cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                createEventsView = true;
1231a6357118c223d00ed722ecd40ecdda92d705d211Erik                oldVersion += 1;
1232a6357118c223d00ed722ecd40ecdda92d705d211Erik            }
1233a6357118c223d00ed722ecd40ecdda92d705d211Erik            if (oldVersion == 65) {
1234a6357118c223d00ed722ecd40ecdda92d705d211Erik                upgradeToVersion66(db);
1235a6357118c223d00ed722ecd40ecdda92d705d211Erik                oldVersion += 1;
1236a6357118c223d00ed722ecd40ecdda92d705d211Erik            }
12371599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio            if (oldVersion == 66) {
1238679d544f38aa33d00c12884b987d8f8af2a6a6d3Fabrice Di Meglio                // Changes are done thru recreateMetaDataAndInstances() method
12391599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio                oldVersion += 1;
12401599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio            }
1241679d544f38aa33d00c12884b987d8f8af2a6a6d3Fabrice Di Meglio            if (recreateMetaDataAndInstances) {
12422cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                recreateMetaDataAndInstances67(db);
1243679d544f38aa33d00c12884b987d8f8af2a6a6d3Fabrice Di Meglio            }
124443b3eba05ef67bdd4b0a2b285b6ed2b377c136c5Fabrice Di Meglio            if (oldVersion == 67 || oldVersion == 68) {
1245e3730b9dce00439666e7ef324a28263a0ee92032Erik                upgradeToVersion69(db);
1246e3730b9dce00439666e7ef324a28263a0ee92032Erik                oldVersion = 69;
12477b40dde3168f4af2c757cb43955aa3bfe1668666Erik            }
1248b492524403ca34b0cb03bfad6456909494479925Fabrice Di Meglio            // 69. 70 are for Froyo/old Gingerbread only and 100s are for Gingerbread only
1249b492524403ca34b0cb03bfad6456909494479925Fabrice Di Meglio            // 70 and 71 have been for Honeycomb but no more used
1250b492524403ca34b0cb03bfad6456909494479925Fabrice Di Meglio            // 72 and 73 and 74 were for Honeycomb only but are considered as obsolete for enabling
1251b492524403ca34b0cb03bfad6456909494479925Fabrice Di Meglio            // room for Froyo version numbers
1252b492524403ca34b0cb03bfad6456909494479925Fabrice Di Meglio            if(oldVersion == 69) {
1253315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio                upgradeToVersion200(db);
12542cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                createEventsView = true;
1255315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio                oldVersion = 200;
125643b3eba05ef67bdd4b0a2b285b6ed2b377c136c5Fabrice Di Meglio            }
1257b492524403ca34b0cb03bfad6456909494479925Fabrice Di Meglio            if (oldVersion == 70) {
1258b492524403ca34b0cb03bfad6456909494479925Fabrice Di Meglio                upgradeToVersion200(db);
1259b492524403ca34b0cb03bfad6456909494479925Fabrice Di Meglio                oldVersion = 200;
1260b492524403ca34b0cb03bfad6456909494479925Fabrice Di Meglio            }
1261b492524403ca34b0cb03bfad6456909494479925Fabrice Di Meglio            if (oldVersion == 100) {
12627544af675ce2fd78f33198e5e9194f2bc7bd129fAndy McFadden                // note we skip past v101 and v102
1263b492524403ca34b0cb03bfad6456909494479925Fabrice Di Meglio                upgradeToVersion200(db);
1264b492524403ca34b0cb03bfad6456909494479925Fabrice Di Meglio                oldVersion = 200;
1265c59a6b5d8ff6b941fc44e9181e668fe0ec7df088Fabrice Di Meglio            }
1266315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio            boolean need203Update = true;
12677544af675ce2fd78f33198e5e9194f2bc7bd129fAndy McFadden            if (oldVersion == 101 || oldVersion == 102) {
12687544af675ce2fd78f33198e5e9194f2bc7bd129fAndy McFadden                // v101 is v100 plus updateCalendarCacheTableTo203().
12697544af675ce2fd78f33198e5e9194f2bc7bd129fAndy McFadden                // v102 is v101 with Event._id changed to autoincrement.
12707544af675ce2fd78f33198e5e9194f2bc7bd129fAndy McFadden                // Upgrade to 200 and skip the 203 update.
12717544af675ce2fd78f33198e5e9194f2bc7bd129fAndy McFadden                upgradeToVersion200(db);
1272315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio                oldVersion = 200;
1273315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio                need203Update = false;
1274315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio            }
1275b492524403ca34b0cb03bfad6456909494479925Fabrice Di Meglio            if (oldVersion == 200) {
1276b492524403ca34b0cb03bfad6456909494479925Fabrice Di Meglio                upgradeToVersion201(db);
12777e7329964ddd60c98e93a7eda18b68944a630382Fabrice Di Meglio                oldVersion += 1;
12787e7329964ddd60c98e93a7eda18b68944a630382Fabrice Di Meglio            }
1279b492524403ca34b0cb03bfad6456909494479925Fabrice Di Meglio            if (oldVersion == 201) {
1280b492524403ca34b0cb03bfad6456909494479925Fabrice Di Meglio                upgradeToVersion202(db);
12812cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                createEventsView = true;
1282b492524403ca34b0cb03bfad6456909494479925Fabrice Di Meglio                oldVersion += 1;
1283b492524403ca34b0cb03bfad6456909494479925Fabrice Di Meglio            }
12847544af675ce2fd78f33198e5e9194f2bc7bd129fAndy McFadden            if (oldVersion == 202) {
12857544af675ce2fd78f33198e5e9194f2bc7bd129fAndy McFadden                if (need203Update) {
12867544af675ce2fd78f33198e5e9194f2bc7bd129fAndy McFadden                    upgradeToVersion203(db);
12877544af675ce2fd78f33198e5e9194f2bc7bd129fAndy McFadden                }
1288315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio                oldVersion += 1;
1289315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio            }
1290c4d44fd028e7f5f44f46439c3410dab3456e6d3fFabrice Di Meglio            if (oldVersion == 203) {
12912cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                createEventsView = true;
1292c4d44fd028e7f5f44f46439c3410dab3456e6d3fFabrice Di Meglio                oldVersion += 1;
1293c4d44fd028e7f5f44f46439c3410dab3456e6d3fFabrice Di Meglio            }
12947544af675ce2fd78f33198e5e9194f2bc7bd129fAndy McFadden            if (oldVersion == 206) {
12957544af675ce2fd78f33198e5e9194f2bc7bd129fAndy McFadden                // v206 exists only in HC (change Event._id to autoincrement).  Otherwise
12967544af675ce2fd78f33198e5e9194f2bc7bd129fAndy McFadden                // identical to v204, so back it up and let the upgrade path continue.
12977544af675ce2fd78f33198e5e9194f2bc7bd129fAndy McFadden                oldVersion -= 2;
12987544af675ce2fd78f33198e5e9194f2bc7bd129fAndy McFadden            }
12994067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden            if (oldVersion == 204) {
1300c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                // This is an ICS update, all following use 300+ versions.
13014067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                upgradeToVersion205(db);
13024067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                createEventsView = true;
13034067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                oldVersion += 1;
13044067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden            }
1305c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik            if (oldVersion == 205) {
1306c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                // Move ICS updates to 300 range
1307c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                upgradeToVersion300(db);
1308c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                createEventsView = true;
1309c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                oldVersion = 300;
1310c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik            }
131134c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik            if (oldVersion == 300) {
131234c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik                upgradeToVersion301(db);
131334c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik                createEventsView = true;
131434c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik                oldVersion++;
131534c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik            }
1316da641c374b00946f37bfe00e53bb292f4e0103d8RoboErik            if (oldVersion == 301) {
1317da641c374b00946f37bfe00e53bb292f4e0103d8RoboErik                upgradeToVersion302(db);
1318da641c374b00946f37bfe00e53bb292f4e0103d8RoboErik                oldVersion++;
1319da641c374b00946f37bfe00e53bb292f4e0103d8RoboErik            }
1320fa332ecedc0c340109811552407142f6e4f600b2RoboErik            if (oldVersion == 302) {
1321fa332ecedc0c340109811552407142f6e4f600b2RoboErik                upgradeToVersion303(db);
1322fa332ecedc0c340109811552407142f6e4f600b2RoboErik                oldVersion++;
1323fa332ecedc0c340109811552407142f6e4f600b2RoboErik                createEventsView = true;
1324fa332ecedc0c340109811552407142f6e4f600b2RoboErik            }
13259ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert            if (oldVersion == 303) {
13269ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                upgradeToVersion304(db);
13279ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                oldVersion++;
13289ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                createEventsView = true;
13299ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert            }
133002f97c538fc46a08d857d2c807c76fd0eec12493RoboErik            if (oldVersion == 304) {
133102f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                upgradeToVersion305(db);
133202f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                oldVersion++;
133302f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                createEventsView = true;
133402f97c538fc46a08d857d2c807c76fd0eec12493RoboErik            }
1335470aa5bc291ca33d51dda356f38ac2954026da9aAlon Albert            if (oldVersion == 305) {
1336470aa5bc291ca33d51dda356f38ac2954026da9aAlon Albert                upgradeToVersion306(db);
1337470aa5bc291ca33d51dda356f38ac2954026da9aAlon Albert                // force a sync to update edit url and etag
1338470aa5bc291ca33d51dda356f38ac2954026da9aAlon Albert                scheduleSync(null /* all accounts */, false, null);
1339470aa5bc291ca33d51dda356f38ac2954026da9aAlon Albert                oldVersion++;
1340470aa5bc291ca33d51dda356f38ac2954026da9aAlon Albert            }
1341935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            if (oldVersion == 306) {
1342935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden                upgradeToVersion307(db);
1343935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden                oldVersion++;
1344935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            }
13452f251c778c06d21ed7693a70f4a1268ff929242eRoboErik            if (oldVersion == 307) {
13462f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                upgradeToVersion308(db);
13472f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                oldVersion++;
13482f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                createEventsView = true;
13492f251c778c06d21ed7693a70f4a1268ff929242eRoboErik            }
13502cff10f1a005bd7302245d4c680cf851193c3a97RoboErik            if (createEventsView) {
13512cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                createEventsView(db);
13522cff10f1a005bd7302245d4c680cf851193c3a97RoboErik            }
1353b492524403ca34b0cb03bfad6456909494479925Fabrice Di Meglio            if (oldVersion != DATABASE_VERSION) {
1354b492524403ca34b0cb03bfad6456909494479925Fabrice Di Meglio                Log.e(TAG, "Need to recreate Calendar schema because of "
1355b492524403ca34b0cb03bfad6456909494479925Fabrice Di Meglio                        + "unknown Calendar database version: " + oldVersion);
1356b492524403ca34b0cb03bfad6456909494479925Fabrice Di Meglio                dropTables(db);
1357b492524403ca34b0cb03bfad6456909494479925Fabrice Di Meglio                bootstrapDB(db);
1358b492524403ca34b0cb03bfad6456909494479925Fabrice Di Meglio                oldVersion = DATABASE_VERSION;
1359935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            } else {
1360935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden                removeOrphans(db);
1361b492524403ca34b0cb03bfad6456909494479925Fabrice Di Meglio            }
1362a6357118c223d00ed722ecd40ecdda92d705d211Erik        } catch (SQLiteException e) {
13637544af675ce2fd78f33198e5e9194f2bc7bd129fAndy McFadden            Log.e(TAG, "onUpgrade: SQLiteException, recreating db. ", e);
13647544af675ce2fd78f33198e5e9194f2bc7bd129fAndy McFadden            Log.e(TAG, "(oldVersion was " + oldVersion + ")");
1365a6357118c223d00ed722ecd40ecdda92d705d211Erik            dropTables(db);
1366a6357118c223d00ed722ecd40ecdda92d705d211Erik            bootstrapDB(db);
1367a6357118c223d00ed722ecd40ecdda92d705d211Erik            return; // this was lossy
1368bf897b03effb752368a98cfb89e6b90cfdde50fcMarc Blank        }
1369c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik
13707544af675ce2fd78f33198e5e9194f2bc7bd129fAndy McFadden        long endWhen = System.nanoTime();
13717544af675ce2fd78f33198e5e9194f2bc7bd129fAndy McFadden        Log.d(TAG, "Calendar upgrade took " + ((endWhen - startWhen) / 1000000) + "ms");
13727544af675ce2fd78f33198e5e9194f2bc7bd129fAndy McFadden
1373c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik        /**
1374c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik         * db versions < 100 correspond to Froyo and earlier. Gingerbread bumped
1375c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik         * the db versioning to 100. Honeycomb bumped it to 200. ICS will begin
1376c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik         * in 300. At each major release we should jump to the next
1377c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik         * centiversion.
1378c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik         */
1379ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff    }
1380ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff
13811599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio    /**
1382679d544f38aa33d00c12884b987d8f8af2a6a6d3Fabrice Di Meglio     * If the user_version of the database if between 59 and 66 (those versions has been deployed
1383679d544f38aa33d00c12884b987d8f8af2a6a6d3Fabrice Di Meglio     * with no primary key for the CalendarMetaData table)
13841599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio     */
13852cff10f1a005bd7302245d4c680cf851193c3a97RoboErik    private void recreateMetaDataAndInstances67(SQLiteDatabase db) {
1386679d544f38aa33d00c12884b987d8f8af2a6a6d3Fabrice Di Meglio        // Recreate the CalendarMetaData table with correct primary key
13872cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("DROP TABLE CalendarMetaData;");
13882cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        createCalendarMetaDataTable59(db);
1389679d544f38aa33d00c12884b987d8f8af2a6a6d3Fabrice Di Meglio
1390679d544f38aa33d00c12884b987d8f8af2a6a6d3Fabrice Di Meglio        // Also clean the Instance table as this table may be corrupted
13912cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("DELETE FROM Instances;");
1392ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff    }
1393ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff
13947b40dde3168f4af2c757cb43955aa3bfe1668666Erik    private static boolean fixAllDayTime(Time time, String timezone, Long timeInMillis) {
13957b40dde3168f4af2c757cb43955aa3bfe1668666Erik        time.set(timeInMillis);
13967b40dde3168f4af2c757cb43955aa3bfe1668666Erik        if(time.hour != 0 || time.minute != 0 || time.second != 0) {
13977b40dde3168f4af2c757cb43955aa3bfe1668666Erik            time.hour = 0;
13987b40dde3168f4af2c757cb43955aa3bfe1668666Erik            time.minute = 0;
13997b40dde3168f4af2c757cb43955aa3bfe1668666Erik            time.second = 0;
14007b40dde3168f4af2c757cb43955aa3bfe1668666Erik            return true;
14017b40dde3168f4af2c757cb43955aa3bfe1668666Erik        }
14027b40dde3168f4af2c757cb43955aa3bfe1668666Erik        return false;
14037b40dde3168f4af2c757cb43955aa3bfe1668666Erik    }
14047b40dde3168f4af2c757cb43955aa3bfe1668666Erik
14057b40dde3168f4af2c757cb43955aa3bfe1668666Erik    @VisibleForTesting
14062f251c778c06d21ed7693a70f4a1268ff929242eRoboErik    void upgradeToVersion308(SQLiteDatabase db) {
14072f251c778c06d21ed7693a70f4a1268ff929242eRoboErik        /*
14082f251c778c06d21ed7693a70f4a1268ff929242eRoboErik         * Changes from version 307 to 308:
14092f251c778c06d21ed7693a70f4a1268ff929242eRoboErik         * - add Colors table to db
14102f251c778c06d21ed7693a70f4a1268ff929242eRoboErik         * - add eventColor_index to Events table
14112f251c778c06d21ed7693a70f4a1268ff929242eRoboErik         * - add calendar_color_index to Calendars table
14122f251c778c06d21ed7693a70f4a1268ff929242eRoboErik         * - add allowedAttendeeTypes to Calendars table
14132f251c778c06d21ed7693a70f4a1268ff929242eRoboErik         * - add allowedAvailability to Calendars table
14142f251c778c06d21ed7693a70f4a1268ff929242eRoboErik         */
14152f251c778c06d21ed7693a70f4a1268ff929242eRoboErik        createColorsTable(db);
14162f251c778c06d21ed7693a70f4a1268ff929242eRoboErik
14172f251c778c06d21ed7693a70f4a1268ff929242eRoboErik        db.execSQL("ALTER TABLE Calendars ADD COLUMN allowedAvailability TEXT DEFAULT '0,1';");
14182f251c778c06d21ed7693a70f4a1268ff929242eRoboErik        db.execSQL("ALTER TABLE Calendars ADD COLUMN allowedAttendeeTypes TEXT DEFAULT '0,1,2';");
14192f251c778c06d21ed7693a70f4a1268ff929242eRoboErik        db.execSQL("ALTER TABLE Calendars ADD COLUMN calendar_color_index TEXT;");
14202f251c778c06d21ed7693a70f4a1268ff929242eRoboErik        db.execSQL("ALTER TABLE Events ADD COLUMN eventColor_index TEXT;");
14212f251c778c06d21ed7693a70f4a1268ff929242eRoboErik
14222f251c778c06d21ed7693a70f4a1268ff929242eRoboErik        // Default Exchange calendars to be supporting the 'tentative'
14232f251c778c06d21ed7693a70f4a1268ff929242eRoboErik        // availability as well
14242f251c778c06d21ed7693a70f4a1268ff929242eRoboErik        db.execSQL("UPDATE Calendars SET allowedAvailability='0,1,2' WHERE _id IN "
14252f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + "(SELECT _id FROM Calendars WHERE account_type='com.android.exchange');");
14262f251c778c06d21ed7693a70f4a1268ff929242eRoboErik
14272f251c778c06d21ed7693a70f4a1268ff929242eRoboErik        // Triggers to update the color stored in an event or a calendar when
14282f251c778c06d21ed7693a70f4a1268ff929242eRoboErik        // the color_index is changed.
14292f251c778c06d21ed7693a70f4a1268ff929242eRoboErik        createColorsTriggers(db);
14302f251c778c06d21ed7693a70f4a1268ff929242eRoboErik    }
14312f251c778c06d21ed7693a70f4a1268ff929242eRoboErik
14322f251c778c06d21ed7693a70f4a1268ff929242eRoboErik    @VisibleForTesting
1433935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden    void upgradeToVersion307(SQLiteDatabase db) {
1434935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden        /*
1435935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden         * Changes from version 306 to 307:
1436935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden         * - Changed _id field to AUTOINCREMENT
1437935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden         */
1438935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden        db.execSQL("ALTER TABLE Events RENAME TO Events_Backup;");
1439935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden        db.execSQL("DROP TRIGGER IF EXISTS events_cleanup_delete");
1440935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden        db.execSQL("DROP TRIGGER IF EXISTS original_sync_update");
1441935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden        db.execSQL("DROP INDEX IF EXISTS eventsCalendarIdIndex");
14422f251c778c06d21ed7693a70f4a1268ff929242eRoboErik        createEventsTable307(db);
1443935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden
1444935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden        String FIELD_LIST =
1445935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            "_id, " +
1446935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            "_sync_id, " +
1447935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            "dirty, " +
1448935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            "lastSynced," +
1449935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            "calendar_id, " +
1450935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            "title, " +
1451935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            "eventLocation, " +
1452935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            "description, " +
1453935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            "eventColor, " +
1454935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            "eventStatus, " +
1455935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            "selfAttendeeStatus, " +
1456935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            "dtstart, " +
1457935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            "dtend, " +
1458935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            "eventTimezone, " +
1459935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            "duration, " +
1460935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            "allDay, " +
1461935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            "accessLevel, " +
1462935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            "availability, " +
1463935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            "hasAlarm, " +
1464935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            "hasExtendedProperties, " +
1465935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            "rrule, " +
1466935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            "rdate, " +
1467935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            "exrule, " +
1468935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            "exdate, " +
1469935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            "original_id," +
1470935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            "original_sync_id, " +
1471935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            "originalInstanceTime, " +
1472935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            "originalAllDay, " +
1473935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            "lastDate, " +
1474935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            "hasAttendeeData, " +
1475935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            "guestsCanModify, " +
1476935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            "guestsCanInviteOthers, " +
1477935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            "guestsCanSeeGuests, " +
1478935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            "organizer, " +
1479935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            "deleted, " +
1480935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            "eventEndTimezone, " +
1481935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            "sync_data1," +
1482935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            "sync_data2," +
1483935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            "sync_data3," +
1484935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            "sync_data4," +
1485935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            "sync_data5," +
1486935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            "sync_data6," +
1487935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            "sync_data7," +
1488935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            "sync_data8," +
1489935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            "sync_data9," +
1490935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden            "sync_data10 ";
1491935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden
1492935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden        // copy fields from old to new
1493935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden        db.execSQL("INSERT INTO Events (" + FIELD_LIST + ") SELECT " + FIELD_LIST +
1494935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden                "FROM Events_Backup;");
1495935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden
1496935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden        db.execSQL("DROP TABLE Events_Backup;");
1497935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden
1498935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden        // Trigger to remove data tied to an event when we delete that event.
1499935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden        db.execSQL("CREATE TRIGGER events_cleanup_delete DELETE ON " + Tables.EVENTS + " " +
1500935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden                "BEGIN " + EVENTS_CLEANUP_TRIGGER_SQL + "END");
1501935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden
1502935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden        // Trigger to update exceptions when an original event updates its
1503935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden        // _sync_id
1504935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden        db.execSQL(CREATE_SYNC_ID_UPDATE_TRIGGER);
1505935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden    }
1506935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden
1507935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden    @VisibleForTesting
1508470aa5bc291ca33d51dda356f38ac2954026da9aAlon Albert    void upgradeToVersion306(SQLiteDatabase db) {
1509470aa5bc291ca33d51dda356f38ac2954026da9aAlon Albert        /*
1510470aa5bc291ca33d51dda356f38ac2954026da9aAlon Albert        * The following changes are for google.com accounts only.
1511470aa5bc291ca33d51dda356f38ac2954026da9aAlon Albert        *
1512470aa5bc291ca33d51dda356f38ac2954026da9aAlon Albert        * Change event id's from ".../private/full/... to .../events/...
1513470aa5bc291ca33d51dda356f38ac2954026da9aAlon Albert        * Set Calendars.canPartiallyUpdate to 1 to support partial updates
1514470aa5bc291ca33d51dda356f38ac2954026da9aAlon Albert        * Nuke sync state so we re-sync with a fresh etag and edit url
15153ac8148cdc79bde4b009ccb6a9ffda77bdb547d3Andy McFadden        *
15163ac8148cdc79bde4b009ccb6a9ffda77bdb547d3Andy McFadden        * We need to drop the original_sync_update trigger because it fires whenever the
15173ac8148cdc79bde4b009ccb6a9ffda77bdb547d3Andy McFadden        * sync_id field is touched, and dramatically slows this operation.
1518470aa5bc291ca33d51dda356f38ac2954026da9aAlon Albert        */
15193ac8148cdc79bde4b009ccb6a9ffda77bdb547d3Andy McFadden        db.execSQL("DROP TRIGGER IF EXISTS original_sync_update");
1520470aa5bc291ca33d51dda356f38ac2954026da9aAlon Albert        db.execSQL("UPDATE Events SET "
1521470aa5bc291ca33d51dda356f38ac2954026da9aAlon Albert                + "_sync_id = REPLACE(_sync_id, '/private/full/', '/events/'), "
1522470aa5bc291ca33d51dda356f38ac2954026da9aAlon Albert                + "original_sync_id = REPLACE(original_sync_id, '/private/full/', '/events/') "
1523470aa5bc291ca33d51dda356f38ac2954026da9aAlon Albert                + "WHERE _id IN (SELECT Events._id FROM Events "
1524470aa5bc291ca33d51dda356f38ac2954026da9aAlon Albert                +    "JOIN Calendars ON Events.calendar_id = Calendars._id "
1525470aa5bc291ca33d51dda356f38ac2954026da9aAlon Albert                +    "WHERE account_type = 'com.google')"
1526470aa5bc291ca33d51dda356f38ac2954026da9aAlon Albert        );
15273ac8148cdc79bde4b009ccb6a9ffda77bdb547d3Andy McFadden        db.execSQL(CREATE_SYNC_ID_UPDATE_TRIGGER);
1528470aa5bc291ca33d51dda356f38ac2954026da9aAlon Albert
1529470aa5bc291ca33d51dda356f38ac2954026da9aAlon Albert        db.execSQL("UPDATE Calendars SET canPartiallyUpdate = 1 WHERE account_type = 'com.google'");
1530470aa5bc291ca33d51dda356f38ac2954026da9aAlon Albert
1531470aa5bc291ca33d51dda356f38ac2954026da9aAlon Albert        db.execSQL("DELETE FROM _sync_state WHERE account_type = 'com.google'");
1532470aa5bc291ca33d51dda356f38ac2954026da9aAlon Albert    }
1533470aa5bc291ca33d51dda356f38ac2954026da9aAlon Albert
1534470aa5bc291ca33d51dda356f38ac2954026da9aAlon Albert    @VisibleForTesting
153502f97c538fc46a08d857d2c807c76fd0eec12493RoboErik    void upgradeToVersion305(SQLiteDatabase db) {
153602f97c538fc46a08d857d2c807c76fd0eec12493RoboErik        /*
153702f97c538fc46a08d857d2c807c76fd0eec12493RoboErik         * Changes from version 304 to 305:
153802f97c538fc46a08d857d2c807c76fd0eec12493RoboErik         * -Add CAL_SYNC columns up to 10
153902f97c538fc46a08d857d2c807c76fd0eec12493RoboErik         * -Rename Calendars.access_level to calendar_access_level
154002f97c538fc46a08d857d2c807c76fd0eec12493RoboErik         * -Rename calendars _sync_version to cal_sync7
154102f97c538fc46a08d857d2c807c76fd0eec12493RoboErik         * -Rename calendars _sync_time to cal_sync8
154202f97c538fc46a08d857d2c807c76fd0eec12493RoboErik         * -Rename displayName to calendar_displayName
154302f97c538fc46a08d857d2c807c76fd0eec12493RoboErik         * -Rename _sync_local_id to sync_data2
154402f97c538fc46a08d857d2c807c76fd0eec12493RoboErik         * -Rename htmlUri to sync_data3
154502f97c538fc46a08d857d2c807c76fd0eec12493RoboErik         * -Rename events _sync_version to sync_data4
154602f97c538fc46a08d857d2c807c76fd0eec12493RoboErik         * -Rename events _sync_time to sync_data5
154702f97c538fc46a08d857d2c807c76fd0eec12493RoboErik         * -Rename commentsUri to sync_data6
154802f97c538fc46a08d857d2c807c76fd0eec12493RoboErik         * -Migrate Events _sync_mark to sync_data8
154902f97c538fc46a08d857d2c807c76fd0eec12493RoboErik         * -Change sync_data2 from INTEGER to TEXT
155002f97c538fc46a08d857d2c807c76fd0eec12493RoboErik         * -Change sync_data8 from INTEGER to TEXT
155102f97c538fc46a08d857d2c807c76fd0eec12493RoboErik         * -Add SYNC_DATA columns up to 10
155202f97c538fc46a08d857d2c807c76fd0eec12493RoboErik         * -Add EVENT_COLOR to Events table
155302f97c538fc46a08d857d2c807c76fd0eec12493RoboErik         */
155402f97c538fc46a08d857d2c807c76fd0eec12493RoboErik
155502f97c538fc46a08d857d2c807c76fd0eec12493RoboErik        // rename old table, create new table with updated layout
155602f97c538fc46a08d857d2c807c76fd0eec12493RoboErik        db.execSQL("ALTER TABLE Calendars RENAME TO Calendars_Backup;");
155702f97c538fc46a08d857d2c807c76fd0eec12493RoboErik        db.execSQL("DROP TRIGGER IF EXISTS calendar_cleanup");
15582f251c778c06d21ed7693a70f4a1268ff929242eRoboErik        createCalendarsTable305(db);
155902f97c538fc46a08d857d2c807c76fd0eec12493RoboErik
156002f97c538fc46a08d857d2c807c76fd0eec12493RoboErik        // copy fields from old to new
156102f97c538fc46a08d857d2c807c76fd0eec12493RoboErik        db.execSQL("INSERT INTO Calendars (" +
156202f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "_id, " +
156302f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "account_name, " +
156402f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "account_type, " +
156502f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "_sync_id, " +
156602f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "cal_sync7, " +             // rename from _sync_version
156702f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "cal_sync8, " +             // rename from _sync_time
156802f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "dirty, " +
156902f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "name, " +
157002f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "calendar_displayName, " +  // rename from displayName
157102f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "calendar_color, " +
157202f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "calendar_access_level, " + // rename from access_level
157302f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "visible, " +
157402f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "sync_events, " +
157502f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "calendar_location, " +
157602f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "calendar_timezone, " +
157702f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "ownerAccount, " +
157802f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "canOrganizerRespond, " +
157902f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "canModifyTimeZone, " +
158002f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "maxReminders, " +
158102f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "allowedReminders, " +
158202f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "deleted, " +
158302f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "canPartiallyUpdate," +
158402f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "cal_sync1, " +
158502f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "cal_sync2, " +
158602f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "cal_sync3, " +
158702f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "cal_sync4, " +
158802f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "cal_sync5, " +
158902f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "cal_sync6) " +
159002f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "SELECT " +
159102f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "_id, " +
159202f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "account_name, " +
159302f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "account_type, " +
159402f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "_sync_id, " +
159502f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "_sync_version, " +
159602f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "_sync_time, " +
159702f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "dirty, " +
159802f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "name, " +
159902f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "displayName, " +
160002f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "calendar_color, " +
160102f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "access_level, " +
160202f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "visible, " +
160302f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "sync_events, " +
160402f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "calendar_location, " +
160502f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "calendar_timezone, " +
160602f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "ownerAccount, " +
160702f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "canOrganizerRespond, " +
160802f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "canModifyTimeZone, " +
160902f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "maxReminders, " +
161002f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "allowedReminders, " +
161102f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "deleted, " +
161202f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "canPartiallyUpdate," +
161302f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "cal_sync1, " +
161402f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "cal_sync2, " +
161502f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "cal_sync3, " +
161602f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "cal_sync4, " +
161702f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "cal_sync5, " +
161802f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "cal_sync6 " +
161902f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "FROM Calendars_Backup;");
162002f97c538fc46a08d857d2c807c76fd0eec12493RoboErik
162102f97c538fc46a08d857d2c807c76fd0eec12493RoboErik        // drop the old table
162202f97c538fc46a08d857d2c807c76fd0eec12493RoboErik        db.execSQL("DROP TABLE Calendars_Backup;");
162302f97c538fc46a08d857d2c807c76fd0eec12493RoboErik
162402f97c538fc46a08d857d2c807c76fd0eec12493RoboErik        db.execSQL("ALTER TABLE Events RENAME TO Events_Backup;");
162502f97c538fc46a08d857d2c807c76fd0eec12493RoboErik        db.execSQL("DROP TRIGGER IF EXISTS events_cleanup_delete");
162602f97c538fc46a08d857d2c807c76fd0eec12493RoboErik        db.execSQL("DROP INDEX IF EXISTS eventsCalendarIdIndex");
1627935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden        // 305 and 307 can share the same createEventsTable implementation, because the
1628935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden        // addition of "autoincrement" to _ID doesn't affect the upgrade path.  (Note that
1629935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden        // much older databases may also already have autoincrement set because the change
1630935132618f821883f101db31af24e6d4c2b1e82cAndy McFadden        // was back-ported.)
16312f251c778c06d21ed7693a70f4a1268ff929242eRoboErik        createEventsTable307(db);
163202f97c538fc46a08d857d2c807c76fd0eec12493RoboErik
163302f97c538fc46a08d857d2c807c76fd0eec12493RoboErik        // copy fields from old to new
163402f97c538fc46a08d857d2c807c76fd0eec12493RoboErik        db.execSQL("INSERT INTO Events (" +
163502f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "_id, " +
163602f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "_sync_id, " +
163702f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "sync_data4, " +        // renamed from _sync_version
163802f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "sync_data5, " +        // renamed from _sync_time
163902f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "sync_data2, " +        // renamed from _sync_local_id
164002f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "dirty, " +
164102f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "sync_data8, " +        // renamed from _sync_mark
164202f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "calendar_id, " +
164302f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "sync_data3, " +        // renamed from htmlUri
164402f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "title, " +
164502f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "eventLocation, " +
164602f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "description, " +
164702f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "eventStatus, " +
164802f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "selfAttendeeStatus, " +
164902f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "sync_data6, " +        // renamed from commentsUri
165002f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "dtstart, " +
165102f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "dtend, " +
165202f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "eventTimezone, " +
165302f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "eventEndTimezone, " +
165402f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "duration, " +
165502f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "allDay, " +
165602f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "accessLevel, " +
165702f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "availability, " +
165802f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "hasAlarm, " +
165902f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "hasExtendedProperties, " +
166002f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "rrule, " +
166102f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "rdate, " +
166202f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "exrule, " +
166302f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "exdate, " +
166402f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "original_id," +
166502f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "original_sync_id, " +
166602f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "originalInstanceTime, " +
166702f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "originalAllDay, " +
166802f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "lastDate, " +
166902f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "hasAttendeeData, " +
167002f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "guestsCanModify, " +
167102f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "guestsCanInviteOthers, " +
167202f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "guestsCanSeeGuests, " +
167302f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "organizer, " +
167402f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "deleted, " +
167502f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "sync_data7," +
167602f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "lastSynced," +
167702f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "sync_data1) " +
167802f97c538fc46a08d857d2c807c76fd0eec12493RoboErik
167902f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "SELECT " +
168002f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "_id, " +
168102f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "_sync_id, " +
168202f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "_sync_version, " +
168302f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "_sync_time, " +
168402f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "_sync_local_id, " +
168502f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "dirty, " +
168602f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "_sync_mark, " +
168702f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "calendar_id, " +
168802f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "htmlUri, " +
168902f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "title, " +
169002f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "eventLocation, " +
169102f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "description, " +
169202f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "eventStatus, " +
169302f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "selfAttendeeStatus, " +
169402f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "commentsUri, " +
169502f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "dtstart, " +
169602f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "dtend, " +
169702f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "eventTimezone, " +
169802f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "eventEndTimezone, " +
169902f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "duration, " +
170002f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "allDay, " +
170102f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "accessLevel, " +
170202f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "availability, " +
170302f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "hasAlarm, " +
170402f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "hasExtendedProperties, " +
170502f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "rrule, " +
170602f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "rdate, " +
170702f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "exrule, " +
170802f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "exdate, " +
170902f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "original_id," +
171002f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "original_sync_id, " +
171102f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "originalInstanceTime, " +
171202f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "originalAllDay, " +
171302f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "lastDate, " +
171402f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "hasAttendeeData, " +
171502f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "guestsCanModify, " +
171602f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "guestsCanInviteOthers, " +
171702f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "guestsCanSeeGuests, " +
171802f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "organizer, " +
171902f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "deleted, " +
172002f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "sync_data7," +
172102f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "lastSynced," +
172202f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "sync_data1 " +
172302f97c538fc46a08d857d2c807c76fd0eec12493RoboErik
172402f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "FROM Events_Backup;"
172502f97c538fc46a08d857d2c807c76fd0eec12493RoboErik        );
172602f97c538fc46a08d857d2c807c76fd0eec12493RoboErik
172702f97c538fc46a08d857d2c807c76fd0eec12493RoboErik        db.execSQL("DROP TABLE Events_Backup;");
172802f97c538fc46a08d857d2c807c76fd0eec12493RoboErik
172902f97c538fc46a08d857d2c807c76fd0eec12493RoboErik        // Trigger to remove data tied to an event when we delete that event.
173002f97c538fc46a08d857d2c807c76fd0eec12493RoboErik        db.execSQL("CREATE TRIGGER events_cleanup_delete DELETE ON " + Tables.EVENTS + " " +
173102f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "BEGIN " +
173202f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                EVENTS_CLEANUP_TRIGGER_SQL +
173302f97c538fc46a08d857d2c807c76fd0eec12493RoboErik                "END");
173402f97c538fc46a08d857d2c807c76fd0eec12493RoboErik
173502f97c538fc46a08d857d2c807c76fd0eec12493RoboErik        // Trigger to update exceptions when an original event updates its
173602f97c538fc46a08d857d2c807c76fd0eec12493RoboErik        // _sync_id
173702f97c538fc46a08d857d2c807c76fd0eec12493RoboErik        db.execSQL(CREATE_SYNC_ID_UPDATE_TRIGGER);
173802f97c538fc46a08d857d2c807c76fd0eec12493RoboErik    }
173902f97c538fc46a08d857d2c807c76fd0eec12493RoboErik
174002f97c538fc46a08d857d2c807c76fd0eec12493RoboErik    @VisibleForTesting
17419ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert    void upgradeToVersion304(SQLiteDatabase db) {
17429ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert        /*
17439ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert         * Changes from version 303 to 304:
17449ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert         * - add canPartiallyUpdate to Calendars table
17459ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert         * - add sync_data7 to Calendars to Events table
17469ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert         * - add lastSynced to Calendars to Events table
17479ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert         */
17489ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert        db.execSQL("ALTER TABLE Calendars ADD COLUMN canPartiallyUpdate INTEGER DEFAULT 0;");
17499ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert        db.execSQL("ALTER TABLE Events ADD COLUMN sync_data7 TEXT;");
17509ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert        db.execSQL("ALTER TABLE Events ADD COLUMN lastSynced INTEGER DEFAULT 0;");
17519ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert    }
17529ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert
17539ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert    @VisibleForTesting
1754fa332ecedc0c340109811552407142f6e4f600b2RoboErik    void upgradeToVersion303(SQLiteDatabase db) {
1755fa332ecedc0c340109811552407142f6e4f600b2RoboErik        /*
1756fa332ecedc0c340109811552407142f6e4f600b2RoboErik         * Changes from version 302 to 303:
1757fa332ecedc0c340109811552407142f6e4f600b2RoboErik         * - change SYNCx columns to CAL_SYNCx
1758fa332ecedc0c340109811552407142f6e4f600b2RoboErik         */
1759fa332ecedc0c340109811552407142f6e4f600b2RoboErik
1760fa332ecedc0c340109811552407142f6e4f600b2RoboErik        // rename old table, create new table with updated layout
1761fa332ecedc0c340109811552407142f6e4f600b2RoboErik        db.execSQL("ALTER TABLE Calendars RENAME TO Calendars_Backup;");
1762fa332ecedc0c340109811552407142f6e4f600b2RoboErik        db.execSQL("DROP TRIGGER IF EXISTS calendar_cleanup");
17639ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert        createCalendarsTable303(db);
1764fa332ecedc0c340109811552407142f6e4f600b2RoboErik
1765fa332ecedc0c340109811552407142f6e4f600b2RoboErik        // copy fields from old to new
1766fa332ecedc0c340109811552407142f6e4f600b2RoboErik        db.execSQL("INSERT INTO Calendars (" +
1767fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "_id, " +
1768fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "account_name, " +
1769fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "account_type, " +
1770fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "_sync_id, " +
1771fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "_sync_version, " +
1772fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "_sync_time, " +
1773fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "dirty, " +
1774fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "name, " +
1775fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "displayName, " +
1776fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "calendar_color, " +
1777fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "access_level, " +
1778fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "visible, " +
1779fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "sync_events, " +
1780fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "calendar_location, " +
1781fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "calendar_timezone, " +
1782fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "ownerAccount, " +
1783fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "canOrganizerRespond, " +
1784fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "canModifyTimeZone, " +
1785fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "maxReminders, " +
1786fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "allowedReminders, " +
1787fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "deleted, " +
1788fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "cal_sync1, " +     // rename from sync1
1789fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "cal_sync2, " +     // rename from sync2
1790fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "cal_sync3, " +     // rename from sync3
1791fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "cal_sync4, " +     // rename from sync4
1792fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "cal_sync5, " +     // rename from sync5
1793fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "cal_sync6) " +     // rename from sync6
1794fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "SELECT " +
1795fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "_id, " +
1796fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "account_name, " +
1797fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "account_type, " +
1798fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "_sync_id, " +
1799fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "_sync_version, " +
1800fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "_sync_time, " +
1801fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "dirty, " +
1802fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "name, " +
1803fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "displayName, " +
1804fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "calendar_color, " +
1805fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "access_level, " +
1806fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "visible, " +
1807fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "sync_events, " +
1808fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "calendar_location, " +
1809fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "calendar_timezone, " +
1810fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "ownerAccount, " +
1811fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "canOrganizerRespond, " +
1812fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "canModifyTimeZone, " +
1813fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "maxReminders, " +
1814fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "allowedReminders," +
1815fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "deleted, " +
1816fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "sync1, " +
1817fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "sync2, " +
1818fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "sync3, " +
1819fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "sync4," +
1820fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "sync5," +
1821fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "sync6 " +
1822fa332ecedc0c340109811552407142f6e4f600b2RoboErik                "FROM Calendars_Backup;"
1823fa332ecedc0c340109811552407142f6e4f600b2RoboErik        );
1824fa332ecedc0c340109811552407142f6e4f600b2RoboErik
1825fa332ecedc0c340109811552407142f6e4f600b2RoboErik        // drop the old table
1826fa332ecedc0c340109811552407142f6e4f600b2RoboErik        db.execSQL("DROP TABLE Calendars_Backup;");
1827fa332ecedc0c340109811552407142f6e4f600b2RoboErik    }
1828fa332ecedc0c340109811552407142f6e4f600b2RoboErik
1829fa332ecedc0c340109811552407142f6e4f600b2RoboErik    @VisibleForTesting
1830da641c374b00946f37bfe00e53bb292f4e0103d8RoboErik    void upgradeToVersion302(SQLiteDatabase db) {
1831da641c374b00946f37bfe00e53bb292f4e0103d8RoboErik        /*
1832da641c374b00946f37bfe00e53bb292f4e0103d8RoboErik         * Changes from version 301 to 302
1833da641c374b00946f37bfe00e53bb292f4e0103d8RoboErik         * - Move Exchange eventEndTimezone values to SYNC_DATA1
1834da641c374b00946f37bfe00e53bb292f4e0103d8RoboErik         */
1835da641c374b00946f37bfe00e53bb292f4e0103d8RoboErik        db.execSQL("UPDATE Events SET sync_data1=eventEndTimezone WHERE calendar_id IN "
1836da641c374b00946f37bfe00e53bb292f4e0103d8RoboErik                + "(SELECT _id FROM Calendars WHERE account_type='com.android.exchange');");
1837da641c374b00946f37bfe00e53bb292f4e0103d8RoboErik
1838da641c374b00946f37bfe00e53bb292f4e0103d8RoboErik        db.execSQL("UPDATE Events SET eventEndTimezone=NULL WHERE calendar_id IN "
1839da641c374b00946f37bfe00e53bb292f4e0103d8RoboErik                + "(SELECT _id FROM Calendars WHERE account_type='com.android.exchange');");
1840da641c374b00946f37bfe00e53bb292f4e0103d8RoboErik    }
1841da641c374b00946f37bfe00e53bb292f4e0103d8RoboErik
1842da641c374b00946f37bfe00e53bb292f4e0103d8RoboErik    @VisibleForTesting
184334c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik    void upgradeToVersion301(SQLiteDatabase db) {
184434c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik        /*
184534c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik         * Changes from version 300 to 301
184634c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik         * - Added original_id column to Events table
184734c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik         * - Added triggers to keep original_id and original_sync_id in sync
184834c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik         */
184934c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik
185034c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik        db.execSQL("DROP TRIGGER IF EXISTS " + SYNC_ID_UPDATE_TRIGGER_NAME + ";");
185134c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik
185234c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik        db.execSQL("ALTER TABLE Events ADD COLUMN original_id INTEGER;");
185334c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik
185434c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik        // Fill in the original_id for all events that have an original_sync_id
185534c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik        db.execSQL("UPDATE Events set original_id=" +
185634c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik                "(SELECT Events2._id FROM Events AS Events2 " +
185734c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik                        "WHERE Events2._sync_id=Events.original_sync_id) " +
185834c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik                "WHERE Events.original_sync_id NOT NULL");
185934c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik        // Trigger to update exceptions when an original event updates its
186034c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik        // _sync_id
186134c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik        db.execSQL(CREATE_SYNC_ID_UPDATE_TRIGGER);
186234c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik    }
186334c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik
186434c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik    @VisibleForTesting
1865c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik    void upgradeToVersion300(SQLiteDatabase db) {
1866c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik
1867c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik        /*
1868c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik         * Changes from version 205 to 300:
1869c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik         * - rename _sync_account to account_name in Calendars table
1870c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik         * - remove _sync_account from Events table
1871c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik         * - rename _sync_account_type to account_type in Calendars table
1872c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik         * - remove _sync_account_type from Events table
1873c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik         * - rename _sync_dirty to dirty in Calendars/Events table
1874c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik         * - rename color to calendar_color in Calendars table
1875c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik         * - rename location to calendar_location in Calendars table
1876c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik         * - rename timezone to calendar_timezone in Calendars table
1877c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik         * - add allowedReminders in Calendars table
1878c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik         * - rename visibility to accessLevel in Events table
1879c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik         * - rename transparency to availability in Events table
1880c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik         * - rename originalEvent to original_sync_id in Events table
1881c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik         * - remove dtstart2 and dtend2 from Events table
1882c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik         * - rename syncAdapterData to sync_data1 in Events table
1883c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik         */
1884c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik
1885c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik        // rename old table, create new table with updated layout
1886c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik        db.execSQL("ALTER TABLE Calendars RENAME TO Calendars_Backup;");
188734c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik        db.execSQL("DROP TRIGGER IF EXISTS calendar_cleanup;");
1888fa332ecedc0c340109811552407142f6e4f600b2RoboErik        createCalendarsTable300(db);
1889c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik
1890c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik        // copy fields from old to new
1891c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik        db.execSQL("INSERT INTO Calendars (" +
1892c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "_id, " +
1893c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "account_name, " +          // rename from _sync_account
1894c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "account_type, " +          // rename from _sync_account_type
1895c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "_sync_id, " +
1896c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "_sync_version, " +
1897c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "_sync_time, " +
1898c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "dirty, " +                 // rename from _sync_dirty
1899c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "name, " +
1900c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "displayName, " +
1901c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "calendar_color, " +        // rename from color
1902c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "access_level, " +
1903c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "visible, " +
1904c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "sync_events, " +
1905c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "calendar_location, " +     // rename from location
1906c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "calendar_timezone, " +     // rename from timezone
1907c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "ownerAccount, " +
1908c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "canOrganizerRespond, " +
1909c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "canModifyTimeZone, " +
1910c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "maxReminders, " +
1911c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "allowedReminders," +
1912c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "deleted, " +
1913c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "sync1, " +
1914c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "sync2, " +
1915c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "sync3, " +
1916c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "sync4," +
1917c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "sync5," +
1918c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "sync6) " +
1919c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik
1920c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "SELECT " +
1921c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "_id, " +
1922c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "_sync_account, " +
1923c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "_sync_account_type, " +
1924c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "_sync_id, " +
1925c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "_sync_version, " +
1926c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "_sync_time, " +
1927c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "_sync_dirty, " +
1928c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "name, " +
1929c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "displayName, " +
1930c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "color, " +
1931c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "access_level, " +
1932c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "visible, " +
1933c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "sync_events, " +
1934c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "location, " +
1935c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "timezone, " +
1936c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "ownerAccount, " +
1937c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "canOrganizerRespond, " +
1938c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "canModifyTimeZone, " +
1939c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "maxReminders, " +
1940c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "'0,1,2,3'," +
1941c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "deleted, " +
1942c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "sync1, " +
1943c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "sync2, " +
1944c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "sync3, " +
1945c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "sync4, " +
1946c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "sync5, " +
1947c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "sync6 " +
1948c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "FROM Calendars_Backup;"
1949c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik        );
1950c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik
1951bf986d8deeeed9566e0badeba89d4800533cbca6Andy McFadden        /* expand the set of allowed reminders for Google calendars to include email */
1952bf986d8deeeed9566e0badeba89d4800533cbca6Andy McFadden        db.execSQL("UPDATE Calendars SET allowedReminders = '0,1,2' " +
1953bf986d8deeeed9566e0badeba89d4800533cbca6Andy McFadden                "WHERE account_type = 'com.google'");
1954bf986d8deeeed9566e0badeba89d4800533cbca6Andy McFadden
1955c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik        // drop the old table
1956c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik        db.execSQL("DROP TABLE Calendars_Backup;");
1957c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik
1958c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik        db.execSQL("ALTER TABLE Events RENAME TO Events_Backup;");
1959c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik        db.execSQL("DROP TRIGGER IF EXISTS events_insert");
1960c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik        db.execSQL("DROP TRIGGER IF EXISTS events_cleanup_delete");
1961c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik        db.execSQL("DROP INDEX IF EXISTS eventSyncAccountAndIdIndex");
1962c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik        db.execSQL("DROP INDEX IF EXISTS eventsCalendarIdIndex");
196334c32cd924eb8ee28381106b37044b78fd8cbc30RoboErik        createEventsTable300(db);
1964c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik
1965c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik        // copy fields from old to new
1966c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik        db.execSQL("INSERT INTO Events (" +
1967c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "_id, " +
1968c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "_sync_id, " +
1969c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "_sync_version, " +
1970c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "_sync_time, " +
1971c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "_sync_local_id, " +
1972c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "dirty, " +                 // renamed from _sync_dirty
1973c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "_sync_mark, " +
1974c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "calendar_id, " +
1975c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "htmlUri, " +
1976c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "title, " +
1977c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "eventLocation, " +
1978c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "description, " +
1979c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "eventStatus, " +
1980c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "selfAttendeeStatus, " +
1981c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "commentsUri, " +
1982c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "dtstart, " +
1983c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "dtend, " +
1984c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "eventTimezone, " +
1985c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "eventEndTimezone, " +      // renamed from eventTimezone2
1986c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "duration, " +
1987c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "allDay, " +
1988c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "accessLevel, " +           // renamed from visibility
1989c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "availability, " +          // renamed from transparency
1990c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "hasAlarm, " +
1991c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "hasExtendedProperties, " +
1992c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "rrule, " +
1993c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "rdate, " +
1994c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "exrule, " +
1995c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "exdate, " +
1996c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "original_sync_id, " +      // renamed from originalEvent
1997c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "originalInstanceTime, " +
1998c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "originalAllDay, " +
1999c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "lastDate, " +
2000c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "hasAttendeeData, " +
2001c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "guestsCanModify, " +
2002c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "guestsCanInviteOthers, " +
2003c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "guestsCanSeeGuests, " +
2004c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "organizer, " +
2005c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "deleted, " +
2006c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "sync_data1) " +             // renamed from syncAdapterData
2007c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik
2008c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "SELECT " +
2009c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "_id, " +
2010c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "_sync_id, " +
2011c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "_sync_version, " +
2012c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "_sync_time, " +
2013c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "_sync_local_id, " +
2014c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "_sync_dirty, " +
2015c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "_sync_mark, " +
2016c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "calendar_id, " +
2017c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "htmlUri, " +
2018c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "title, " +
2019c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "eventLocation, " +
2020c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "description, " +
2021c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "eventStatus, " +
2022c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "selfAttendeeStatus, " +
2023c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "commentsUri, " +
2024c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "dtstart, " +
2025c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "dtend, " +
2026c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "eventTimezone, " +
2027c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "eventTimezone2, " +
2028c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "duration, " +
2029c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "allDay, " +
2030c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "visibility, " +
2031c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "transparency, " +
2032c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "hasAlarm, " +
2033c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "hasExtendedProperties, " +
2034c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "rrule, " +
2035c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "rdate, " +
2036c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "exrule, " +
2037c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "exdate, " +
2038c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "originalEvent, " +
2039c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "originalInstanceTime, " +
2040c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "originalAllDay, " +
2041c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "lastDate, " +
2042c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "hasAttendeeData, " +
2043c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "guestsCanModify, " +
2044c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "guestsCanInviteOthers, " +
2045c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "guestsCanSeeGuests, " +
2046c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "organizer, " +
2047c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "deleted, " +
2048c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "syncAdapterData " +
2049c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik
2050c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "FROM Events_Backup;"
2051c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik        );
2052c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik
2053c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik        db.execSQL("DROP TABLE Events_Backup;");
2054c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik
2055c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik        // Trigger to remove data tied to an event when we delete that event.
2056c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik        db.execSQL("CREATE TRIGGER events_cleanup_delete DELETE ON " + Tables.EVENTS + " " +
2057c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "BEGIN " +
2058c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                EVENTS_CLEANUP_TRIGGER_SQL +
2059c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik                "END");
2060c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik
2061fa332ecedc0c340109811552407142f6e4f600b2RoboErik    }
2062c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik
2063c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik    @VisibleForTesting
20644067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden    void upgradeToVersion205(SQLiteDatabase db) {
20654067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden        /*
20664067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden         * Changes from version 204 to 205:
20674067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden         * - rename+reorder "_sync_mark" to "sync6" (and change type from INTEGER to TEXT)
20684067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden         * - rename "selected" to "visible"
20694067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden         * - rename "organizerCanRespond" to "canOrganizerRespond"
20704067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden         * - add "canModifyTimeZone"
20714067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden         * - add "maxReminders"
20724067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden         * - remove "_sync_local_id" (a/k/a _SYNC_DATA)
20734067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden         */
20744067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden
20754067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden        // rename old table, create new table with updated layout
20764067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden        db.execSQL("ALTER TABLE Calendars RENAME TO Calendars_Backup;");
20774067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden        db.execSQL("DROP TRIGGER IF EXISTS calendar_cleanup");
2078c8383567db3ade2aea28447ad3bd09ac3033bcd7RoboErik        createCalendarsTable205(db);
20794067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden
20804067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden        // copy fields from old to new
20814067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden        db.execSQL("INSERT INTO Calendars (" +
20824067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "_id, " +
20834067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "_sync_account, " +
20844067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "_sync_account_type, " +
20854067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "_sync_id, " +
20864067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "_sync_version, " +
20874067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "_sync_time, " +
20884067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "_sync_dirty, " +
20894067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "name, " +
20904067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "displayName, " +
20914067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "color, " +
20924067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "access_level, " +
20934067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "visible, " +                   // rename from "selected"
20944067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "sync_events, " +
20954067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "location, " +
20964067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "timezone, " +
20974067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "ownerAccount, " +
20984067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "canOrganizerRespond, " +       // rename from "organizerCanRespond"
20994067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "canModifyTimeZone, " +
21004067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "maxReminders, " +
21014067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "deleted, " +
21024067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "sync1, " +
21034067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "sync2, " +
21044067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "sync3, " +
21054067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "sync4," +
21064067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "sync5," +
21074067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "sync6) " +                     // rename/reorder from _sync_mark
21084067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "SELECT " +
21094067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "_id, " +
21104067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "_sync_account, " +
21114067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "_sync_account_type, " +
21124067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "_sync_id, " +
21134067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "_sync_version, " +
21144067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "_sync_time, " +
21154067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "_sync_dirty, " +
21164067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "name, " +
21174067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "displayName, " +
21184067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "color, " +
21194067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "access_level, " +
21204067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "selected, " +
21214067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "sync_events, " +
21224067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "location, " +
21234067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "timezone, " +
21244067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "ownerAccount, " +
21254067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "organizerCanRespond, " +
21264067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "1, " +
21274067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "5, " +
21284067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "deleted, " +
21294067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "sync1, " +
21304067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "sync2, " +
21314067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "sync3, " +
21324067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "sync4, " +
21334067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "sync5, " +
21344067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "_sync_mark " +
21354067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "FROM Calendars_Backup;"
21364067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden        );
21374067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden
21384067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden        // set these fields appropriately for Exchange events
21394067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden        db.execSQL("UPDATE Calendars SET canModifyTimeZone=0, maxReminders=1 " +
21404067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden                "WHERE _sync_account_type='com.android.exchange'");
21414067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden
21424067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden        // drop the old table
21434067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden        db.execSQL("DROP TABLE Calendars_Backup;");
21444067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden    }
21454067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden
21464067700dbedcf4c8a379c9ecba9b5603972b4607Andy McFadden    @VisibleForTesting
2147315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio    void upgradeToVersion203(SQLiteDatabase db) {
2148315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio        // Same as Gingerbread version 100
21492cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        Cursor cursor = db.rawQuery("SELECT value FROM CalendarCache WHERE key=?",
2150315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio                new String[] {"timezoneDatabaseVersion"});
2151315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio
2152315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio        String oldTimezoneDbVersion = null;
2153315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio        if (cursor != null && cursor.moveToNext()) {
215458313767dd0e7e3823c35ca61b40eddb9dd229bbFabrice Di Meglio            try {
215558313767dd0e7e3823c35ca61b40eddb9dd229bbFabrice Di Meglio                oldTimezoneDbVersion = cursor.getString(0);
215658313767dd0e7e3823c35ca61b40eddb9dd229bbFabrice Di Meglio            } finally {
215758313767dd0e7e3823c35ca61b40eddb9dd229bbFabrice Di Meglio                cursor.close();
215858313767dd0e7e3823c35ca61b40eddb9dd229bbFabrice Di Meglio            }
21593443e3ebeaa39e8415b43e7cf3b218caee554e9bFabrice Di Meglio            // Also clean the CalendarCache table
21602cff10f1a005bd7302245d4c680cf851193c3a97RoboErik            db.execSQL("DELETE FROM CalendarCache;");
2161315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio        }
21622cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        initCalendarCacheTable203(db, oldTimezoneDbVersion);
2163315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio
2164315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio        // Same as Gingerbread version 101
2165315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio        updateCalendarCacheTableTo203(db);
2166315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio    }
2167315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio
2168315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio    @VisibleForTesting
2169b492524403ca34b0cb03bfad6456909494479925Fabrice Di Meglio    void upgradeToVersion202(SQLiteDatabase db) {
21707e7329964ddd60c98e93a7eda18b68944a630382Fabrice Di Meglio        // We will drop the "hidden" column from the calendar schema and add the "sync5" column
21712cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("ALTER TABLE Calendars RENAME TO Calendars_Backup;");
21727e7329964ddd60c98e93a7eda18b68944a630382Fabrice Di Meglio
21737e7329964ddd60c98e93a7eda18b68944a630382Fabrice Di Meglio        db.execSQL("DROP TRIGGER IF EXISTS calendar_cleanup");
2174180076a810558478f55ade53ebef0a2ddfa6bbc0Andy McFadden        createCalendarsTable202(db);
21757e7329964ddd60c98e93a7eda18b68944a630382Fabrice Di Meglio
21767e7329964ddd60c98e93a7eda18b68944a630382Fabrice Di Meglio        // Populate the new Calendars table and put into the "sync5" column the value of the
21777e7329964ddd60c98e93a7eda18b68944a630382Fabrice Di Meglio        // old "hidden" column
21782cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("INSERT INTO Calendars (" +
21792cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_id, " +
21802cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_account, " +
21812cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_account_type, " +
21822cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_id, " +
21832cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_version, " +
21842cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_time, " +
21852cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_local_id, " +
21862cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_dirty, " +
21872cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_mark, " +
21882cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "name, " +
21892cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "displayName, " +
21902cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "color, " +
21912cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "access_level, " +
21922cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "selected, " +
21932cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "sync_events, " +
21942cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "location, " +
21952cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "timezone, " +
21962cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "ownerAccount, " +
21972cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "organizerCanRespond, " +
21982cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "deleted, " +
21992cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "sync1, " +
22002cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "sync2, " +
22012cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "sync3, " +
22022cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "sync4," +
22032cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "sync5) " +
22047e7329964ddd60c98e93a7eda18b68944a630382Fabrice Di Meglio                "SELECT " +
22052cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_id, " +
22062cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_account, " +
22072cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_account_type, " +
22082cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_id, " +
22092cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_version, " +
22102cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_time, " +
22112cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_local_id, " +
22122cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_dirty, " +
22132cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_mark, " +
22142cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "name, " +
22152cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "displayName, " +
22162cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "color, " +
22172cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "access_level, " +
22182cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "selected, " +
22192cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "sync_events, " +
22202cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "location, " +
22212cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "timezone, " +
22222cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "ownerAccount, " +
22232cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "organizerCanRespond, " +
22242cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "deleted, " +
22252cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "sync1, " +
22262cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "sync2, " +
22272cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "sync3, " +
22282cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "sync4, " +
22292cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "hidden " +
22302cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "FROM Calendars_Backup;"
22317e7329964ddd60c98e93a7eda18b68944a630382Fabrice Di Meglio        );
22327e7329964ddd60c98e93a7eda18b68944a630382Fabrice Di Meglio
22337e7329964ddd60c98e93a7eda18b68944a630382Fabrice Di Meglio        // Drop the backup table
22342cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("DROP TABLE Calendars_Backup;");
22357e7329964ddd60c98e93a7eda18b68944a630382Fabrice Di Meglio    }
22367e7329964ddd60c98e93a7eda18b68944a630382Fabrice Di Meglio
22377e7329964ddd60c98e93a7eda18b68944a630382Fabrice Di Meglio    @VisibleForTesting
2238b492524403ca34b0cb03bfad6456909494479925Fabrice Di Meglio    void upgradeToVersion201(SQLiteDatabase db) {
22392cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("ALTER TABLE Calendars ADD COLUMN sync4 TEXT;");
2240836bc8e9da32b8231f1b0d57be271730d7a5368dFabrice Di Meglio    }
2241836bc8e9da32b8231f1b0d57be271730d7a5368dFabrice Di Meglio
2242836bc8e9da32b8231f1b0d57be271730d7a5368dFabrice Di Meglio    @VisibleForTesting
2243b492524403ca34b0cb03bfad6456909494479925Fabrice Di Meglio    void upgradeToVersion200(SQLiteDatabase db) {
22441b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio        // we cannot use here a Calendar.Calendars,URL constant for "url" as we are trying to make
22451b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio        // it disappear so we are keeping the hardcoded name "url" in all the SQLs
22462cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("ALTER TABLE Calendars RENAME TO Calendars_Backup;");
22471b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio
22481fc162fc3a3bb466a39146cf59a8b51ec5d9de52Fabrice Di Meglio        db.execSQL("DROP TRIGGER IF EXISTS calendar_cleanup");
22492cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        createCalendarsTable200(db);
22501b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio
22511b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio        // Populate the new Calendars table except the SYNC2 / SYNC3 columns
22522cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("INSERT INTO Calendars (" +
22532cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_id, " +
22542cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_account, " +
22552cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_account_type, " +
22562cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_id, " +
22572cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_version, " +
22582cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_time, " +
22592cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_local_id, " +
22602cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_dirty, " +
22612cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_mark, " +
22622cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "name, " +
22632cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "displayName, " +
22642cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "color, " +
22652cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "access_level, " +
22662cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "selected, " +
22672cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "sync_events, " +
22682cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "location, " +
22692cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "timezone, " +
22702cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "ownerAccount, " +
22712cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "organizerCanRespond, " +
22722cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "deleted, " +
22732cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "sync1) " +
22741b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio                "SELECT " +
22752cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_id, " +
22762cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_account, " +
22772cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_account_type, " +
22782cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_id, " +
22792cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_version, " +
22802cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_time, " +
22812cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_local_id, " +
22822cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_dirty, " +
22832cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_mark, " +
22842cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "name, " +
22852cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "displayName, " +
22862cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "color, " +
22872cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "access_level, " +
22882cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "selected, " +
22892cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "sync_events, " +
22902cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "location, " +
22912cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "timezone, " +
22922cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "ownerAccount, " +
22932cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "organizerCanRespond, " +
22942cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "0, " +
22952cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "url " +
22962cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "FROM Calendars_Backup;"
22971b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio        );
22981b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio
22991b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio        // Populate SYNC2 and SYNC3 columns - SYNC1 represent the old "url" column
23001b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio        // We will need to iterate over all the "com.google" type of calendars
23012cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        String selectSql = "SELECT _id, url" +
23022cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                " FROM Calendars_Backup" +
23032cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                " WHERE _sync_account_type='com.google'" +
23041b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio                " AND url IS NOT NULL;";
23051b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio
23062cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        String updateSql = "UPDATE Calendars SET " +
23072cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "sync2=?, " + // edit Url
23082cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "sync3=? " + // self Url
23092cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "WHERE _id=?;";
23101b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio
23111b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio        Cursor cursor = db.rawQuery(selectSql, null /* selection args */);
23121b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio        if (cursor != null && cursor.getCount() > 0) {
23131b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio            try {
23141b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio                Object[] bindArgs = new Object[3];
2315c59a6b5d8ff6b941fc44e9181e668fe0ec7df088Fabrice Di Meglio
23161b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio                while (cursor.moveToNext()) {
23171b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio                    Long id = cursor.getLong(0);
23181b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio                    String url = cursor.getString(1);
23191b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio                    String selfUrl = getSelfUrlFromEventsUrl(url);
23201b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio                    String editUrl = getEditUrlFromEventsUrl(url);
232143b3eba05ef67bdd4b0a2b285b6ed2b377c136c5Fabrice Di Meglio
23221b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio                    bindArgs[0] = editUrl;
23231b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio                    bindArgs[1] = selfUrl;
23241b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio                    bindArgs[2] = id;
232543b3eba05ef67bdd4b0a2b285b6ed2b377c136c5Fabrice Di Meglio
23261b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio                    db.execSQL(updateSql, bindArgs);
23271b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio                }
23281b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio            } finally {
23291b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio                cursor.close();
23301b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio            }
23311b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio        }
23321b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio
23331b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio        // Drop the backup table
23342cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("DROP TABLE Calendars_Backup;");
233543b3eba05ef67bdd4b0a2b285b6ed2b377c136c5Fabrice Di Meglio    }
233643b3eba05ef67bdd4b0a2b285b6ed2b377c136c5Fabrice Di Meglio
233743b3eba05ef67bdd4b0a2b285b6ed2b377c136c5Fabrice Di Meglio    @VisibleForTesting
2338e3730b9dce00439666e7ef324a28263a0ee92032Erik    static void upgradeToVersion69(SQLiteDatabase db) {
23397b40dde3168f4af2c757cb43955aa3bfe1668666Erik        // Clean up allDay events which could be in an invalid state from an earlier version
23407b40dde3168f4af2c757cb43955aa3bfe1668666Erik        // Some allDay events had hour, min, sec not set to zero, which throws elsewhere. This
2341e3730b9dce00439666e7ef324a28263a0ee92032Erik        // will go through the allDay events and make sure they have proper values and are in the
2342e3730b9dce00439666e7ef324a28263a0ee92032Erik        // correct timezone. Verifies that dtstart and dtend are in UTC and at midnight, that
2343e3730b9dce00439666e7ef324a28263a0ee92032Erik        // eventTimezone is set to UTC, tries to make sure duration is in days, and that dtstart2
2344e3730b9dce00439666e7ef324a28263a0ee92032Erik        // and dtend2 are at midnight in their timezone.
23452cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        final String sql = "SELECT _id, " +
23462cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "dtstart, " +
23472cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "dtend, " +
23482cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "duration, " +
23492cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "dtstart2, " +
23502cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "dtend2, " +
23512cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "eventTimezone, " +
23522cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "eventTimezone2, " +
23532cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "rrule " +
23542cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "FROM Events " +
23552cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "WHERE allDay=?";
23567cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        Cursor cursor = db.rawQuery(sql, new String[] {"1"});
23577b40dde3168f4af2c757cb43955aa3bfe1668666Erik        if (cursor != null) {
23587b40dde3168f4af2c757cb43955aa3bfe1668666Erik            try {
23597b40dde3168f4af2c757cb43955aa3bfe1668666Erik                String timezone;
23607b40dde3168f4af2c757cb43955aa3bfe1668666Erik                String timezone2;
23617b40dde3168f4af2c757cb43955aa3bfe1668666Erik                String duration;
23627b40dde3168f4af2c757cb43955aa3bfe1668666Erik                Long dtstart;
23637b40dde3168f4af2c757cb43955aa3bfe1668666Erik                Long dtstart2;
23647b40dde3168f4af2c757cb43955aa3bfe1668666Erik                Long dtend;
23657b40dde3168f4af2c757cb43955aa3bfe1668666Erik                Long dtend2;
23667b40dde3168f4af2c757cb43955aa3bfe1668666Erik                Time time = new Time();
23677b40dde3168f4af2c757cb43955aa3bfe1668666Erik                Long id;
2368e3730b9dce00439666e7ef324a28263a0ee92032Erik                // some things need to be in utc so we call this frequently, cache to make faster
2369e3730b9dce00439666e7ef324a28263a0ee92032Erik                final String utc = Time.TIMEZONE_UTC;
23707b40dde3168f4af2c757cb43955aa3bfe1668666Erik                while (cursor.moveToNext()) {
23717b40dde3168f4af2c757cb43955aa3bfe1668666Erik                    String rrule = cursor.getString(8);
23727b40dde3168f4af2c757cb43955aa3bfe1668666Erik                    id = cursor.getLong(0);
23737b40dde3168f4af2c757cb43955aa3bfe1668666Erik                    dtstart = cursor.getLong(1);
23747b40dde3168f4af2c757cb43955aa3bfe1668666Erik                    dtstart2 = null;
23757b40dde3168f4af2c757cb43955aa3bfe1668666Erik                    timezone = cursor.getString(6);
23767b40dde3168f4af2c757cb43955aa3bfe1668666Erik                    timezone2 = cursor.getString(7);
23777b40dde3168f4af2c757cb43955aa3bfe1668666Erik                    duration = cursor.getString(3);
23787b40dde3168f4af2c757cb43955aa3bfe1668666Erik
2379e3730b9dce00439666e7ef324a28263a0ee92032Erik                    if (TextUtils.isEmpty(rrule)) {
23807b40dde3168f4af2c757cb43955aa3bfe1668666Erik                        // For non-recurring events dtstart and dtend should both have values
23817b40dde3168f4af2c757cb43955aa3bfe1668666Erik                        // and duration should be null.
23827b40dde3168f4af2c757cb43955aa3bfe1668666Erik                        dtend = cursor.getLong(2);
23837b40dde3168f4af2c757cb43955aa3bfe1668666Erik                        dtend2 = null;
23847b40dde3168f4af2c757cb43955aa3bfe1668666Erik                        // Since we made all three of these at the same time if timezone2 exists
23857b40dde3168f4af2c757cb43955aa3bfe1668666Erik                        // so should dtstart2 and dtend2.
23867b40dde3168f4af2c757cb43955aa3bfe1668666Erik                        if(!TextUtils.isEmpty(timezone2)) {
23877b40dde3168f4af2c757cb43955aa3bfe1668666Erik                            dtstart2 = cursor.getLong(4);
23887b40dde3168f4af2c757cb43955aa3bfe1668666Erik                            dtend2 = cursor.getLong(5);
23897b40dde3168f4af2c757cb43955aa3bfe1668666Erik                        }
23907b40dde3168f4af2c757cb43955aa3bfe1668666Erik
23917b40dde3168f4af2c757cb43955aa3bfe1668666Erik                        boolean update = false;
2392e3730b9dce00439666e7ef324a28263a0ee92032Erik                        if (!TextUtils.equals(timezone, utc)) {
2393e3730b9dce00439666e7ef324a28263a0ee92032Erik                            update = true;
2394e3730b9dce00439666e7ef324a28263a0ee92032Erik                            timezone = utc;
2395e3730b9dce00439666e7ef324a28263a0ee92032Erik                        }
2396e3730b9dce00439666e7ef324a28263a0ee92032Erik
2397e3730b9dce00439666e7ef324a28263a0ee92032Erik                        time.clear(timezone);
2398e3730b9dce00439666e7ef324a28263a0ee92032Erik                        update |= fixAllDayTime(time, timezone, dtstart);
23997b40dde3168f4af2c757cb43955aa3bfe1668666Erik                        dtstart = time.normalize(false);
2400e3730b9dce00439666e7ef324a28263a0ee92032Erik
2401e3730b9dce00439666e7ef324a28263a0ee92032Erik                        time.clear(timezone);
24027b40dde3168f4af2c757cb43955aa3bfe1668666Erik                        update |= fixAllDayTime(time, timezone, dtend);
24037b40dde3168f4af2c757cb43955aa3bfe1668666Erik                        dtend = time.normalize(false);
24047b40dde3168f4af2c757cb43955aa3bfe1668666Erik
24057b40dde3168f4af2c757cb43955aa3bfe1668666Erik                        if (dtstart2 != null) {
2406e3730b9dce00439666e7ef324a28263a0ee92032Erik                            time.clear(timezone2);
24077b40dde3168f4af2c757cb43955aa3bfe1668666Erik                            update |= fixAllDayTime(time, timezone2, dtstart2);
24087b40dde3168f4af2c757cb43955aa3bfe1668666Erik                            dtstart2 = time.normalize(false);
24097b40dde3168f4af2c757cb43955aa3bfe1668666Erik                        }
24107b40dde3168f4af2c757cb43955aa3bfe1668666Erik
24117b40dde3168f4af2c757cb43955aa3bfe1668666Erik                        if (dtend2 != null) {
2412e3730b9dce00439666e7ef324a28263a0ee92032Erik                            time.clear(timezone2);
24137b40dde3168f4af2c757cb43955aa3bfe1668666Erik                            update |= fixAllDayTime(time, timezone2, dtend2);
24147b40dde3168f4af2c757cb43955aa3bfe1668666Erik                            dtend2 = time.normalize(false);
24157b40dde3168f4af2c757cb43955aa3bfe1668666Erik                        }
24167b40dde3168f4af2c757cb43955aa3bfe1668666Erik
24177b40dde3168f4af2c757cb43955aa3bfe1668666Erik                        if (!TextUtils.isEmpty(duration)) {
24187b40dde3168f4af2c757cb43955aa3bfe1668666Erik                            update = true;
24197b40dde3168f4af2c757cb43955aa3bfe1668666Erik                        }
24207b40dde3168f4af2c757cb43955aa3bfe1668666Erik
24217b40dde3168f4af2c757cb43955aa3bfe1668666Erik                        if (update) {
24227b40dde3168f4af2c757cb43955aa3bfe1668666Erik                            // enforce duration being null
24232cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                            db.execSQL("UPDATE Events SET " +
24242cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                                    "dtstart=?, " +
24252cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                                    "dtend=?, " +
24262cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                                    "dtstart2=?, " +
24272cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                                    "dtend2=?, " +
24282cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                                    "duration=?, " +
24292cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                                    "eventTimezone=?, " +
24302cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                                    "eventTimezone2=? " +
24312cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                                    "WHERE _id=?",
24327cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio                                    new Object[] {
24337cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio                                            dtstart,
24347cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio                                            dtend,
24357cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio                                            dtstart2,
24367cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio                                            dtend2,
24377cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio                                            null,
24387cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio                                            timezone,
24397cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio                                            timezone2,
24407cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio                                            id}
24417cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio                            );
24427b40dde3168f4af2c757cb43955aa3bfe1668666Erik                        }
24437b40dde3168f4af2c757cb43955aa3bfe1668666Erik
24447b40dde3168f4af2c757cb43955aa3bfe1668666Erik                    } else {
24457b40dde3168f4af2c757cb43955aa3bfe1668666Erik                        // For recurring events only dtstart and duration should be used.
24467b40dde3168f4af2c757cb43955aa3bfe1668666Erik                        // We ignore dtend since it will be overwritten if the event changes to a
24477b40dde3168f4af2c757cb43955aa3bfe1668666Erik                        // non-recurring event and won't be used otherwise.
24487b40dde3168f4af2c757cb43955aa3bfe1668666Erik                        if(!TextUtils.isEmpty(timezone2)) {
24497b40dde3168f4af2c757cb43955aa3bfe1668666Erik                            dtstart2 = cursor.getLong(4);
24507b40dde3168f4af2c757cb43955aa3bfe1668666Erik                        }
24517b40dde3168f4af2c757cb43955aa3bfe1668666Erik
24527b40dde3168f4af2c757cb43955aa3bfe1668666Erik                        boolean update = false;
2453e3730b9dce00439666e7ef324a28263a0ee92032Erik                        if (!TextUtils.equals(timezone, utc)) {
2454e3730b9dce00439666e7ef324a28263a0ee92032Erik                            update = true;
2455e3730b9dce00439666e7ef324a28263a0ee92032Erik                            timezone = utc;
2456e3730b9dce00439666e7ef324a28263a0ee92032Erik                        }
2457e3730b9dce00439666e7ef324a28263a0ee92032Erik
2458e3730b9dce00439666e7ef324a28263a0ee92032Erik                        time.clear(timezone);
2459e3730b9dce00439666e7ef324a28263a0ee92032Erik                        update |= fixAllDayTime(time, timezone, dtstart);
24607b40dde3168f4af2c757cb43955aa3bfe1668666Erik                        dtstart = time.normalize(false);
24617b40dde3168f4af2c757cb43955aa3bfe1668666Erik
24627b40dde3168f4af2c757cb43955aa3bfe1668666Erik                        if (dtstart2 != null) {
2463e3730b9dce00439666e7ef324a28263a0ee92032Erik                            time.clear(timezone2);
24647b40dde3168f4af2c757cb43955aa3bfe1668666Erik                            update |= fixAllDayTime(time, timezone2, dtstart2);
24657b40dde3168f4af2c757cb43955aa3bfe1668666Erik                            dtstart2 = time.normalize(false);
24667b40dde3168f4af2c757cb43955aa3bfe1668666Erik                        }
24677b40dde3168f4af2c757cb43955aa3bfe1668666Erik
24687b40dde3168f4af2c757cb43955aa3bfe1668666Erik                        if (TextUtils.isEmpty(duration)) {
24697b40dde3168f4af2c757cb43955aa3bfe1668666Erik                            // If duration was missing assume a 1 day duration
24707b40dde3168f4af2c757cb43955aa3bfe1668666Erik                            duration = "P1D";
24717b40dde3168f4af2c757cb43955aa3bfe1668666Erik                            update = true;
24727b40dde3168f4af2c757cb43955aa3bfe1668666Erik                        } else {
24737b40dde3168f4af2c757cb43955aa3bfe1668666Erik                            int len = duration.length();
24747b40dde3168f4af2c757cb43955aa3bfe1668666Erik                            // TODO fix durations in other formats as well
24757b40dde3168f4af2c757cb43955aa3bfe1668666Erik                            if (duration.charAt(0) == 'P' &&
24767b40dde3168f4af2c757cb43955aa3bfe1668666Erik                                    duration.charAt(len - 1) == 'S') {
24777b40dde3168f4af2c757cb43955aa3bfe1668666Erik                                int seconds = Integer.parseInt(duration.substring(1, len - 1));
24787b40dde3168f4af2c757cb43955aa3bfe1668666Erik                                int days = (seconds + DAY_IN_SECONDS - 1) / DAY_IN_SECONDS;
24797b40dde3168f4af2c757cb43955aa3bfe1668666Erik                                duration = "P" + days + "D";
24807b40dde3168f4af2c757cb43955aa3bfe1668666Erik                                update = true;
24817b40dde3168f4af2c757cb43955aa3bfe1668666Erik                            }
24827b40dde3168f4af2c757cb43955aa3bfe1668666Erik                        }
24837b40dde3168f4af2c757cb43955aa3bfe1668666Erik
24847b40dde3168f4af2c757cb43955aa3bfe1668666Erik                        if (update) {
24857b40dde3168f4af2c757cb43955aa3bfe1668666Erik                            // If there were other problems also enforce dtend being null
24862cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                            db.execSQL("UPDATE Events SET " +
24872cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                                    "dtstart=?, " +
24882cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                                    "dtend=?, " +
24892cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                                    "dtstart2=?, " +
24902cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                                    "dtend2=?, " +
24912cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                                    "duration=?," +
24922cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                                    "eventTimezone=?, " +
24932cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                                    "eventTimezone2=? " +
24942cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                                    "WHERE _id=?",
24957cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio                                    new Object[] {
24967cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio                                            dtstart,
24977cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio                                            null,
24987cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio                                            dtstart2,
24997cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio                                            null,
25007cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio                                            duration,
25017cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio                                            timezone,
25027cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio                                            timezone2,
25037cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio                                            id}
25047cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio                            );
25057b40dde3168f4af2c757cb43955aa3bfe1668666Erik                        }
25067b40dde3168f4af2c757cb43955aa3bfe1668666Erik                    }
25077b40dde3168f4af2c757cb43955aa3bfe1668666Erik                }
25087b40dde3168f4af2c757cb43955aa3bfe1668666Erik            } finally {
25097b40dde3168f4af2c757cb43955aa3bfe1668666Erik                cursor.close();
25107b40dde3168f4af2c757cb43955aa3bfe1668666Erik            }
25117b40dde3168f4af2c757cb43955aa3bfe1668666Erik        }
25127b40dde3168f4af2c757cb43955aa3bfe1668666Erik    }
25137b40dde3168f4af2c757cb43955aa3bfe1668666Erik
2514bf897b03effb752368a98cfb89e6b90cfdde50fcMarc Blank    private void upgradeToVersion66(SQLiteDatabase db) {
2515bf897b03effb752368a98cfb89e6b90cfdde50fcMarc Blank        // Add a column to indicate whether the event organizer can respond to his own events
2516bf897b03effb752368a98cfb89e6b90cfdde50fcMarc Blank        // The UI should not show attendee status for events in calendars with this column = 0
25172cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("ALTER TABLE Calendars" +
25182cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                " ADD COLUMN organizerCanRespond INTEGER NOT NULL DEFAULT 1;");
2519cf9dc6b9bd031b1f6f811a32326ee85429c94debMarc Blank    }
2520cf9dc6b9bd031b1f6f811a32326ee85429c94debMarc Blank
2521162c7c9bbd53b623fbe913b376e7f7f42915bb59Marc Blank    private void upgradeToVersion64(SQLiteDatabase db) {
2522162c7c9bbd53b623fbe913b376e7f7f42915bb59Marc Blank        // Add a column that may be used by sync adapters
25232cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("ALTER TABLE Events" +
25242cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                " ADD COLUMN syncAdapterData TEXT;");
25252d1b3d70a6ebce8194932f8a8355d97a89da113fFabrice Di Meglio    }
25262d1b3d70a6ebce8194932f8a8355d97a89da113fFabrice Di Meglio
2527ae4f20e120d3107cef20be860a612c9c23816295Erik    private void upgradeToVersion62(SQLiteDatabase db) {
2528ae4f20e120d3107cef20be860a612c9c23816295Erik        // New columns are to transition to having allDay events in the local timezone
25292cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("ALTER TABLE Events" +
25302cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                " ADD COLUMN dtstart2 INTEGER;");
25312cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("ALTER TABLE Events" +
25322cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                " ADD COLUMN dtend2 INTEGER;");
25332cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("ALTER TABLE Events" +
25342cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                " ADD COLUMN eventTimezone2 TEXT;");
2535ae4f20e120d3107cef20be860a612c9c23816295Erik
2536ae4f20e120d3107cef20be860a612c9c23816295Erik        String[] allDayBit = new String[] {"0"};
2537ae4f20e120d3107cef20be860a612c9c23816295Erik        // Copy over all the data that isn't an all day event.
25382cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("UPDATE Events SET " +
25392cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "dtstart2=dtstart," +
25402cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "dtend2=dtend," +
25412cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "eventTimezone2=eventTimezone " +
25422cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "WHERE allDay=?;",
2543ae4f20e120d3107cef20be860a612c9c23816295Erik                allDayBit /* selection args */);
2544ae4f20e120d3107cef20be860a612c9c23816295Erik
2545ae4f20e120d3107cef20be860a612c9c23816295Erik        // "cursor" iterates over all the calendars
2546ae4f20e120d3107cef20be860a612c9c23816295Erik        allDayBit[0] = "1";
25472cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        Cursor cursor = db.rawQuery("SELECT Events._id," +
25482cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "dtstart," +
25492cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "dtend," +
25502cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "eventTimezone," +
25512cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "timezone " +
25522cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "FROM Events INNER JOIN Calendars " +
25532cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "WHERE Events.calendar_id=Calendars._id" +
25542cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                " AND allDay=?",
2555ae4f20e120d3107cef20be860a612c9c23816295Erik                allDayBit /* selection args */);
2556ae4f20e120d3107cef20be860a612c9c23816295Erik
2557ae4f20e120d3107cef20be860a612c9c23816295Erik        Time oldTime = new Time();
2558ae4f20e120d3107cef20be860a612c9c23816295Erik        Time newTime = new Time();
2559ae4f20e120d3107cef20be860a612c9c23816295Erik        // Update the allday events in the new columns
2560ae4f20e120d3107cef20be860a612c9c23816295Erik        if (cursor != null) {
2561ae4f20e120d3107cef20be860a612c9c23816295Erik            try {
2562ae4f20e120d3107cef20be860a612c9c23816295Erik                String[] newData = new String[4];
2563ae4f20e120d3107cef20be860a612c9c23816295Erik                cursor.moveToPosition(-1);
2564ae4f20e120d3107cef20be860a612c9c23816295Erik                while (cursor.moveToNext()) {
2565ae4f20e120d3107cef20be860a612c9c23816295Erik                    long id = cursor.getLong(0); // Order from query above
2566ae4f20e120d3107cef20be860a612c9c23816295Erik                    long dtstart = cursor.getLong(1);
2567ae4f20e120d3107cef20be860a612c9c23816295Erik                    long dtend = cursor.getLong(2);
2568ae4f20e120d3107cef20be860a612c9c23816295Erik                    String eTz = cursor.getString(3); // current event timezone
2569ae4f20e120d3107cef20be860a612c9c23816295Erik                    String tz = cursor.getString(4); // Calendar timezone
2570dbaad88527665d5144a8a178fa822f58d2bc7d05Erik                    //If there's no timezone for some reason use UTC by default.
2571dbaad88527665d5144a8a178fa822f58d2bc7d05Erik                    if(eTz == null) {
2572dbaad88527665d5144a8a178fa822f58d2bc7d05Erik                        eTz = Time.TIMEZONE_UTC;
2573dbaad88527665d5144a8a178fa822f58d2bc7d05Erik                    }
2574ae4f20e120d3107cef20be860a612c9c23816295Erik
2575ae4f20e120d3107cef20be860a612c9c23816295Erik                    // Convert start time for all day events into the timezone of their calendar
2576ae4f20e120d3107cef20be860a612c9c23816295Erik                    oldTime.clear(eTz);
2577ae4f20e120d3107cef20be860a612c9c23816295Erik                    oldTime.set(dtstart);
2578ae4f20e120d3107cef20be860a612c9c23816295Erik                    newTime.clear(tz);
2579ae4f20e120d3107cef20be860a612c9c23816295Erik                    newTime.set(oldTime.monthDay, oldTime.month, oldTime.year);
2580ae4f20e120d3107cef20be860a612c9c23816295Erik                    newTime.normalize(false);
2581ae4f20e120d3107cef20be860a612c9c23816295Erik                    dtstart = newTime.toMillis(false /*ignoreDst*/);
2582ae4f20e120d3107cef20be860a612c9c23816295Erik
2583ae4f20e120d3107cef20be860a612c9c23816295Erik                    // Convert end time for all day events into the timezone of their calendar
2584ae4f20e120d3107cef20be860a612c9c23816295Erik                    oldTime.clear(eTz);
2585ae4f20e120d3107cef20be860a612c9c23816295Erik                    oldTime.set(dtend);
2586ae4f20e120d3107cef20be860a612c9c23816295Erik                    newTime.clear(tz);
2587ae4f20e120d3107cef20be860a612c9c23816295Erik                    newTime.set(oldTime.monthDay, oldTime.month, oldTime.year);
2588ae4f20e120d3107cef20be860a612c9c23816295Erik                    newTime.normalize(false);
2589ae4f20e120d3107cef20be860a612c9c23816295Erik                    dtend = newTime.toMillis(false /*ignoreDst*/);
2590ae4f20e120d3107cef20be860a612c9c23816295Erik
2591ae4f20e120d3107cef20be860a612c9c23816295Erik                    newData[0] = String.valueOf(dtstart);
2592ae4f20e120d3107cef20be860a612c9c23816295Erik                    newData[1] = String.valueOf(dtend);
2593ae4f20e120d3107cef20be860a612c9c23816295Erik                    newData[2] = tz;
2594ae4f20e120d3107cef20be860a612c9c23816295Erik                    newData[3] = String.valueOf(id);
25952cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                    db.execSQL("UPDATE Events SET " +
25962cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                            "dtstart2=?, " +
25972cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                            "dtend2=?, " +
25982cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                            "eventTimezone2=? " +
25992cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                            "WHERE _id=?",
2600ae4f20e120d3107cef20be860a612c9c23816295Erik                            newData);
2601ae4f20e120d3107cef20be860a612c9c23816295Erik                }
2602ae4f20e120d3107cef20be860a612c9c23816295Erik            } finally {
2603ae4f20e120d3107cef20be860a612c9c23816295Erik                cursor.close();
2604ae4f20e120d3107cef20be860a612c9c23816295Erik            }
2605ae4f20e120d3107cef20be860a612c9c23816295Erik        }
2606ae4f20e120d3107cef20be860a612c9c23816295Erik    }
2607ae4f20e120d3107cef20be860a612c9c23816295Erik
2608ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio    private void upgradeToVersion61(SQLiteDatabase db) {
2609315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio        db.execSQL("DROP TABLE IF EXISTS CalendarCache;");
2610315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio
2611315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio        // IF NOT EXISTS should be normal pattern for table creation
26122cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("CREATE TABLE IF NOT EXISTS CalendarCache (" +
26132cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_id INTEGER PRIMARY KEY," +
26142cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "key TEXT NOT NULL," +
26152cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "value TEXT" +
2616315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio                ");");
2617315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio
26182cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("INSERT INTO CalendarCache (" +
26192cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "key, " +
26202cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "value) VALUES (" +
26212cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "'timezoneDatabaseVersion',"  +
26222cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "'2009s'" +
2623315d9326acd39566959f3c547225483f1fb6aefcFabrice Di Meglio                ");");
2624ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio    }
2625ae270e35e14b5c7a756050cb8dcccf5771743850Fabrice Di Meglio
2626ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff    private void upgradeToVersion60(SQLiteDatabase db) {
2627ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        // Switch to CalendarProvider2
2628d5aa3cc17ecda3d72882d9a2e6c48577892df903Ken Shirriff        upgradeSyncState(db);
2629ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        db.execSQL("DROP TRIGGER IF EXISTS calendar_cleanup");
26302cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("CREATE TRIGGER calendar_cleanup DELETE ON Calendars " +
2631ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff                "BEGIN " +
26322cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                ("DELETE FROM Events" +
26332cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                        " WHERE calendar_id=old._id;") +
2634ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff                "END");
26352cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("ALTER TABLE Events" +
26362cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                " ADD COLUMN deleted INTEGER NOT NULL DEFAULT 0;");
2637ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        db.execSQL("DROP TRIGGER IF EXISTS events_insert");
26387cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        // Trigger to set event's sync_account
26392cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("CREATE TRIGGER events_insert AFTER INSERT ON Events " +
2640ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff                "BEGIN " +
26412cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "UPDATE Events" +
26422cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                " SET _sync_account=" +
26432cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                " (SELECT _sync_account FROM Calendars" +
26442cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                " WHERE Calendars._id=new.calendar_id)," +
26452cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_account_type=" +
26462cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                " (SELECT _sync_account_type FROM Calendars" +
26472cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                " WHERE Calendars._id=new.calendar_id) " +
26482cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "WHERE Events._id=new._id;" +
2649ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff                "END");
2650ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        db.execSQL("DROP TABLE IF EXISTS DeletedEvents;");
2651ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        db.execSQL("DROP TRIGGER IF EXISTS events_cleanup_delete");
26527cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        // Trigger to remove data tied to an event when we delete that event.
26532cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("CREATE TRIGGER events_cleanup_delete DELETE ON Events " +
2654ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff                "BEGIN " +
26552cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                ("DELETE FROM Instances" +
26562cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                    " WHERE event_id=old._id;" +
26572cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "DELETE FROM EventsRawTimes" +
26582cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                    " WHERE event_id=old._id;" +
26592cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "DELETE FROM Attendees" +
26602cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                    " WHERE event_id=old._id;" +
26612cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "DELETE FROM Reminders" +
26622cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                    " WHERE event_id=old._id;" +
26632cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "DELETE FROM CalendarAlerts" +
26642cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                    " WHERE event_id=old._id;" +
26652cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "DELETE FROM ExtendedProperties" +
26662cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                    " WHERE event_id=old._id;") +
2667ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff                "END");
2668ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        db.execSQL("DROP TRIGGER IF EXISTS attendees_update");
2669ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        db.execSQL("DROP TRIGGER IF EXISTS attendees_insert");
2670ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        db.execSQL("DROP TRIGGER IF EXISTS attendees_delete");
2671ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        db.execSQL("DROP TRIGGER IF EXISTS reminders_update");
2672ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        db.execSQL("DROP TRIGGER IF EXISTS reminders_insert");
2673ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        db.execSQL("DROP TRIGGER IF EXISTS reminders_delete");
2674ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        db.execSQL("DROP TRIGGER IF EXISTS extended_properties_update");
2675ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        db.execSQL("DROP TRIGGER IF EXISTS extended_properties_insert");
2676ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        db.execSQL("DROP TRIGGER IF EXISTS extended_properties_delete");
2677ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff    }
2678ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff
2679ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff    private void upgradeToVersion59(SQLiteDatabase db) {
2680ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        db.execSQL("DROP TABLE IF EXISTS BusyBits;");
26812cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("CREATE TEMPORARY TABLE CalendarMetaData_Backup(" +
26822cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_id," +
26832cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "localTimezone," +
26842cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "minInstance," +
26852cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "maxInstance" +
26867cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio                ");");
26872cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("INSERT INTO CalendarMetaData_Backup " +
26887cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio                "SELECT " +
26892cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_id," +
26902cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "localTimezone," +
26912cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "minInstance," +
26922cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "maxInstance" +
26932cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                " FROM CalendarMetaData;");
26942cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("DROP TABLE CalendarMetaData;");
26952cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        createCalendarMetaDataTable59(db);
26962cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("INSERT INTO CalendarMetaData " +
26977cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio                "SELECT " +
26982cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_id," +
26992cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "localTimezone," +
27002cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "minInstance," +
27012cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "maxInstance" +
27022cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                " FROM CalendarMetaData_Backup;");
27032cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("DROP TABLE CalendarMetaData_Backup;");
2704ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff    }
2705ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff
2706ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff    private void upgradeToVersion57(SQLiteDatabase db) {
27072cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("ALTER TABLE Events" +
27082cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                " ADD COLUMN guestsCanModify" +
27097cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio                " INTEGER NOT NULL DEFAULT 0;");
27102cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("ALTER TABLE Events" +
27112cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                " ADD COLUMN guestsCanInviteOthers" +
27127cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio                " INTEGER NOT NULL DEFAULT 1;");
27132cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("ALTER TABLE Events" +
27142cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                " ADD COLUMN guestsCanSeeGuests" +
27157cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio                " INTEGER NOT NULL DEFAULT 1;");
27162cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("ALTER TABLE Events" +
27172cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                " ADD COLUMN organizer" +
27187cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio                " STRING;");
27192cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("UPDATE Events SET organizer=" +
27202cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "(SELECT attendeeEmail" +
27212cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                " FROM Attendees"  +
27227cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio                " WHERE " +
27232cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "Attendees.event_id=" +
27242cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "Events._id" +
27257cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio                " AND " +
27262cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "Attendees.attendeeRelationship=2);");
2727ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff    }
2728ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff
27291599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio    private void upgradeToVersion56(SQLiteDatabase db) {
27302cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("ALTER TABLE Calendars" +
27312cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                " ADD COLUMN ownerAccount TEXT;");
27322cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("ALTER TABLE Events" +
2733d5f4742d7ba16d791edd9fd33a1a2a42eeac709bRoboErik                " ADD COLUMN hasAttendeeData INTEGER NOT NULL DEFAULT 0;");
27347cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio
27351599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio        // Clear _sync_dirty to avoid a client-to-server sync that could blow away
27361599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio        // server attendees.
27371599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio        // Clear _sync_version to pull down the server's event (with attendees)
27381599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio        // Change the URLs from full-selfattendance to full
27392cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("UPDATE Events"
27402cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                + " SET _sync_dirty=0, "
27412cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                + "_sync_version=NULL, "
27422cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                + "_sync_id="
27432cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                + "REPLACE(_sync_id, " +
27447cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio                    "'/private/full-selfattendance', '/private/full'),"
27452cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                + "commentsUri="
27462cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                + "REPLACE(commentsUri, " +
27477cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio                    "'/private/full-selfattendance', '/private/full');");
27487cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio
27492cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("UPDATE Calendars"
27502cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                + " SET url="
27512cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                + "REPLACE(url, '/private/full-selfattendance', '/private/full');");
27521599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio
27531599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio        // "cursor" iterates over all the calendars
27542cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        Cursor cursor = db.rawQuery("SELECT _id, " +
27552cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "url FROM Calendars",
27561599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio                null /* selection args */);
27571599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio        // Add the owner column.
27581599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio        if (cursor != null) {
27591599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio            try {
27602cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                final String updateSql = "UPDATE Calendars" +
27612cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                        " SET ownerAccount=?" +
27622cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                        " WHERE _id=?";
27631599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio                while (cursor.moveToNext()) {
27641599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio                    Long id = cursor.getLong(0);
27651599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio                    String url = cursor.getString(1);
27661599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio                    String owner = calendarEmailAddressFromFeedUrl(url);
27677cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio                    db.execSQL(updateSql, new Object[] {owner, id});
27681599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio                }
27691599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio            } finally {
27701599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio                cursor.close();
27711599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio            }
27721599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio        }
27731599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio    }
27741599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio
27751599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio    private void upgradeResync(SQLiteDatabase db) {
27761599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio        // Delete sync state, so all records will be re-synced.
27772cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("DELETE FROM _sync_state;");
27781599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio
27791599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio        // "cursor" iterates over all the calendars
27802cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        Cursor cursor = db.rawQuery("SELECT _sync_account," +
27812cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_account_type,url FROM Calendars",
27821599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio                null /* selection args */);
27831599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio        if (cursor != null) {
27841599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio            try {
27851599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio                while (cursor.moveToNext()) {
27861599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio                    String accountName = cursor.getString(0);
27871599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio                    String accountType = cursor.getString(1);
27881599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio                    final Account account = new Account(accountName, accountType);
27891599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio                    String calendarUrl = cursor.getString(2);
27901599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio                    scheduleSync(account, false /* two-way sync */, calendarUrl);
27911599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio                }
27921599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio            } finally {
27931599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio                cursor.close();
27941599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio            }
27951599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio        }
27961599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio    }
27971599ceb270bc70f81dcaf8ecf4568453d7dddd9eFabrice Di Meglio
2798ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff    private void upgradeToVersion55(SQLiteDatabase db) {
27992cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("ALTER TABLE Calendars ADD COLUMN " +
28002cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_account_type TEXT;");
28012cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("ALTER TABLE Events ADD COLUMN " +
28022cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "_sync_account_type TEXT;");
2803ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        db.execSQL("ALTER TABLE DeletedEvents ADD COLUMN _sync_account_type TEXT;");
28042cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("UPDATE Calendars"
28052cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                + " SET _sync_account_type='com.google'"
28062cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                + " WHERE _sync_account IS NOT NULL");
28072cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("UPDATE Events"
28082cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                + " SET _sync_account_type='com.google'"
28092cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                + " WHERE _sync_account IS NOT NULL");
2810ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        db.execSQL("UPDATE DeletedEvents"
2811ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff                + " SET _sync_account_type='com.google'"
2812ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff                + " WHERE _sync_account IS NOT NULL");
2813ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        Log.w(TAG, "re-creating eventSyncAccountAndIdIndex");
2814ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        db.execSQL("DROP INDEX eventSyncAccountAndIdIndex");
28152cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("CREATE INDEX eventSyncAccountAndIdIndex ON Events ("
28162cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                + "_sync_account_type, "
28172cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                + "_sync_account, "
28182cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                + "_sync_id);");
2819ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff    }
2820ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff
2821ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff    private void upgradeToVersion54(SQLiteDatabase db) {
2822ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        Log.w(TAG, "adding eventSyncAccountAndIdIndex");
2823ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        db.execSQL("CREATE INDEX eventSyncAccountAndIdIndex ON Events ("
28242cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                + "_sync_account, _sync_id);");
2825ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff    }
2826ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff
2827ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff    private void upgradeToVersion53(SQLiteDatabase db) {
2828ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        Log.w(TAG, "Upgrading CalendarAlerts table");
28292cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("ALTER TABLE CalendarAlerts ADD COLUMN " +
2830d5f4742d7ba16d791edd9fd33a1a2a42eeac709bRoboErik                "creationTime INTEGER NOT NULL DEFAULT 0;");
28312cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("ALTER TABLE CalendarAlerts ADD COLUMN " +
2832d5f4742d7ba16d791edd9fd33a1a2a42eeac709bRoboErik                "receivedTime INTEGER NOT NULL DEFAULT 0;");
28332cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("ALTER TABLE CalendarAlerts ADD COLUMN " +
2834d5f4742d7ba16d791edd9fd33a1a2a42eeac709bRoboErik                "notifyTime INTEGER NOT NULL DEFAULT 0;");
2835ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff    }
2836ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff
2837ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff    private void upgradeToVersion52(SQLiteDatabase db) {
2838ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        // We added "originalAllDay" to the Events table to keep track of
2839ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        // the allDay status of the original recurring event for entries
2840ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        // that are exceptions to that recurring event.  We need this so
2841ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        // that we can format the date correctly for the "originalInstanceTime"
2842ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        // column when we make a change to the recurrence exception and
2843ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        // send it to the server.
28442cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("ALTER TABLE Events ADD COLUMN " +
28452cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "originalAllDay INTEGER;");
2846ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff
2847ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        // Iterate through the Events table and for each recurrence
2848ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        // exception, fill in the correct value for "originalAllDay",
2849ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        // if possible.  The only times where this might not be possible
2850ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        // are (1) the original recurring event no longer exists, or
2851ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        // (2) the original recurring event does not yet have a _sync_id
2852ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        // because it was created on the phone and hasn't been synced to the
2853ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        // server yet.  In both cases the originalAllDay field will be set
2854ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        // to null.  In the first case we don't care because the recurrence
2855ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        // exception will not be displayed and we won't be able to make
2856ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        // any changes to it (and even if we did, the server should ignore
2857ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        // them, right?).  In the second case, the calendar client already
2858ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        // disallows making changes to an instance of a recurring event
2859ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        // until the recurring event has been synced to the server so the
2860ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        // second case should never occur.
2861ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff
2862ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        // "cursor" iterates over all the recurrences exceptions.
28632cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        Cursor cursor = db.rawQuery("SELECT _id," +
28642cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "originalEvent" +
28652cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                " FROM Events" +
28662cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                " WHERE originalEvent IS NOT NULL",
28677cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio                null /* selection args */);
2868ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        if (cursor != null) {
2869ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff            try {
2870ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff                while (cursor.moveToNext()) {
2871ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff                    long id = cursor.getLong(0);
2872ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff                    String originalEvent = cursor.getString(1);
2873ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff
2874ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff                    // Find the original recurring event (if it exists)
28752cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                    Cursor recur = db.rawQuery("SELECT allDay" +
28762cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                            " FROM Events" +
28772cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                            " WHERE _sync_id=?",
28787cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio                            new String[] {originalEvent});
2879ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff                    if (recur == null) {
2880ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff                        continue;
2881ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff                    }
2882ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff
2883ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff                    try {
2884ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff                        // Fill in the "originalAllDay" field of the
2885ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff                        // recurrence exception with the "allDay" value
2886ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff                        // from the recurring event.
2887ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff                        if (recur.moveToNext()) {
2888ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff                            int allDay = recur.getInt(0);
28892cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                            db.execSQL("UPDATE Events" +
28902cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                                    " SET originalAllDay=" + allDay +
28912cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                                    " WHERE _id="+id);
2892ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff                        }
2893ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff                    } finally {
2894ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff                        recur.close();
2895ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff                    }
2896ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff                }
2897ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff            } finally {
2898ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff                cursor.close();
2899ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff            }
29009f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff        }
29019f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    }
29029f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
2903ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff    private void upgradeToVersion51(SQLiteDatabase db) {
2904ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        Log.w(TAG, "Upgrading DeletedEvents table");
2905ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff
2906ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        // We don't have enough information to fill in the correct
2907ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        // value of the calendar_id for old rows in the DeletedEvents
2908ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        // table, but rows in that table are transient so it is unlikely
2909ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        // that there are any rows.  Plus, the calendar_id is used only
2910ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        // when deleting a calendar, which is a rare event.  All new rows
2911ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        // will have the correct calendar_id.
2912ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        db.execSQL("ALTER TABLE DeletedEvents ADD COLUMN calendar_id INTEGER;");
2913ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff
2914ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        // Trigger to remove a calendar's events when we delete the calendar
2915ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        db.execSQL("DROP TRIGGER IF EXISTS calendar_cleanup");
29162cff10f1a005bd7302245d4c680cf851193c3a97RoboErik        db.execSQL("CREATE TRIGGER calendar_cleanup DELETE ON Calendars " +
2917ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff                "BEGIN " +
29182cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                "DELETE FROM Events WHERE calendar_id=" +
29192cff10f1a005bd7302245d4c680cf851193c3a97RoboErik                    "old._id;" +
2920ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff                "DELETE FROM DeletedEvents WHERE calendar_id = old._id;" +
2921ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff                "END");
2922ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff        db.execSQL("DROP TRIGGER IF EXISTS event_to_deleted");
2923ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff    }
2924ad37c99d051aa4e2508b940c8dec91ee87f53056Ken Shirriff
29259f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    private void dropTables(SQLiteDatabase db) {
29262f251c778c06d21ed7693a70f4a1268ff929242eRoboErik        db.execSQL("DROP TABLE IF EXISTS " + Tables.COLORS + ";");
29277cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        db.execSQL("DROP TABLE IF EXISTS " + Tables.CALENDARS + ";");
29287cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        db.execSQL("DROP TABLE IF EXISTS " + Tables.EVENTS + ";");
29297cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        db.execSQL("DROP TABLE IF EXISTS " + Tables.EVENTS_RAW_TIMES + ";");
29307cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        db.execSQL("DROP TABLE IF EXISTS " + Tables.INSTANCES + ";");
29317cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        db.execSQL("DROP TABLE IF EXISTS " + Tables.CALENDAR_META_DATA + ";");
29327cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        db.execSQL("DROP TABLE IF EXISTS " + Tables.CALENDAR_CACHE + ";");
29337cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        db.execSQL("DROP TABLE IF EXISTS " + Tables.ATTENDEES + ";");
29347cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        db.execSQL("DROP TABLE IF EXISTS " + Tables.REMINDERS + ";");
29357cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        db.execSQL("DROP TABLE IF EXISTS " + Tables.CALENDAR_ALERTS + ";");
29367cb72fa3ea680dce378d8dac71f878e52e03f83aFabrice Di Meglio        db.execSQL("DROP TABLE IF EXISTS " + Tables.EXTENDED_PROPERTIES + ";");
29379f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    }
29389f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
29399f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    @Override
29409f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    public synchronized SQLiteDatabase getWritableDatabase() {
29419f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff        SQLiteDatabase db = super.getWritableDatabase();
29429f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff        return db;
29439f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    }
29449f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
29459f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    public SyncStateContentProviderHelper getSyncState() {
29469f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff        return mSyncState;
29479f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    }
29489f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
29499f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    /**
29509f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff     * Schedule a calendar sync for the account.
29519f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff     * @param account the account for which to schedule a sync
29529f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff     * @param uploadChangesOnly if set, specify that the sync should only send
29537e3ec5f2025164fca508f81a5a01940bc912e064Ken Shirriff     *   up local changes.  This is typically used for a local sync, a user override of
29547e3ec5f2025164fca508f81a5a01940bc912e064Ken Shirriff     *   too many deletions, or a sync after a calendar is unselected.
29557e3ec5f2025164fca508f81a5a01940bc912e064Ken Shirriff     * @param url the url feed for the calendar to sync (may be null, in which case a poll of
29567e3ec5f2025164fca508f81a5a01940bc912e064Ken Shirriff     *   all feeds is done.)
29579f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff     */
29589f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    void scheduleSync(Account account, boolean uploadChangesOnly, String url) {
29599f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff        Bundle extras = new Bundle();
29607e3ec5f2025164fca508f81a5a01940bc912e064Ken Shirriff        if (uploadChangesOnly) {
29617e3ec5f2025164fca508f81a5a01940bc912e064Ken Shirriff            extras.putBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, uploadChangesOnly);
29627e3ec5f2025164fca508f81a5a01940bc912e064Ken Shirriff        }
29639f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff        if (url != null) {
29649f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff            extras.putString("feed", url);
29659f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff            extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
29669f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff        }
2967b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik        ContentResolver.requestSync(account, CalendarContract.Calendars.CONTENT_URI.getAuthority(),
2968b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                extras);
29699f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff    }
29709f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff
29717e3ec5f2025164fca508f81a5a01940bc912e064Ken Shirriff    private static void createEventsView(SQLiteDatabase db) {
29727e3ec5f2025164fca508f81a5a01940bc912e064Ken Shirriff        db.execSQL("DROP VIEW IF EXISTS " + Views.EVENTS + ";");
29737e3ec5f2025164fca508f81a5a01940bc912e064Ken Shirriff        String eventsSelect = "SELECT "
2974b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + Tables.EVENTS + "." + CalendarContract.Events._ID
2975b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                        + " AS " + CalendarContract.Events._ID + ","
2976b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Events.TITLE + ","
2977b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Events.DESCRIPTION + ","
2978b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Events.EVENT_LOCATION + ","
2979b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Events.EVENT_COLOR + ","
2980387535fec9f646e0b7acb82d5354f2b5ebee4395RoboErik                + CalendarContract.Events.EVENT_COLOR_KEY + ","
2981b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Events.STATUS + ","
2982b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Events.SELF_ATTENDEE_STATUS + ","
2983b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Events.DTSTART + ","
2984b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Events.DTEND + ","
2985b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Events.DURATION + ","
2986b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Events.EVENT_TIMEZONE + ","
2987b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Events.EVENT_END_TIMEZONE + ","
2988b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Events.ALL_DAY + ","
2989b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Events.ACCESS_LEVEL + ","
2990b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Events.AVAILABILITY + ","
2991b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Events.HAS_ALARM + ","
2992b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Events.HAS_EXTENDED_PROPERTIES + ","
2993b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Events.RRULE + ","
2994b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Events.RDATE + ","
2995b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Events.EXRULE + ","
2996b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Events.EXDATE + ","
2997b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Events.ORIGINAL_SYNC_ID + ","
2998b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Events.ORIGINAL_ID + ","
2999b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Events.ORIGINAL_INSTANCE_TIME + ","
3000b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Events.ORIGINAL_ALL_DAY + ","
3001b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Events.LAST_DATE + ","
3002b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Events.HAS_ATTENDEE_DATA + ","
3003b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Events.CALENDAR_ID + ","
3004b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Events.GUESTS_CAN_INVITE_OTHERS + ","
3005b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Events.GUESTS_CAN_MODIFY + ","
3006b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Events.GUESTS_CAN_SEE_GUESTS + ","
3007b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Events.ORGANIZER + ","
3008b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Events.SYNC_DATA1 + ","
3009b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Events.SYNC_DATA2 + ","
3010b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Events.SYNC_DATA3 + ","
3011b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Events.SYNC_DATA4 + ","
3012b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Events.SYNC_DATA5 + ","
3013b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Events.SYNC_DATA6 + ","
3014b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Events.SYNC_DATA7 + ","
3015b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Events.SYNC_DATA8 + ","
3016b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Events.SYNC_DATA9 + ","
3017b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Events.SYNC_DATA10 + ","
3018b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + Tables.EVENTS + "." + CalendarContract.Events.DELETED
3019b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + " AS " + CalendarContract.Events.DELETED + ","
3020b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + Tables.EVENTS + "." + CalendarContract.Events._SYNC_ID
3021b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + " AS " + CalendarContract.Events._SYNC_ID + ","
3022b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + Tables.EVENTS + "." + CalendarContract.Events.DIRTY
3023b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + " AS " + CalendarContract.Events.DIRTY + ","
3024b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Events.LAST_SYNCED + ","
3025b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + Tables.CALENDARS + "." + CalendarContract.Calendars.ACCOUNT_NAME
3026b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + " AS " + CalendarContract.Events.ACCOUNT_NAME + ","
3027b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + Tables.CALENDARS + "." + CalendarContract.Calendars.ACCOUNT_TYPE
3028b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + " AS " + CalendarContract.Events.ACCOUNT_TYPE + ","
3029b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Calendars.CALENDAR_TIME_ZONE + ","
3030b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Calendars.CALENDAR_DISPLAY_NAME + ","
3031b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Calendars.CALENDAR_LOCATION + ","
3032b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Calendars.VISIBLE + ","
3033b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Calendars.CALENDAR_COLOR + ","
3034387535fec9f646e0b7acb82d5354f2b5ebee4395RoboErik                + CalendarContract.Calendars.CALENDAR_COLOR_KEY + ","
3035b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Calendars.CALENDAR_ACCESS_LEVEL + ","
3036b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Calendars.MAX_REMINDERS + ","
3037b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Calendars.ALLOWED_REMINDERS + ","
30382f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + CalendarContract.Calendars.ALLOWED_ATTENDEE_TYPES + ","
30392f251c778c06d21ed7693a70f4a1268ff929242eRoboErik                + CalendarContract.Calendars.ALLOWED_AVAILABILITY + ","
3040b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Calendars.CAN_ORGANIZER_RESPOND + ","
3041b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Calendars.CAN_MODIFY_TIME_ZONE + ","
3042b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Calendars.CAN_PARTIALLY_UPDATE + ","
3043b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Calendars.CAL_SYNC1 + ","
3044b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Calendars.CAL_SYNC2 + ","
3045b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Calendars.CAL_SYNC3 + ","
3046b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Calendars.CAL_SYNC4 + ","
3047b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Calendars.CAL_SYNC5 + ","
3048b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Calendars.CAL_SYNC6 + ","
3049b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Calendars.CAL_SYNC7 + ","
3050b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Calendars.CAL_SYNC8 + ","
3051b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Calendars.CAL_SYNC9 + ","
3052b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Calendars.CAL_SYNC10 + ","
3053b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Calendars.OWNER_ACCOUNT + ","
3054b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Calendars.SYNC_EVENTS
30557e3ec5f2025164fca508f81a5a01940bc912e064Ken Shirriff                + " FROM " + Tables.EVENTS + " JOIN " + Tables.CALENDARS
3056b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + " ON (" + Tables.EVENTS + "." + CalendarContract.Events.CALENDAR_ID
3057b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + "=" + Tables.CALENDARS + "." + CalendarContract.Calendars._ID
30587e3ec5f2025164fca508f81a5a01940bc912e064Ken Shirriff                + ")";
30597e3ec5f2025164fca508f81a5a01940bc912e064Ken Shirriff
30607e3ec5f2025164fca508f81a5a01940bc912e064Ken Shirriff        db.execSQL("CREATE VIEW " + Views.EVENTS + " AS " + eventsSelect);
30617e3ec5f2025164fca508f81a5a01940bc912e064Ken Shirriff    }
3062d39cfe09aa7e752cdc7512ae58d90d49d4b5ef9eKen Shirriff
3063d39cfe09aa7e752cdc7512ae58d90d49d4b5ef9eKen Shirriff    /**
3064d39cfe09aa7e752cdc7512ae58d90d49d4b5ef9eKen Shirriff     * Extracts the calendar email from a calendar feed url.
3065d39cfe09aa7e752cdc7512ae58d90d49d4b5ef9eKen Shirriff     * @param feed the calendar feed url
3066d39cfe09aa7e752cdc7512ae58d90d49d4b5ef9eKen Shirriff     * @return the calendar email that is in the feed url or null if it can't
3067d39cfe09aa7e752cdc7512ae58d90d49d4b5ef9eKen Shirriff     * find the email address.
3068d39cfe09aa7e752cdc7512ae58d90d49d4b5ef9eKen Shirriff     * TODO: this is duplicated in CalendarSyncAdapter; move to a library
3069d39cfe09aa7e752cdc7512ae58d90d49d4b5ef9eKen Shirriff     */
3070d39cfe09aa7e752cdc7512ae58d90d49d4b5ef9eKen Shirriff    public static String calendarEmailAddressFromFeedUrl(String feed) {
3071d39cfe09aa7e752cdc7512ae58d90d49d4b5ef9eKen Shirriff        // Example feed url:
3072d39cfe09aa7e752cdc7512ae58d90d49d4b5ef9eKen Shirriff        // https://www.google.com/calendar/feeds/foo%40gmail.com/private/full-noattendees
3073d39cfe09aa7e752cdc7512ae58d90d49d4b5ef9eKen Shirriff        String[] pathComponents = feed.split("/");
3074d39cfe09aa7e752cdc7512ae58d90d49d4b5ef9eKen Shirriff        if (pathComponents.length > 5 && "feeds".equals(pathComponents[4])) {
3075d39cfe09aa7e752cdc7512ae58d90d49d4b5ef9eKen Shirriff            try {
3076d39cfe09aa7e752cdc7512ae58d90d49d4b5ef9eKen Shirriff                return URLDecoder.decode(pathComponents[5], "UTF-8");
3077d39cfe09aa7e752cdc7512ae58d90d49d4b5ef9eKen Shirriff            } catch (UnsupportedEncodingException e) {
3078d39cfe09aa7e752cdc7512ae58d90d49d4b5ef9eKen Shirriff                Log.e(TAG, "unable to url decode the email address in calendar " + feed);
3079d39cfe09aa7e752cdc7512ae58d90d49d4b5ef9eKen Shirriff                return null;
3080d39cfe09aa7e752cdc7512ae58d90d49d4b5ef9eKen Shirriff            }
3081d39cfe09aa7e752cdc7512ae58d90d49d4b5ef9eKen Shirriff        }
3082d39cfe09aa7e752cdc7512ae58d90d49d4b5ef9eKen Shirriff
3083d39cfe09aa7e752cdc7512ae58d90d49d4b5ef9eKen Shirriff        Log.e(TAG, "unable to find the email address in calendar " + feed);
3084d39cfe09aa7e752cdc7512ae58d90d49d4b5ef9eKen Shirriff        return null;
3085d39cfe09aa7e752cdc7512ae58d90d49d4b5ef9eKen Shirriff    }
30861b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio
30871b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio    /**
30881b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio     * Get a "allcalendars" url from a "private/full" or "private/free-busy" url
30891b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio     * @param url
30901b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio     * @return the rewritten Url
30911b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio     *
30921b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio     * For example:
30931b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio     *
30941b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio     *      http://www.google.com/calendar/feeds/joe%40joe.com/private/full
30951b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio     *      http://www.google.com/calendar/feeds/joe%40joe.com/private/free-busy
30961b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio     *
30971b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio     * will be rewriten into:
30981b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio     *
30991b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio     *      http://www.google.com/calendar/feeds/default/allcalendars/full/joe%40joe.com
31001b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio     *      http://www.google.com/calendar/feeds/default/allcalendars/full/joe%40joe.com
31011b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio     */
31021b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio    @VisibleForTesting
31031b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio    private static String getAllCalendarsUrlFromEventsUrl(String url) {
31041b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio        if (url == null) {
31051b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio            if (Log.isLoggable(TAG, Log.DEBUG)) {
31061b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio                Log.d(TAG, "Cannot get AllCalendars url from a NULL url");
31071b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio            }
31081b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio            return null;
31091b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio        }
31101b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio        if (url.contains("/private/full")) {
31111b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio            return url.replace("/private/full", "").
31121b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio                    replace("/calendar/feeds", "/calendar/feeds/default/allcalendars/full");
31131b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio        }
31141b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio        if (url.contains("/private/free-busy")) {
31151b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio            return url.replace("/private/free-busy", "").
31161b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio                    replace("/calendar/feeds", "/calendar/feeds/default/allcalendars/full");
31171b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio        }
31181b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio        // Just log as we dont recognize the provided Url
31191b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio        if (Log.isLoggable(TAG, Log.DEBUG)) {
31201b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio            Log.d(TAG, "Cannot get AllCalendars url from the following url: " + url);
31211b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio        }
31221b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio        return null;
31231b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio    }
31241b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio
31251b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio    /**
31261b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio     * Get "selfUrl" from "events url"
31271b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio     * @param url the Events url (either "private/full" or "private/free-busy"
31281b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio     * @return the corresponding allcalendar url
31291b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio     */
31301b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio    private static String getSelfUrlFromEventsUrl(String url) {
31311b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio        return rewriteUrlFromHttpToHttps(getAllCalendarsUrlFromEventsUrl(url));
31321b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio    }
31331b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio
31341b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio    /**
31351b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio     * Get "editUrl" from "events url"
31361b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio     * @param url the Events url (either "private/full" or "private/free-busy"
31371b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio     * @return the corresponding allcalendar url
31381b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio     */
31391b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio    private static String getEditUrlFromEventsUrl(String url) {
31401b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio        return rewriteUrlFromHttpToHttps(getAllCalendarsUrlFromEventsUrl(url));
31411b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio    }
31421b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio
31431b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio    /**
31441b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio     * Rewrite the url from "http" to "https" scheme
31451b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio     * @param url the url to rewrite
31461b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio     * @return the rewritten URL
31471b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio     */
31481b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio    private static String rewriteUrlFromHttpToHttps(String url) {
31491b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio        if (url == null) {
31501b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio            if (Log.isLoggable(TAG, Log.DEBUG)) {
31511b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio                Log.d(TAG, "Cannot rewrite a NULL url");
31521b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio            }
31531b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio            return null;
31541b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio        }
31551b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio        if (url.startsWith(SCHEMA_HTTPS)) {
31561b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio            return url;
31571b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio        }
31581b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio        if (!url.startsWith(SCHEMA_HTTP)) {
31591b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio            throw new IllegalArgumentException("invalid url parameter, unknown scheme: " + url);
31601b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio        }
31611b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio        return SCHEMA_HTTPS + url.substring(SCHEMA_HTTP.length());
31621b6beb61ef04c3da6ab0bdf8504ffecea2b9534cFabrice Di Meglio    }
31639ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert
31641c72909abbfe7559bcc880c339399f1eaa0478f3Andy McFadden    /**
31651c72909abbfe7559bcc880c339399f1eaa0478f3Andy McFadden     * Duplicates an event and its associated tables (Attendees, Reminders, ExtendedProperties).
31661c72909abbfe7559bcc880c339399f1eaa0478f3Andy McFadden     * <p>
31671c72909abbfe7559bcc880c339399f1eaa0478f3Andy McFadden     * Does not create a duplicate if the Calendar's "canPartiallyUpdate" is 0 or the Event's
31681c72909abbfe7559bcc880c339399f1eaa0478f3Andy McFadden     * "dirty" is 1 (so we don't create more than one duplicate).
31691c72909abbfe7559bcc880c339399f1eaa0478f3Andy McFadden     *
31701c72909abbfe7559bcc880c339399f1eaa0478f3Andy McFadden     * @param id The _id of the event to duplicate.
31711c72909abbfe7559bcc880c339399f1eaa0478f3Andy McFadden     */
31729ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert    protected void duplicateEvent(final long id) {
31739ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert        final SQLiteDatabase db = getWritableDatabase();
3174b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik        final long canPartiallyUpdate = DatabaseUtils.longForQuery(db, "SELECT "
3175b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + CalendarContract.Calendars.CAN_PARTIALLY_UPDATE + " FROM " + Views.EVENTS
3176b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + " WHERE " + Events._ID + " = ?", new String[] {
3177b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik            String.valueOf(id)
3178b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik        });
31799ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert        if (canPartiallyUpdate == 0) {
31809ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert            return;
31819ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert        }
31829ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert
31839ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert        db.execSQL("INSERT INTO " + CalendarDatabaseHelper.Tables.EVENTS
31849ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                + "  (" + LAST_SYNCED_EVENT_COLUMNS + ","
31859ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                +         Events.DIRTY + "," + Events.LAST_SYNCED + ")"
31869ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                + " SELECT " + LAST_SYNCED_EVENT_COLUMNS + ", 0, 1"
31879ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                + " FROM " + Tables.EVENTS
31889ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                + " WHERE "  + Events._ID + " = ? AND " + Events.DIRTY + " = ?",
31899ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                new Object[]{
31909ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                        id,
31919ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                        0, // Events.DIRTY
31929ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                });
31939ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert        final long newId = DatabaseUtils.longForQuery(
31949ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                db, "SELECT CASE changes() WHEN 0 THEN -1 ELSE last_insert_rowid() END", null);
31959ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert        if (newId < 0) {
31969ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert            return;
31979ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert        }
31989ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert
31999ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert        if (Log.isLoggable(TAG, Log.VERBOSE)) {
32009ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert            Log.v(TAG, "Duplicating event " + id + " into new event " + newId);
32019ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert        }
32029ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert
3203bcba82631ab0ee16efe58f0e0b0b9c18d93a6fd2Andy McFadden        copyEventRelatedTables(db, newId, id);
3204bcba82631ab0ee16efe58f0e0b0b9c18d93a6fd2Andy McFadden    }
3205bcba82631ab0ee16efe58f0e0b0b9c18d93a6fd2Andy McFadden
32061c72909abbfe7559bcc880c339399f1eaa0478f3Andy McFadden    /**
32071c72909abbfe7559bcc880c339399f1eaa0478f3Andy McFadden     * Makes a copy of the Attendees, Reminders, and ExtendedProperties rows associated with
32081c72909abbfe7559bcc880c339399f1eaa0478f3Andy McFadden     * a specific event.
32091c72909abbfe7559bcc880c339399f1eaa0478f3Andy McFadden     *
32101c72909abbfe7559bcc880c339399f1eaa0478f3Andy McFadden     * @param db The database.
32111c72909abbfe7559bcc880c339399f1eaa0478f3Andy McFadden     * @param newId The ID of the new event.
32121c72909abbfe7559bcc880c339399f1eaa0478f3Andy McFadden     * @param id The ID of the old event.
32131c72909abbfe7559bcc880c339399f1eaa0478f3Andy McFadden     */
3214bcba82631ab0ee16efe58f0e0b0b9c18d93a6fd2Andy McFadden    static void copyEventRelatedTables(SQLiteDatabase db, long newId, long id) {
32159ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert        db.execSQL("INSERT INTO " + Tables.REMINDERS
3216b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + " ( "  + CalendarContract.Reminders.EVENT_ID + ", "
3217b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                        + LAST_SYNCED_REMINDER_COLUMNS + ") "
32189ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                + "SELECT ?," + LAST_SYNCED_REMINDER_COLUMNS
32199ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                + " FROM " + Tables.REMINDERS
3220b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + " WHERE " + CalendarContract.Reminders.EVENT_ID + " = ?",
32219ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                new Object[] {newId, id});
32229ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert        db.execSQL("INSERT INTO "
32239ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                + Tables.ATTENDEES
3224b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + " (" + CalendarContract.Attendees.EVENT_ID + ","
3225b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                        + LAST_SYNCED_ATTENDEE_COLUMNS + ") "
32269ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                + "SELECT ?," + LAST_SYNCED_ATTENDEE_COLUMNS + " FROM " + Tables.ATTENDEES
3227b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + " WHERE " + CalendarContract.Attendees.EVENT_ID + " = ?",
32289ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                new Object[] {newId, id});
32299ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert        db.execSQL("INSERT INTO " + Tables.EXTENDED_PROPERTIES
3230b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + " (" + CalendarContract.ExtendedProperties.EVENT_ID + ","
32319ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                + LAST_SYNCED_EXTENDED_PROPERTY_COLUMNS + ") "
32329ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                + "SELECT ?, " + LAST_SYNCED_EXTENDED_PROPERTY_COLUMNS
32339ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                + " FROM " + Tables.EXTENDED_PROPERTIES
3234b9644fe24edf9e25f0b21c1394e88d25070e0238RoboErik                + " WHERE " + CalendarContract.ExtendedProperties.EVENT_ID + " = ?",
32359ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                new Object[]{newId, id});
32369ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert    }
32379ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert
32389ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert    protected void removeDuplicateEvent(final long id) {
32399ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert        final SQLiteDatabase db = getWritableDatabase();
32409ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert        final Cursor cursor = db.rawQuery("SELECT " + Events._ID + " FROM " + Tables.EVENTS
32419ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                + " WHERE " + Events._SYNC_ID
32429ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                + " = (SELECT " + Events._SYNC_ID
32439ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                + " FROM " + Tables.EVENTS
32449ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                + " WHERE " + Events._ID + " = ?) "
32459ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                + "AND " + Events.LAST_SYNCED + " = ?",
32469ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                new String[]{
32479ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                        String.valueOf(id),
32489ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                        "1", // Events.LAST_SYNCED
32499ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                });
32509ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert        try {
32519ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert            // there should only be at most one but this can't hurt
32529ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert            if (cursor.moveToNext()) {
32539ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                final long dupId = cursor.getLong(0);
32549ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert
32559ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                if (Log.isLoggable(TAG, Log.VERBOSE)) {
32569ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                    Log.v(TAG, "Removing duplicate event " + dupId + " of original event " + id);
32579ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                }
32589ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                // triggers will clean up related tables.
32599ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert                db.execSQL("DELETE FROM Events WHERE " + Events._ID + " = ?", new Object[]{dupId});
32609ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert            }
32619ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert        } finally {
32629ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert          cursor.close();
32639ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert        }
32649ec70fada3d8f7cf56d6b0d0947823ec5bce572cAlon Albert    }
32659f005e4843925efe4fa8434361c4ad4ad384ed4cKen Shirriff}
3266