11a7925761a5db1b424d976ba03fb335e821b7db3Patrick Scott/*
28188813bc869d3df4885f9c2972f9cc85745b59bPaul Sliwowski * Copyright (C) 2013 The Android Open Source Project
31a7925761a5db1b424d976ba03fb335e821b7db3Patrick Scott *
41a7925761a5db1b424d976ba03fb335e821b7db3Patrick Scott * Licensed under the Apache License, Version 2.0 (the "License");
51a7925761a5db1b424d976ba03fb335e821b7db3Patrick Scott * you may not use this file except in compliance with the License.
61a7925761a5db1b424d976ba03fb335e821b7db3Patrick Scott * You may obtain a copy of the License at
71a7925761a5db1b424d976ba03fb335e821b7db3Patrick Scott *
81a7925761a5db1b424d976ba03fb335e821b7db3Patrick Scott *      http://www.apache.org/licenses/LICENSE-2.0
91a7925761a5db1b424d976ba03fb335e821b7db3Patrick Scott *
101a7925761a5db1b424d976ba03fb335e821b7db3Patrick Scott * Unless required by applicable law or agreed to in writing, software
111a7925761a5db1b424d976ba03fb335e821b7db3Patrick Scott * distributed under the License is distributed on an "AS IS" BASIS,
121a7925761a5db1b424d976ba03fb335e821b7db3Patrick Scott * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131a7925761a5db1b424d976ba03fb335e821b7db3Patrick Scott * See the License for the specific language governing permissions and
141a7925761a5db1b424d976ba03fb335e821b7db3Patrick Scott * limitations under the License.
151a7925761a5db1b424d976ba03fb335e821b7db3Patrick Scott */
161a7925761a5db1b424d976ba03fb335e821b7db3Patrick Scott
17b839a7d1f42a1f3d58887f5a3c7978791d508cdbPaul Sliwowskipackage com.android.deskclock.provider;
181a7925761a5db1b424d976ba03fb335e821b7db3Patrick Scott
191a7925761a5db1b424d976ba03fb335e821b7db3Patrick Scottimport android.content.ContentValues;
201a7925761a5db1b424d976ba03fb335e821b7db3Patrick Scottimport android.content.Context;
210a117b5dee4c7666ab9c15787d4e0a802545278aChiao Chengimport android.database.Cursor;
221a7925761a5db1b424d976ba03fb335e821b7db3Patrick Scottimport android.database.SQLException;
231a7925761a5db1b424d976ba03fb335e821b7db3Patrick Scottimport android.database.sqlite.SQLiteDatabase;
241a7925761a5db1b424d976ba03fb335e821b7db3Patrick Scottimport android.database.sqlite.SQLiteOpenHelper;
25ab0d28c68a77bea2a4a2ee50378da3670a1dd939Paul Sliwowskiimport android.net.Uri;
26fd8ddaaa59e8b5e150ac450baad16dfaee1b1881Paul Sliwowskiimport android.text.TextUtils;
271a7925761a5db1b424d976ba03fb335e821b7db3Patrick Scott
28cdbb71b08c13c84af850f4036febc0b90dcfcc7dJustin Klaassenimport com.android.deskclock.LogUtils;
29ab0d28c68a77bea2a4a2ee50378da3670a1dd939Paul Sliwowski
30ab0d28c68a77bea2a4a2ee50378da3670a1dd939Paul Sliwowskiimport java.util.Calendar;
31b839a7d1f42a1f3d58887f5a3c7978791d508cdbPaul Sliwowski
321a7925761a5db1b424d976ba03fb335e821b7db3Patrick Scott/**
331a7925761a5db1b424d976ba03fb335e821b7db3Patrick Scott * Helper class for opening the database from multiple providers.  Also provides
341a7925761a5db1b424d976ba03fb335e821b7db3Patrick Scott * some common functionality.
351a7925761a5db1b424d976ba03fb335e821b7db3Patrick Scott */
36b839a7d1f42a1f3d58887f5a3c7978791d508cdbPaul Sliwowskiclass ClockDatabaseHelper extends SQLiteOpenHelper {
37ab0d28c68a77bea2a4a2ee50378da3670a1dd939Paul Sliwowski    /**
38ab0d28c68a77bea2a4a2ee50378da3670a1dd939Paul Sliwowski     * Original Clock Database.
39ab0d28c68a77bea2a4a2ee50378da3670a1dd939Paul Sliwowski     **/
40ab0d28c68a77bea2a4a2ee50378da3670a1dd939Paul Sliwowski    private static final int VERSION_5 = 5;
41ab0d28c68a77bea2a4a2ee50378da3670a1dd939Paul Sliwowski
42ab0d28c68a77bea2a4a2ee50378da3670a1dd939Paul Sliwowski    /**
43ab0d28c68a77bea2a4a2ee50378da3670a1dd939Paul Sliwowski     * Added alarm_instances table
44ab0d28c68a77bea2a4a2ee50378da3670a1dd939Paul Sliwowski     * Added selected_cities table
45ab0d28c68a77bea2a4a2ee50378da3670a1dd939Paul Sliwowski     * Added DELETE_AFTER_USE column to alarms table
46ab0d28c68a77bea2a4a2ee50378da3670a1dd939Paul Sliwowski     */
47ab0d28c68a77bea2a4a2ee50378da3670a1dd939Paul Sliwowski    private static final int VERSION_6 = 6;
48ab0d28c68a77bea2a4a2ee50378da3670a1dd939Paul Sliwowski
49ab0d28c68a77bea2a4a2ee50378da3670a1dd939Paul Sliwowski    /**
50ab0d28c68a77bea2a4a2ee50378da3670a1dd939Paul Sliwowski     * Added alarm settings to instance table.
51ab0d28c68a77bea2a4a2ee50378da3670a1dd939Paul Sliwowski     */
52ab0d28c68a77bea2a4a2ee50378da3670a1dd939Paul Sliwowski    private static final int VERSION_7 = 7;
531a7925761a5db1b424d976ba03fb335e821b7db3Patrick Scott
540750923e1ee389c0987e19801ec12d5de53d4b57James Lemieux    /**
550750923e1ee389c0987e19801ec12d5de53d4b57James Lemieux     * Removed selected_cities table.
560750923e1ee389c0987e19801ec12d5de53d4b57James Lemieux     */
570750923e1ee389c0987e19801ec12d5de53d4b57James Lemieux    private static final int VERSION_8 = 8;
580750923e1ee389c0987e19801ec12d5de53d4b57James Lemieux
598188813bc869d3df4885f9c2972f9cc85745b59bPaul Sliwowski    // This creates a default alarm at 8:30 for every Mon,Tue,Wed,Thu,Fri
60c2d5ab6a6ce4721f17d97eef1250a90a583397afJames Lemieux    private static final String DEFAULT_ALARM_1 = "(8, 30, 31, 0, 1, '', NULL, 0);";
618188813bc869d3df4885f9c2972f9cc85745b59bPaul Sliwowski
628188813bc869d3df4885f9c2972f9cc85745b59bPaul Sliwowski    // This creates a default alarm at 9:30 for every Sat,Sun
63c2d5ab6a6ce4721f17d97eef1250a90a583397afJames Lemieux    private static final String DEFAULT_ALARM_2 = "(9, 00, 96, 0, 1, '', NULL, 0);";
648188813bc869d3df4885f9c2972f9cc85745b59bPaul Sliwowski
658188813bc869d3df4885f9c2972f9cc85745b59bPaul Sliwowski    // Database and table names
668188813bc869d3df4885f9c2972f9cc85745b59bPaul Sliwowski    static final String DATABASE_NAME = "alarms.db";
67ab0d28c68a77bea2a4a2ee50378da3670a1dd939Paul Sliwowski    static final String OLD_ALARMS_TABLE_NAME = "alarms";
68ab0d28c68a77bea2a4a2ee50378da3670a1dd939Paul Sliwowski    static final String ALARMS_TABLE_NAME = "alarm_templates";
698188813bc869d3df4885f9c2972f9cc85745b59bPaul Sliwowski    static final String INSTANCES_TABLE_NAME = "alarm_instances";
700750923e1ee389c0987e19801ec12d5de53d4b57James Lemieux    private static final String SELECTED_CITIES_TABLE_NAME = "selected_cities";
718188813bc869d3df4885f9c2972f9cc85745b59bPaul Sliwowski
728188813bc869d3df4885f9c2972f9cc85745b59bPaul Sliwowski    private static void createAlarmsTable(SQLiteDatabase db) {
738188813bc869d3df4885f9c2972f9cc85745b59bPaul Sliwowski        db.execSQL("CREATE TABLE " + ALARMS_TABLE_NAME + " (" +
748188813bc869d3df4885f9c2972f9cc85745b59bPaul Sliwowski                ClockContract.AlarmsColumns._ID + " INTEGER PRIMARY KEY," +
75ab0d28c68a77bea2a4a2ee50378da3670a1dd939Paul Sliwowski                ClockContract.AlarmsColumns.HOUR + " INTEGER NOT NULL, " +
76ab0d28c68a77bea2a4a2ee50378da3670a1dd939Paul Sliwowski                ClockContract.AlarmsColumns.MINUTES + " INTEGER NOT NULL, " +
77ab0d28c68a77bea2a4a2ee50378da3670a1dd939Paul Sliwowski                ClockContract.AlarmsColumns.DAYS_OF_WEEK + " INTEGER NOT NULL, " +
78ab0d28c68a77bea2a4a2ee50378da3670a1dd939Paul Sliwowski                ClockContract.AlarmsColumns.ENABLED + " INTEGER NOT NULL, " +
79ab0d28c68a77bea2a4a2ee50378da3670a1dd939Paul Sliwowski                ClockContract.AlarmsColumns.VIBRATE + " INTEGER NOT NULL, " +
80ab0d28c68a77bea2a4a2ee50378da3670a1dd939Paul Sliwowski                ClockContract.AlarmsColumns.LABEL + " TEXT NOT NULL, " +
81ab0d28c68a77bea2a4a2ee50378da3670a1dd939Paul Sliwowski                ClockContract.AlarmsColumns.RINGTONE + " TEXT, " +
822f2584bdcabbf2f114f48efcab7ceb0a34067761Annie Chin                ClockContract.AlarmsColumns.DELETE_AFTER_USE + " INTEGER NOT NULL DEFAULT 0);");
83cdbb71b08c13c84af850f4036febc0b90dcfcc7dJustin Klaassen        LogUtils.i("Alarms Table created");
848188813bc869d3df4885f9c2972f9cc85745b59bPaul Sliwowski    }
858188813bc869d3df4885f9c2972f9cc85745b59bPaul Sliwowski
868188813bc869d3df4885f9c2972f9cc85745b59bPaul Sliwowski    private static void createInstanceTable(SQLiteDatabase db) {
878188813bc869d3df4885f9c2972f9cc85745b59bPaul Sliwowski        db.execSQL("CREATE TABLE " + INSTANCES_TABLE_NAME + " (" +
888188813bc869d3df4885f9c2972f9cc85745b59bPaul Sliwowski                ClockContract.InstancesColumns._ID + " INTEGER PRIMARY KEY," +
89ab0d28c68a77bea2a4a2ee50378da3670a1dd939Paul Sliwowski                ClockContract.InstancesColumns.YEAR + " INTEGER NOT NULL, " +
90ab0d28c68a77bea2a4a2ee50378da3670a1dd939Paul Sliwowski                ClockContract.InstancesColumns.MONTH + " INTEGER NOT NULL, " +
91ab0d28c68a77bea2a4a2ee50378da3670a1dd939Paul Sliwowski                ClockContract.InstancesColumns.DAY + " INTEGER NOT NULL, " +
92ab0d28c68a77bea2a4a2ee50378da3670a1dd939Paul Sliwowski                ClockContract.InstancesColumns.HOUR + " INTEGER NOT NULL, " +
93ab0d28c68a77bea2a4a2ee50378da3670a1dd939Paul Sliwowski                ClockContract.InstancesColumns.MINUTES + " INTEGER NOT NULL, " +
94ab0d28c68a77bea2a4a2ee50378da3670a1dd939Paul Sliwowski                ClockContract.InstancesColumns.VIBRATE + " INTEGER NOT NULL, " +
95ab0d28c68a77bea2a4a2ee50378da3670a1dd939Paul Sliwowski                ClockContract.InstancesColumns.LABEL + " TEXT NOT NULL, " +
96ab0d28c68a77bea2a4a2ee50378da3670a1dd939Paul Sliwowski                ClockContract.InstancesColumns.RINGTONE + " TEXT, " +
97ab0d28c68a77bea2a4a2ee50378da3670a1dd939Paul Sliwowski                ClockContract.InstancesColumns.ALARM_STATE + " INTEGER NOT NULL, " +
988188813bc869d3df4885f9c2972f9cc85745b59bPaul Sliwowski                ClockContract.InstancesColumns.ALARM_ID + " INTEGER REFERENCES " +
998188813bc869d3df4885f9c2972f9cc85745b59bPaul Sliwowski                    ALARMS_TABLE_NAME + "(" + ClockContract.AlarmsColumns._ID + ") " +
1008188813bc869d3df4885f9c2972f9cc85745b59bPaul Sliwowski                    "ON UPDATE CASCADE ON DELETE CASCADE" +
1018188813bc869d3df4885f9c2972f9cc85745b59bPaul Sliwowski                ");");
102cdbb71b08c13c84af850f4036febc0b90dcfcc7dJustin Klaassen        LogUtils.i("Instance table created");
1038188813bc869d3df4885f9c2972f9cc85745b59bPaul Sliwowski    }
1048188813bc869d3df4885f9c2972f9cc85745b59bPaul Sliwowski
105b839a7d1f42a1f3d58887f5a3c7978791d508cdbPaul Sliwowski    public ClockDatabaseHelper(Context context) {
1060750923e1ee389c0987e19801ec12d5de53d4b57James Lemieux        super(context, DATABASE_NAME, null, VERSION_8);
1071a7925761a5db1b424d976ba03fb335e821b7db3Patrick Scott    }
1081a7925761a5db1b424d976ba03fb335e821b7db3Patrick Scott
1091a7925761a5db1b424d976ba03fb335e821b7db3Patrick Scott    @Override
1101a7925761a5db1b424d976ba03fb335e821b7db3Patrick Scott    public void onCreate(SQLiteDatabase db) {
1118188813bc869d3df4885f9c2972f9cc85745b59bPaul Sliwowski        createAlarmsTable(db);
1128188813bc869d3df4885f9c2972f9cc85745b59bPaul Sliwowski        createInstanceTable(db);
1131a7925761a5db1b424d976ba03fb335e821b7db3Patrick Scott
1141a7925761a5db1b424d976ba03fb335e821b7db3Patrick Scott        // insert default alarms
115cdbb71b08c13c84af850f4036febc0b90dcfcc7dJustin Klaassen        LogUtils.i("Inserting default alarms");
116982295f9412d9ce7474c902aa0d8de8fce9890d4Isaac Katzenelson        String cs = ", "; //comma and space
1178188813bc869d3df4885f9c2972f9cc85745b59bPaul Sliwowski        String insertMe = "INSERT INTO " + ALARMS_TABLE_NAME + " (" +
1188188813bc869d3df4885f9c2972f9cc85745b59bPaul Sliwowski                ClockContract.AlarmsColumns.HOUR + cs +
1198188813bc869d3df4885f9c2972f9cc85745b59bPaul Sliwowski                ClockContract.AlarmsColumns.MINUTES + cs +
1208188813bc869d3df4885f9c2972f9cc85745b59bPaul Sliwowski                ClockContract.AlarmsColumns.DAYS_OF_WEEK + cs +
1218188813bc869d3df4885f9c2972f9cc85745b59bPaul Sliwowski                ClockContract.AlarmsColumns.ENABLED + cs +
1228188813bc869d3df4885f9c2972f9cc85745b59bPaul Sliwowski                ClockContract.AlarmsColumns.VIBRATE + cs +
123ab0d28c68a77bea2a4a2ee50378da3670a1dd939Paul Sliwowski                ClockContract.AlarmsColumns.LABEL + cs +
124ab0d28c68a77bea2a4a2ee50378da3670a1dd939Paul Sliwowski                ClockContract.AlarmsColumns.RINGTONE + cs +
1252f2584bdcabbf2f114f48efcab7ceb0a34067761Annie Chin                ClockContract.AlarmsColumns.DELETE_AFTER_USE + ") VALUES ";
1268188813bc869d3df4885f9c2972f9cc85745b59bPaul Sliwowski        db.execSQL(insertMe + DEFAULT_ALARM_1);
1278188813bc869d3df4885f9c2972f9cc85745b59bPaul Sliwowski        db.execSQL(insertMe + DEFAULT_ALARM_2);
1281a7925761a5db1b424d976ba03fb335e821b7db3Patrick Scott    }
1291a7925761a5db1b424d976ba03fb335e821b7db3Patrick Scott
1301a7925761a5db1b424d976ba03fb335e821b7db3Patrick Scott    @Override
1318188813bc869d3df4885f9c2972f9cc85745b59bPaul Sliwowski    public void onUpgrade(SQLiteDatabase db, int oldVersion, int currentVersion) {
1320750923e1ee389c0987e19801ec12d5de53d4b57James Lemieux        LogUtils.v("Upgrading alarms database from version %d to %d", oldVersion, currentVersion);
1330750923e1ee389c0987e19801ec12d5de53d4b57James Lemieux
1340750923e1ee389c0987e19801ec12d5de53d4b57James Lemieux        if (oldVersion <= VERSION_7) {
1350750923e1ee389c0987e19801ec12d5de53d4b57James Lemieux            // This was not used in VERSION_7 or prior, so we can just drop it.
1360750923e1ee389c0987e19801ec12d5de53d4b57James Lemieux            db.execSQL("DROP TABLE IF EXISTS " + SELECTED_CITIES_TABLE_NAME + ";");
1370750923e1ee389c0987e19801ec12d5de53d4b57James Lemieux        }
1388188813bc869d3df4885f9c2972f9cc85745b59bPaul Sliwowski
139ab0d28c68a77bea2a4a2ee50378da3670a1dd939Paul Sliwowski        if (oldVersion <= VERSION_6) {
1400750923e1ee389c0987e19801ec12d5de53d4b57James Lemieux            // This was not used in VERSION_6 or prior, so we can just drop it.
1412f2584bdcabbf2f114f48efcab7ceb0a34067761Annie Chin            db.execSQL("DROP TABLE IF EXISTS " + INSTANCES_TABLE_NAME + ";");
1422f2584bdcabbf2f114f48efcab7ceb0a34067761Annie Chin
1432f2584bdcabbf2f114f48efcab7ceb0a34067761Annie Chin            // Create new alarms table and copy over the data
1442f2584bdcabbf2f114f48efcab7ceb0a34067761Annie Chin            createAlarmsTable(db);
1452f2584bdcabbf2f114f48efcab7ceb0a34067761Annie Chin            createInstanceTable(db);
1462f2584bdcabbf2f114f48efcab7ceb0a34067761Annie Chin
1472f2584bdcabbf2f114f48efcab7ceb0a34067761Annie Chin            LogUtils.i("Copying old alarms to new table");
148c2d5ab6a6ce4721f17d97eef1250a90a583397afJames Lemieux            final String[] OLD_TABLE_COLUMNS = {
1492f2584bdcabbf2f114f48efcab7ceb0a34067761Annie Chin                    "_id",
1502f2584bdcabbf2f114f48efcab7ceb0a34067761Annie Chin                    "hour",
1512f2584bdcabbf2f114f48efcab7ceb0a34067761Annie Chin                    "minutes",
1522f2584bdcabbf2f114f48efcab7ceb0a34067761Annie Chin                    "daysofweek",
1532f2584bdcabbf2f114f48efcab7ceb0a34067761Annie Chin                    "enabled",
1542f2584bdcabbf2f114f48efcab7ceb0a34067761Annie Chin                    "vibrate",
1552f2584bdcabbf2f114f48efcab7ceb0a34067761Annie Chin                    "message",
1562f2584bdcabbf2f114f48efcab7ceb0a34067761Annie Chin                    "alert",
1572f2584bdcabbf2f114f48efcab7ceb0a34067761Annie Chin            };
158c2d5ab6a6ce4721f17d97eef1250a90a583397afJames Lemieux            try (Cursor cursor = db.query(OLD_ALARMS_TABLE_NAME, OLD_TABLE_COLUMNS,
159c2d5ab6a6ce4721f17d97eef1250a90a583397afJames Lemieux                    null, null, null, null, null)) {
160c2d5ab6a6ce4721f17d97eef1250a90a583397afJames Lemieux                final Calendar currentTime = Calendar.getInstance();
1610750923e1ee389c0987e19801ec12d5de53d4b57James Lemieux                while (cursor != null && cursor.moveToNext()) {
162c2d5ab6a6ce4721f17d97eef1250a90a583397afJames Lemieux                    final Alarm alarm = new Alarm();
163c2d5ab6a6ce4721f17d97eef1250a90a583397afJames Lemieux                    alarm.id = cursor.getLong(0);
164c2d5ab6a6ce4721f17d97eef1250a90a583397afJames Lemieux                    alarm.hour = cursor.getInt(1);
165c2d5ab6a6ce4721f17d97eef1250a90a583397afJames Lemieux                    alarm.minutes = cursor.getInt(2);
166c2d5ab6a6ce4721f17d97eef1250a90a583397afJames Lemieux                    alarm.daysOfWeek = new DaysOfWeek(cursor.getInt(3));
167c2d5ab6a6ce4721f17d97eef1250a90a583397afJames Lemieux                    alarm.enabled = cursor.getInt(4) == 1;
168c2d5ab6a6ce4721f17d97eef1250a90a583397afJames Lemieux                    alarm.vibrate = cursor.getInt(5) == 1;
169c2d5ab6a6ce4721f17d97eef1250a90a583397afJames Lemieux                    alarm.label = cursor.getString(6);
170c2d5ab6a6ce4721f17d97eef1250a90a583397afJames Lemieux
171c2d5ab6a6ce4721f17d97eef1250a90a583397afJames Lemieux                    final String alertString = cursor.getString(7);
172c2d5ab6a6ce4721f17d97eef1250a90a583397afJames Lemieux                    if ("silent".equals(alertString)) {
173c2d5ab6a6ce4721f17d97eef1250a90a583397afJames Lemieux                        alarm.alert = Alarm.NO_RINGTONE_URI;
174c2d5ab6a6ce4721f17d97eef1250a90a583397afJames Lemieux                    } else {
175c2d5ab6a6ce4721f17d97eef1250a90a583397afJames Lemieux                        alarm.alert =
176c2d5ab6a6ce4721f17d97eef1250a90a583397afJames Lemieux                                TextUtils.isEmpty(alertString) ? null : Uri.parse(alertString);
177c2d5ab6a6ce4721f17d97eef1250a90a583397afJames Lemieux                    }
1782f2584bdcabbf2f114f48efcab7ceb0a34067761Annie Chin
1790750923e1ee389c0987e19801ec12d5de53d4b57James Lemieux                    // Save new version of alarm and create alarm instance for it
180c2d5ab6a6ce4721f17d97eef1250a90a583397afJames Lemieux                    db.insert(ALARMS_TABLE_NAME, null, Alarm.createContentValues(alarm));
181c2d5ab6a6ce4721f17d97eef1250a90a583397afJames Lemieux                    if (alarm.enabled) {
182c2d5ab6a6ce4721f17d97eef1250a90a583397afJames Lemieux                        AlarmInstance newInstance = alarm.createInstanceAfter(currentTime);
183c2d5ab6a6ce4721f17d97eef1250a90a583397afJames Lemieux                        db.insert(INSTANCES_TABLE_NAME, null,
184c2d5ab6a6ce4721f17d97eef1250a90a583397afJames Lemieux                                AlarmInstance.createContentValues(newInstance));
185c2d5ab6a6ce4721f17d97eef1250a90a583397afJames Lemieux                    }
1862f2584bdcabbf2f114f48efcab7ceb0a34067761Annie Chin                }
187ab0d28c68a77bea2a4a2ee50378da3670a1dd939Paul Sliwowski            }
188ab0d28c68a77bea2a4a2ee50378da3670a1dd939Paul Sliwowski
1892f2584bdcabbf2f114f48efcab7ceb0a34067761Annie Chin            LogUtils.i("Dropping old alarm table");
1902f2584bdcabbf2f114f48efcab7ceb0a34067761Annie Chin            db.execSQL("DROP TABLE IF EXISTS " + OLD_ALARMS_TABLE_NAME + ";");
1918188813bc869d3df4885f9c2972f9cc85745b59bPaul Sliwowski        }
1921a7925761a5db1b424d976ba03fb335e821b7db3Patrick Scott    }
1931a7925761a5db1b424d976ba03fb335e821b7db3Patrick Scott
1948188813bc869d3df4885f9c2972f9cc85745b59bPaul Sliwowski    long fixAlarmInsert(ContentValues values) {
195ab0d28c68a77bea2a4a2ee50378da3670a1dd939Paul Sliwowski        // Why are we doing this? Is this not a programming bug if we try to
196ab0d28c68a77bea2a4a2ee50378da3670a1dd939Paul Sliwowski        // insert an already used id?
197c2d5ab6a6ce4721f17d97eef1250a90a583397afJames Lemieux        final SQLiteDatabase db = getWritableDatabase();
1980a117b5dee4c7666ab9c15787d4e0a802545278aChiao Cheng        db.beginTransaction();
1990a117b5dee4c7666ab9c15787d4e0a802545278aChiao Cheng        long rowId = -1;
2000a117b5dee4c7666ab9c15787d4e0a802545278aChiao Cheng        try {
2010a117b5dee4c7666ab9c15787d4e0a802545278aChiao Cheng            // Check if we are trying to re-use an existing id.
202c2d5ab6a6ce4721f17d97eef1250a90a583397afJames Lemieux            final Object value = values.get(ClockContract.AlarmsColumns._ID);
2030a117b5dee4c7666ab9c15787d4e0a802545278aChiao Cheng            if (value != null) {
204b9dff52be236a4c3a2088ecbbdf9811b0533d21fSam Blitzstein                long id = (Long) value;
2050a117b5dee4c7666ab9c15787d4e0a802545278aChiao Cheng                if (id > -1) {
206c2d5ab6a6ce4721f17d97eef1250a90a583397afJames Lemieux                    final String[] columns = {ClockContract.AlarmsColumns._ID};
207c2d5ab6a6ce4721f17d97eef1250a90a583397afJames Lemieux                    final String selection = ClockContract.AlarmsColumns._ID + " = ?";
208c2d5ab6a6ce4721f17d97eef1250a90a583397afJames Lemieux                    final String[] selectionArgs = {String.valueOf(id)};
209c2d5ab6a6ce4721f17d97eef1250a90a583397afJames Lemieux                    try (Cursor cursor = db.query(ALARMS_TABLE_NAME, columns, selection,
210c2d5ab6a6ce4721f17d97eef1250a90a583397afJames Lemieux                            selectionArgs, null, null, null)) {
211c2d5ab6a6ce4721f17d97eef1250a90a583397afJames Lemieux                        if (cursor.moveToFirst()) {
212c2d5ab6a6ce4721f17d97eef1250a90a583397afJames Lemieux                            // Record exists. Remove the id so sqlite can generate a new one.
213c2d5ab6a6ce4721f17d97eef1250a90a583397afJames Lemieux                            values.putNull(ClockContract.AlarmsColumns._ID);
214c2d5ab6a6ce4721f17d97eef1250a90a583397afJames Lemieux                        }
2150a117b5dee4c7666ab9c15787d4e0a802545278aChiao Cheng                    }
2160a117b5dee4c7666ab9c15787d4e0a802545278aChiao Cheng                }
2170a117b5dee4c7666ab9c15787d4e0a802545278aChiao Cheng            }
2180a117b5dee4c7666ab9c15787d4e0a802545278aChiao Cheng
219ab0d28c68a77bea2a4a2ee50378da3670a1dd939Paul Sliwowski            rowId = db.insert(ALARMS_TABLE_NAME, ClockContract.AlarmsColumns.RINGTONE, values);
2200a117b5dee4c7666ab9c15787d4e0a802545278aChiao Cheng            db.setTransactionSuccessful();
2210a117b5dee4c7666ab9c15787d4e0a802545278aChiao Cheng        } finally {
2220a117b5dee4c7666ab9c15787d4e0a802545278aChiao Cheng            db.endTransaction();
2230a117b5dee4c7666ab9c15787d4e0a802545278aChiao Cheng        }
2241a7925761a5db1b424d976ba03fb335e821b7db3Patrick Scott        if (rowId < 0) {
2251a7925761a5db1b424d976ba03fb335e821b7db3Patrick Scott            throw new SQLException("Failed to insert row");
2261a7925761a5db1b424d976ba03fb335e821b7db3Patrick Scott        }
227cdbb71b08c13c84af850f4036febc0b90dcfcc7dJustin Klaassen        LogUtils.v("Added alarm rowId = " + rowId);
2281a7925761a5db1b424d976ba03fb335e821b7db3Patrick Scott
2298188813bc869d3df4885f9c2972f9cc85745b59bPaul Sliwowski        return rowId;
2301a7925761a5db1b424d976ba03fb335e821b7db3Patrick Scott    }
2311a7925761a5db1b424d976ba03fb335e821b7db3Patrick Scott}
232