blob: 2d09008fa0ae9d1b9a53d3a42ca63d65bcc24e7c [file] [log] [blame]
The Android Open Source Project7236c3a2009-03-03 19:32:44 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.providers.telephony;
18
Tom Taylor10faf3f2011-04-27 10:05:03 -070019import android.content.BroadcastReceiver;
Mark Wagner8e5ee782010-01-04 17:39:06 -080020import android.content.ContentValues;
The Android Open Source Project7236c3a2009-03-03 19:32:44 -080021import android.content.Context;
Tom Taylor10faf3f2011-04-27 10:05:03 -070022import android.content.Intent;
23import android.content.IntentFilter;
Prasath Balakrishnan1dfaed12015-11-18 20:36:17 +053024import android.content.SharedPreferences;
25import android.content.SharedPreferences.Editor;
The Android Open Source Project7236c3a2009-03-03 19:32:44 -080026import android.database.Cursor;
27import android.database.sqlite.SQLiteDatabase;
yanglv3dd0bab2015-08-24 10:40:19 +080028import android.database.sqlite.SQLiteException;
The Android Open Source Project7236c3a2009-03-03 19:32:44 -080029import android.database.sqlite.SQLiteOpenHelper;
30import android.provider.BaseColumns;
Mark Wagner8e5ee782010-01-04 17:39:06 -080031import android.provider.Telephony;
The Android Open Source Project7236c3a2009-03-03 19:32:44 -080032import android.provider.Telephony.Mms;
The Android Open Source Project7236c3a2009-03-03 19:32:44 -080033import android.provider.Telephony.Mms.Addr;
34import android.provider.Telephony.Mms.Part;
35import android.provider.Telephony.Mms.Rate;
Ye Wen72f13552015-03-10 14:17:13 -070036import android.provider.Telephony.MmsSms;
The Android Open Source Project7236c3a2009-03-03 19:32:44 -080037import android.provider.Telephony.MmsSms.PendingMessages;
Ye Wen72f13552015-03-10 14:17:13 -070038import android.provider.Telephony.Sms;
39import android.provider.Telephony.Threads;
Shri Bordea58acf32014-09-17 15:18:01 -070040import android.telephony.SubscriptionManager;
The Android Open Source Project7236c3a2009-03-03 19:32:44 -080041import android.util.Log;
42
Tom Taylorb1bae652010-03-08 16:33:42 -080043import com.google.android.mms.pdu.EncodedStringValue;
44import com.google.android.mms.pdu.PduHeaders;
Tom Taylorc71e7702010-01-28 09:23:12 -080045
Ye Wen72f13552015-03-10 14:17:13 -070046import java.io.File;
47import java.io.FileInputStream;
48import java.io.IOException;
49import java.io.InputStream;
50import java.util.ArrayList;
51import java.util.HashSet;
52import java.util.Iterator;
53
The Android Open Source Project7236c3a2009-03-03 19:32:44 -080054public class MmsSmsDatabaseHelper extends SQLiteOpenHelper {
55 private static final String TAG = "MmsSmsDatabaseHelper";
56
57 private static final String SMS_UPDATE_THREAD_READ_BODY =
58 " UPDATE threads SET read = " +
59 " CASE (SELECT COUNT(*)" +
60 " FROM sms" +
61 " WHERE " + Sms.READ + " = 0" +
62 " AND " + Sms.THREAD_ID + " = threads._id)" +
63 " WHEN 0 THEN 1" +
64 " ELSE 0" +
65 " END" +
66 " WHERE threads._id = new." + Sms.THREAD_ID + "; ";
67
68 private static final String UPDATE_THREAD_COUNT_ON_NEW =
69 " UPDATE threads SET message_count = " +
70 " (SELECT COUNT(sms._id) FROM sms LEFT JOIN threads " +
71 " ON threads._id = " + Sms.THREAD_ID +
72 " WHERE " + Sms.THREAD_ID + " = new.thread_id" +
73 " AND sms." + Sms.TYPE + " != 3) + " +
74 " (SELECT COUNT(pdu._id) FROM pdu LEFT JOIN threads " +
75 " ON threads._id = " + Mms.THREAD_ID +
76 " WHERE " + Mms.THREAD_ID + " = new.thread_id" +
77 " AND (m_type=132 OR m_type=130 OR m_type=128)" +
78 " AND " + Mms.MESSAGE_BOX + " != 3) " +
79 " WHERE threads._id = new.thread_id; ";
80
The Android Open Source Project7236c3a2009-03-03 19:32:44 -080081 private static final String SMS_UPDATE_THREAD_DATE_SNIPPET_COUNT_ON_UPDATE =
82 "BEGIN" +
83 " UPDATE threads SET" +
84 " date = (strftime('%s','now') * 1000), " +
85 " snippet = new." + Sms.BODY + ", " +
86 " snippet_cs = 0" +
87 " WHERE threads._id = new." + Sms.THREAD_ID + "; " +
88 UPDATE_THREAD_COUNT_ON_NEW +
89 SMS_UPDATE_THREAD_READ_BODY +
90 "END;";
91
92 private static final String PDU_UPDATE_THREAD_CONSTRAINTS =
Tom Taylorc71e7702010-01-28 09:23:12 -080093 " WHEN new." + Mms.MESSAGE_TYPE + "=" +
94 PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF +
95 " OR new." + Mms.MESSAGE_TYPE + "=" +
96 PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND +
97 " OR new." + Mms.MESSAGE_TYPE + "=" +
98 PduHeaders.MESSAGE_TYPE_SEND_REQ + " ";
The Android Open Source Project7236c3a2009-03-03 19:32:44 -080099
Tom Taylor1e47c482010-03-12 16:14:50 -0800100 // When looking in the pdu table for unread messages, only count messages that
101 // are displayed to the user. The constants are defined in PduHeaders and could be used
102 // here, but the string "(m_type=132 OR m_type=130 OR m_type=128)" is used throughout this
103 // file and so it is used here to be consistent.
104 // m_type=128 = MESSAGE_TYPE_SEND_REQ
105 // m_type=130 = MESSAGE_TYPE_NOTIFICATION_IND
106 // m_type=132 = MESSAGE_TYPE_RETRIEVE_CONF
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800107 private static final String PDU_UPDATE_THREAD_READ_BODY =
108 " UPDATE threads SET read = " +
109 " CASE (SELECT COUNT(*)" +
110 " FROM " + MmsProvider.TABLE_PDU +
111 " WHERE " + Mms.READ + " = 0" +
Tom Taylor1e47c482010-03-12 16:14:50 -0800112 " AND " + Mms.THREAD_ID + " = threads._id " +
113 " AND (m_type=132 OR m_type=130 OR m_type=128)) " +
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800114 " WHEN 0 THEN 1" +
115 " ELSE 0" +
116 " END" +
117 " WHERE threads._id = new." + Mms.THREAD_ID + "; ";
118
119 private static final String PDU_UPDATE_THREAD_DATE_SNIPPET_COUNT_ON_UPDATE =
120 "BEGIN" +
121 " UPDATE threads SET" +
122 " date = (strftime('%s','now') * 1000), " +
123 " snippet = new." + Mms.SUBJECT + ", " +
124 " snippet_cs = new." + Mms.SUBJECT_CHARSET +
125 " WHERE threads._id = new." + Mms.THREAD_ID + "; " +
126 UPDATE_THREAD_COUNT_ON_NEW +
127 PDU_UPDATE_THREAD_READ_BODY +
128 "END;";
129
The Android Open Source Project5f1e43f2009-03-05 14:34:39 -0800130 // When a part is inserted, if it is not text/plain or application/smil
131 // (which both can exist with text-only MMSes), then there is an attachment.
132 // Set has_attachment=1 in the threads table for the thread in question.
133 private static final String PART_UPDATE_THREADS_ON_INSERT_TRIGGER =
134 "CREATE TRIGGER update_threads_on_insert_part " +
135 " AFTER INSERT ON part " +
136 " WHEN new.ct != 'text/plain' AND new.ct != 'application/smil' " +
137 " BEGIN " +
138 " UPDATE threads SET has_attachment=1 WHERE _id IN " +
139 " (SELECT pdu.thread_id FROM part JOIN pdu ON pdu._id=part.mid " +
140 " WHERE part._id=new._id LIMIT 1); " +
141 " END";
Wei Huang2ad5ba82009-03-24 20:01:04 -0700142
143 // When the 'mid' column in the part table is updated, we need to run the trigger to update
144 // the threads table's has_attachment column, if the part is an attachment.
145 private static final String PART_UPDATE_THREADS_ON_UPDATE_TRIGGER =
146 "CREATE TRIGGER update_threads_on_update_part " +
147 " AFTER UPDATE of " + Part.MSG_ID + " ON part " +
148 " WHEN new.ct != 'text/plain' AND new.ct != 'application/smil' " +
149 " BEGIN " +
150 " UPDATE threads SET has_attachment=1 WHERE _id IN " +
151 " (SELECT pdu.thread_id FROM part JOIN pdu ON pdu._id=part.mid " +
152 " WHERE part._id=new._id LIMIT 1); " +
153 " END";
154
Wei Huang1047ab42009-09-29 20:53:26 -0700155 // When the 'thread_id' column in the pdu table is updated, we need to run the trigger to update
156 // the threads table's has_attachment column, if the message has an attachment in 'part' table
157 private static final String PDU_UPDATE_THREADS_ON_UPDATE_TRIGGER =
158 "CREATE TRIGGER update_threads_on_update_pdu " +
159 " AFTER UPDATE of thread_id ON pdu " +
160 " BEGIN " +
161 " UPDATE threads SET has_attachment=1 WHERE _id IN " +
Tom Taylor94489f82010-02-22 16:25:10 -0800162 " (SELECT pdu.thread_id FROM part JOIN pdu " +
163 " WHERE part.ct != 'text/plain' AND part.ct != 'application/smil' " +
164 " AND part.mid = pdu._id);" +
Wei Huang1047ab42009-09-29 20:53:26 -0700165 " END";
166
Tom Taylor10faf3f2011-04-27 10:05:03 -0700167 private static MmsSmsDatabaseHelper sInstance = null;
168 private static boolean sTriedAutoIncrement = false;
169 private static boolean sFakeLowStorageTest = false; // for testing only
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800170
yanglv3dd0bab2015-08-24 10:40:19 +0800171 private static final String NO_SUCH_COLUMN_EXCEPTION_MESSAGE = "no such column";
172 private static final String NO_SUCH_TABLE_EXCEPTION_MESSAGE = "no such table";
173
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800174 static final String DATABASE_NAME = "mmssms.db";
Ye Wen72f13552015-03-10 14:17:13 -0700175 static final int DATABASE_VERSION = 61;
Tom Taylor10faf3f2011-04-27 10:05:03 -0700176 private final Context mContext;
177 private LowStorageMonitor mLowStorageMonitor;
Tom Taylor1ab48002011-04-19 14:15:06 -0700178
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800179 private MmsSmsDatabaseHelper(Context context) {
180 super(context, DATABASE_NAME, null, DATABASE_VERSION);
Tom Taylor10faf3f2011-04-27 10:05:03 -0700181
182 mContext = context;
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800183 }
184
185 /**
186 * Return a singleton helper for the combined MMS and SMS
187 * database.
188 */
189 /* package */ static synchronized MmsSmsDatabaseHelper getInstance(Context context) {
Tom Taylor10faf3f2011-04-27 10:05:03 -0700190 if (sInstance == null) {
191 sInstance = new MmsSmsDatabaseHelper(context);
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800192 }
Tom Taylor10faf3f2011-04-27 10:05:03 -0700193 return sInstance;
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800194 }
195
Tom Taylorf409b0e2011-12-19 12:52:18 -0800196 /**
197 * Look through all the recipientIds referenced by the threads and then delete any
198 * unreferenced rows from the canonical_addresses table.
199 */
200 private static void removeUnferencedCanonicalAddresses(SQLiteDatabase db) {
Tom Taylor15156cd2012-11-15 14:15:46 -0800201 Cursor c = db.query(MmsSmsProvider.TABLE_THREADS, new String[] { "recipient_ids" },
Tom Taylorf409b0e2011-12-19 12:52:18 -0800202 null, null, null, null, null);
203 if (c != null) {
204 try {
205 if (c.getCount() == 0) {
206 // no threads, delete all addresses
207 int rows = db.delete("canonical_addresses", null, null);
208 } else {
209 // Find all the referenced recipient_ids from the threads. recipientIds is
210 // a space-separated list of recipient ids: "1 14 21"
211 HashSet<Integer> recipientIds = new HashSet<Integer>();
212 while (c.moveToNext()) {
213 String[] recips = c.getString(0).split(" ");
214 for (String recip : recips) {
215 try {
216 int recipientId = Integer.parseInt(recip);
217 recipientIds.add(recipientId);
218 } catch (Exception e) {
219 }
220 }
221 }
222 // Now build a selection string of all the unique recipient ids
kaiyiz6d65c1e2014-11-17 18:29:40 +0800223 StringBuilder sb = new StringBuilder("_id not in (");
Tom Taylorf409b0e2011-12-19 12:52:18 -0800224 Iterator<Integer> iter = recipientIds.iterator();
225 while (iter.hasNext()) {
kaiyiz6d65c1e2014-11-17 18:29:40 +0800226 sb.append(iter.next());
Tom Taylorf409b0e2011-12-19 12:52:18 -0800227 if (iter.hasNext()) {
kaiyiz6d65c1e2014-11-17 18:29:40 +0800228 sb.append(",");
Tom Taylorf409b0e2011-12-19 12:52:18 -0800229 }
230 }
kaiyiz6d65c1e2014-11-17 18:29:40 +0800231 sb.append(")");
232 if (recipientIds.size() > 0) {
Tom Taylorf409b0e2011-12-19 12:52:18 -0800233 int rows = db.delete("canonical_addresses", sb.toString(), null);
234 }
235 }
236 } finally {
237 c.close();
238 }
239 }
240 }
241
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800242 public static void updateThread(SQLiteDatabase db, long thread_id) {
243 if (thread_id < 0) {
244 updateAllThreads(db, null, null);
245 return;
246 }
Mark Wagnerf0a9e902009-06-19 16:00:13 -0700247
Tom Taylor842e3112012-09-26 15:01:42 -0700248 db.beginTransaction();
249 try {
250 // Delete the row for this thread in the threads table if
251 // there are no more messages attached to it in either
252 // the sms or pdu tables.
Tom Taylor15156cd2012-11-15 14:15:46 -0800253 int rows = db.delete(MmsSmsProvider.TABLE_THREADS,
Tom Taylor842e3112012-09-26 15:01:42 -0700254 "_id = ? AND _id NOT IN" +
255 " (SELECT thread_id FROM sms " +
256 " UNION SELECT thread_id FROM pdu)",
257 new String[] { String.valueOf(thread_id) });
258 if (rows > 0) {
259 // If this deleted a row, let's remove orphaned canonical_addresses and get outta here
260 removeUnferencedCanonicalAddresses(db);
261 } else {
262 // Update the message count in the threads table as the sum
263 // of all messages in both the sms and pdu tables.
264 db.execSQL(
265 " UPDATE threads SET message_count = " +
266 " (SELECT COUNT(sms._id) FROM sms LEFT JOIN threads " +
267 " ON threads._id = " + Sms.THREAD_ID +
268 " WHERE " + Sms.THREAD_ID + " = " + thread_id +
269 " AND sms." + Sms.TYPE + " != 3) + " +
270 " (SELECT COUNT(pdu._id) FROM pdu LEFT JOIN threads " +
271 " ON threads._id = " + Mms.THREAD_ID +
272 " WHERE " + Mms.THREAD_ID + " = " + thread_id +
273 " AND (m_type=132 OR m_type=130 OR m_type=128)" +
274 " AND " + Mms.MESSAGE_BOX + " != 3) " +
275 " WHERE threads._id = " + thread_id + ";");
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800276
Tom Taylor842e3112012-09-26 15:01:42 -0700277 // Update the date and the snippet (and its character set) in
278 // the threads table to be that of the most recent message in
279 // the thread.
280 db.execSQL(
281 " UPDATE threads" +
282 " SET" +
283 " date =" +
284 " (SELECT date FROM" +
285 " (SELECT date * 1000 AS date, thread_id FROM pdu" +
286 " UNION SELECT date, thread_id FROM sms)" +
287 " WHERE thread_id = " + thread_id + " ORDER BY date DESC LIMIT 1)," +
288 " snippet =" +
289 " (SELECT snippet FROM" +
290 " (SELECT date * 1000 AS date, sub AS snippet, thread_id FROM pdu" +
291 " UNION SELECT date, body AS snippet, thread_id FROM sms)" +
292 " WHERE thread_id = " + thread_id + " ORDER BY date DESC LIMIT 1)," +
293 " snippet_cs =" +
294 " (SELECT snippet_cs FROM" +
295 " (SELECT date * 1000 AS date, sub_cs AS snippet_cs, thread_id FROM pdu" +
296 " UNION SELECT date, 0 AS snippet_cs, thread_id FROM sms)" +
297 " WHERE thread_id = " + thread_id + " ORDER BY date DESC LIMIT 1)" +
298 " WHERE threads._id = " + thread_id + ";");
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800299
Tom Taylor842e3112012-09-26 15:01:42 -0700300 // Update the error column of the thread to indicate if there
301 // are any messages in it that have failed to send.
302 // First check to see if there are any messages with errors in this thread.
303 String query = "SELECT thread_id FROM sms WHERE type=" +
304 Telephony.TextBasedSmsColumns.MESSAGE_TYPE_FAILED +
305 " AND thread_id = " + thread_id +
306 " LIMIT 1";
307 int setError = 0;
308 Cursor c = db.rawQuery(query, null);
309 if (c != null) {
310 try {
311 setError = c.getCount(); // Because of the LIMIT 1, count will be 1 or 0.
312 } finally {
313 c.close();
Tom Taylor9565e7f2010-03-01 14:05:46 -0800314 }
315 }
Tom Taylor842e3112012-09-26 15:01:42 -0700316 // What's the current state of the error flag in the threads table?
317 String errorQuery = "SELECT error FROM threads WHERE _id = " + thread_id;
318 c = db.rawQuery(errorQuery, null);
319 if (c != null) {
320 try {
321 if (c.moveToNext()) {
322 int curError = c.getInt(0);
323 if (curError != setError) {
324 // The current thread error column differs, update it.
325 db.execSQL("UPDATE threads SET error=" + setError +
326 " WHERE _id = " + thread_id);
327 }
328 }
329 } finally {
330 c.close();
331 }
332 }
Tom Taylor9565e7f2010-03-01 14:05:46 -0800333 }
Tom Taylor842e3112012-09-26 15:01:42 -0700334 db.setTransactionSuccessful();
335 } catch (Throwable ex) {
336 Log.e(TAG, ex.getMessage(), ex);
337 } finally {
338 db.endTransaction();
Tom Taylor9565e7f2010-03-01 14:05:46 -0800339 }
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800340 }
Mark Wagnerf0a9e902009-06-19 16:00:13 -0700341
kaiyiza4238572014-08-09 15:07:18 +0800342 private static void updateThreadDate(SQLiteDatabase db, long thread_id) {
343 if (thread_id <= 0) {
344 return;
345 }
346
347 try {
348 db.execSQL(
349 " UPDATE threads" +
350 " SET" +
351 " date =" +
352 " (SELECT date FROM" +
353 " (SELECT date * 1000 AS date, thread_id FROM pdu" +
354 " UNION SELECT date, thread_id FROM sms)" +
355 " WHERE thread_id = " + thread_id + " ORDER BY date DESC LIMIT 1)" +
356 " WHERE threads._id = " + thread_id + ";");
357 } catch (Throwable ex) {
358 Log.e(TAG, ex.getMessage(), ex);
359 }
360 }
361
362 public static void updateThreadsDate(SQLiteDatabase db, String where, String[] whereArgs) {
363 db.beginTransaction();
364 try {
365 if (where == null) {
366 where = "";
367 } else {
368 where = "WHERE (" + where + ")";
369 }
370 String query = "SELECT _id FROM threads " + where;
371 Cursor c = db.rawQuery(query, whereArgs);
372 if (c != null) {
373 try {
374 Log.d(TAG, "updateThread count : " + c.getCount());
375 while (c.moveToNext()) {
376 updateThreadDate(db, c.getInt(0));
377 }
378 } finally {
379 c.close();
380 }
381 }
382 db.setTransactionSuccessful();
383 } catch (Throwable ex) {
384 Log.e(TAG, ex.getMessage(), ex);
385 } finally {
386 db.endTransaction();
387 }
388 }
389
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800390 public static void updateAllThreads(SQLiteDatabase db, String where, String[] whereArgs) {
Tom Taylor842e3112012-09-26 15:01:42 -0700391 db.beginTransaction();
392 try {
393 if (where == null) {
394 where = "";
395 } else {
396 where = "WHERE (" + where + ")";
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800397 }
Tom Taylor842e3112012-09-26 15:01:42 -0700398 String query = "SELECT _id FROM threads WHERE _id IN " +
399 "(SELECT DISTINCT thread_id FROM sms " + where + ")";
400 Cursor c = db.rawQuery(query, whereArgs);
401 if (c != null) {
402 try {
403 while (c.moveToNext()) {
404 updateThread(db, c.getInt(0));
405 }
406 } finally {
407 c.close();
408 }
409 }
410 // TODO: there are several db operations in this function. Lets wrap them in a
411 // transaction to make it faster.
412 // remove orphaned threads
Tom Taylor15156cd2012-11-15 14:15:46 -0800413 db.delete(MmsSmsProvider.TABLE_THREADS,
Tom Taylor842e3112012-09-26 15:01:42 -0700414 "_id NOT IN (SELECT DISTINCT thread_id FROM sms where thread_id NOT NULL " +
415 "UNION SELECT DISTINCT thread_id FROM pdu where thread_id NOT NULL)", null);
Tom Taylor3ce9cb82011-09-27 15:14:58 -0700416
Tom Taylor842e3112012-09-26 15:01:42 -0700417 // remove orphaned canonical_addresses
418 removeUnferencedCanonicalAddresses(db);
419
420 db.setTransactionSuccessful();
421 } catch (Throwable ex) {
422 Log.e(TAG, ex.getMessage(), ex);
423 } finally {
424 db.endTransaction();
425 }
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800426 }
Mark Wagnerf0a9e902009-06-19 16:00:13 -0700427
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800428 public static int deleteOneSms(SQLiteDatabase db, int message_id) {
429 int thread_id = -1;
430 // Find the thread ID that the specified SMS belongs to.
431 Cursor c = db.query("sms", new String[] { "thread_id" },
432 "_id=" + message_id, null, null, null, null);
433 if (c != null) {
434 if (c.moveToFirst()) {
435 thread_id = c.getInt(0);
436 }
437 c.close();
438 }
439
440 // Delete the specified message.
441 int rows = db.delete("sms", "_id=" + message_id, null);
442 if (thread_id > 0) {
443 // Update its thread.
444 updateThread(db, thread_id);
445 }
446 return rows;
447 }
448
449 @Override
450 public void onCreate(SQLiteDatabase db) {
451 createMmsTables(db);
452 createSmsTables(db);
453 createCommonTables(db);
454 createCommonTriggers(db);
455 createMmsTriggers(db);
Mark Wagner8e5ee782010-01-04 17:39:06 -0800456 createWordsTables(db);
Tom Taylora6e44cb2010-03-01 09:58:36 -0800457 createIndices(db);
Mark Wagner8e5ee782010-01-04 17:39:06 -0800458 }
459
yanglv3dd0bab2015-08-24 10:40:19 +0800460 @Override
461 public void onOpen(SQLiteDatabase db) {
462 try {
463 // Try to access the table and create it if "no such table"
464 db.query(SmsProvider.TABLE_SMS, null, null, null, null, null, null);
465 checkAndUpdateSmsTable(db);
466 } catch (SQLiteException e) {
467 Log.e(TAG, "onOpen: ex. ", e);
468 if (e.getMessage().startsWith(NO_SUCH_TABLE_EXCEPTION_MESSAGE)) {
469 createSmsTables(db);
470 }
471 }
kaiyizcd21c4f2015-01-30 11:22:36 +0800472
473 // Improve the performance of deleting Mms.
474 dropMmsTriggers(db);
Prasath Balakrishnan1dfaed12015-11-18 20:36:17 +0530475
476 // Upgrade SMS/MMS database
477 upgradeSmsMmsDb(db);
kaiyizcd21c4f2015-01-30 11:22:36 +0800478 }
479
480 private void dropMmsTriggers(SQLiteDatabase db) {
481 db.execSQL("DROP TRIGGER IF EXISTS update_threads_on_delete_part");
482 db.execSQL("DROP TRIGGER IF EXISTS mms_words_delete");
483 db.execSQL("DROP TRIGGER IF EXISTS pdu_update_thread_on_delete");
yanglv3dd0bab2015-08-24 10:40:19 +0800484 }
485
Mark Wagner8e5ee782010-01-04 17:39:06 -0800486 // When upgrading the database we need to populate the words
487 // table with the rows out of sms and part.
488 private void populateWordsTable(SQLiteDatabase db) {
489 final String TABLE_WORDS = "words";
490 {
491 Cursor smsRows = db.query(
492 "sms",
493 new String[] { Sms._ID, Sms.BODY },
494 null,
495 null,
496 null,
497 null,
498 null);
499 try {
500 if (smsRows != null) {
501 smsRows.moveToPosition(-1);
502 ContentValues cv = new ContentValues();
503 while (smsRows.moveToNext()) {
504 cv.clear();
505
506 long id = smsRows.getLong(0); // 0 for Sms._ID
507 String body = smsRows.getString(1); // 1 for Sms.BODY
508
509 cv.put(Telephony.MmsSms.WordsTable.ID, id);
510 cv.put(Telephony.MmsSms.WordsTable.INDEXED_TEXT, body);
511 cv.put(Telephony.MmsSms.WordsTable.SOURCE_ROW_ID, id);
512 cv.put(Telephony.MmsSms.WordsTable.TABLE_ID, 1);
513 db.insert(TABLE_WORDS, Telephony.MmsSms.WordsTable.INDEXED_TEXT, cv);
514 }
515 }
516 } finally {
517 if (smsRows != null) {
518 smsRows.close();
519 }
520 }
521 }
522
523 {
524 Cursor mmsRows = db.query(
525 "part",
526 new String[] { Part._ID, Part.TEXT },
527 "ct = 'text/plain'",
528 null,
529 null,
530 null,
531 null);
532 try {
533 if (mmsRows != null) {
534 mmsRows.moveToPosition(-1);
535 ContentValues cv = new ContentValues();
536 while (mmsRows.moveToNext()) {
537 cv.clear();
538
539 long id = mmsRows.getLong(0); // 0 for Part._ID
540 String body = mmsRows.getString(1); // 1 for Part.TEXT
541
542 cv.put(Telephony.MmsSms.WordsTable.ID, id);
543 cv.put(Telephony.MmsSms.WordsTable.INDEXED_TEXT, body);
544 cv.put(Telephony.MmsSms.WordsTable.SOURCE_ROW_ID, id);
545 cv.put(Telephony.MmsSms.WordsTable.TABLE_ID, 1);
546 db.insert(TABLE_WORDS, Telephony.MmsSms.WordsTable.INDEXED_TEXT, cv);
547 }
548 }
549 } finally {
550 if (mmsRows != null) {
551 mmsRows.close();
552 }
553 }
554 }
555 }
556
557 private void createWordsTables(SQLiteDatabase db) {
558 try {
559 db.execSQL("CREATE VIRTUAL TABLE words USING FTS3 (_id INTEGER PRIMARY KEY, index_text TEXT, source_id INTEGER, table_to_use INTEGER);");
560
561 // monitor the sms table
562 // NOTE don't handle inserts using a trigger because it has an unwanted
563 // side effect: the value returned for the last row ends up being the
564 // id of one of the trigger insert not the original row insert.
565 // Handle inserts manually in the provider.
566 db.execSQL("CREATE TRIGGER sms_words_update AFTER UPDATE ON sms BEGIN UPDATE words " +
567 " SET index_text = NEW.body WHERE (source_id=NEW._id AND table_to_use=1); " +
568 " END;");
569 db.execSQL("CREATE TRIGGER sms_words_delete AFTER DELETE ON sms BEGIN DELETE FROM " +
570 " words WHERE source_id = OLD._id AND table_to_use = 1; END;");
571
Mark Wagner8e5ee782010-01-04 17:39:06 -0800572 populateWordsTable(db);
573 } catch (Exception ex) {
574 Log.e(TAG, "got exception creating words table: " + ex.toString());
575 }
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800576 }
577
Tom Taylora6e44cb2010-03-01 09:58:36 -0800578 private void createIndices(SQLiteDatabase db) {
579 createThreadIdIndex(db);
kaiyizcd21c4f2015-01-30 11:22:36 +0800580 createPduPartIndex(db);
Tom Taylora6e44cb2010-03-01 09:58:36 -0800581 }
582
kaiyizcd21c4f2015-01-30 11:22:36 +0800583 private void createPduPartIndex(SQLiteDatabase db) {
584 try {
585 db.execSQL("CREATE INDEX IF NOT EXISTS index_part ON " + MmsProvider.TABLE_PART +
586 " (mid);");
587 } catch (Exception ex) {
588 Log.e(TAG, "got exception creating indices: " + ex.toString());
589 }
590 }
591
Tom Taylora6e44cb2010-03-01 09:58:36 -0800592 private void createThreadIdIndex(SQLiteDatabase db) {
593 try {
594 db.execSQL("CREATE INDEX IF NOT EXISTS typeThreadIdIndex ON sms" +
595 " (type, thread_id);");
596 } catch (Exception ex) {
597 Log.e(TAG, "got exception creating indices: " + ex.toString());
598 }
599 }
600
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800601 private void createMmsTables(SQLiteDatabase db) {
602 // N.B.: Whenever the columns here are changed, the columns in
603 // {@ref MmsSmsProvider} must be changed to match.
604 db.execSQL("CREATE TABLE " + MmsProvider.TABLE_PDU + " (" +
Tom Taylor49c9ede2012-09-09 09:41:50 -0700605 Mms._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800606 Mms.THREAD_ID + " INTEGER," +
607 Mms.DATE + " INTEGER," +
Fredrik Roubertea5c40c2010-11-18 17:16:23 +0100608 Mms.DATE_SENT + " INTEGER DEFAULT 0," +
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800609 Mms.MESSAGE_BOX + " INTEGER," +
610 Mms.READ + " INTEGER DEFAULT 0," +
611 Mms.MESSAGE_ID + " TEXT," +
612 Mms.SUBJECT + " TEXT," +
613 Mms.SUBJECT_CHARSET + " INTEGER," +
614 Mms.CONTENT_TYPE + " TEXT," +
615 Mms.CONTENT_LOCATION + " TEXT," +
616 Mms.EXPIRY + " INTEGER," +
617 Mms.MESSAGE_CLASS + " TEXT," +
618 Mms.MESSAGE_TYPE + " INTEGER," +
619 Mms.MMS_VERSION + " INTEGER," +
620 Mms.MESSAGE_SIZE + " INTEGER," +
621 Mms.PRIORITY + " INTEGER," +
622 Mms.READ_REPORT + " INTEGER," +
623 Mms.REPORT_ALLOWED + " INTEGER," +
624 Mms.RESPONSE_STATUS + " INTEGER," +
625 Mms.STATUS + " INTEGER," +
626 Mms.TRANSACTION_ID + " TEXT," +
627 Mms.RETRIEVE_STATUS + " INTEGER," +
628 Mms.RETRIEVE_TEXT + " TEXT," +
629 Mms.RETRIEVE_TEXT_CHARSET + " INTEGER," +
630 Mms.READ_STATUS + " INTEGER," +
631 Mms.CONTENT_CLASS + " INTEGER," +
632 Mms.RESPONSE_TEXT + " TEXT," +
633 Mms.DELIVERY_TIME + " INTEGER," +
Tom Taylora48a9662009-06-04 14:05:05 -0700634 Mms.DELIVERY_REPORT + " INTEGER," +
Wei Huangdfac5762010-02-25 17:23:51 -0800635 Mms.LOCKED + " INTEGER DEFAULT 0," +
Wink Savillea42e4172014-12-09 18:55:22 -0800636 Mms.SUBSCRIPTION_ID + " INTEGER DEFAULT "
637 + SubscriptionManager.INVALID_SUBSCRIPTION_ID + ", " +
Suresh Koleti02354f12014-08-19 16:21:45 +0530638 Mms.PHONE_ID + " INTEGER DEFAULT -1, " +
Tom Taylor49c9ede2012-09-09 09:41:50 -0700639 Mms.SEEN + " INTEGER DEFAULT 0," +
Ye Wen49776412014-07-09 16:57:32 -0700640 Mms.CREATOR + " TEXT," +
Tom Taylorf88d1d62012-09-07 13:38:39 -0700641 Mms.TEXT_ONLY + " INTEGER DEFAULT 0" +
Tom Taylora48a9662009-06-04 14:05:05 -0700642 ");");
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800643
644 db.execSQL("CREATE TABLE " + MmsProvider.TABLE_ADDR + " (" +
645 Addr._ID + " INTEGER PRIMARY KEY," +
646 Addr.MSG_ID + " INTEGER," +
647 Addr.CONTACT_ID + " INTEGER," +
648 Addr.ADDRESS + " TEXT," +
649 Addr.TYPE + " INTEGER," +
650 Addr.CHARSET + " INTEGER);");
651
652 db.execSQL("CREATE TABLE " + MmsProvider.TABLE_PART + " (" +
Tom Taylor49c9ede2012-09-09 09:41:50 -0700653 Part._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800654 Part.MSG_ID + " INTEGER," +
655 Part.SEQ + " INTEGER DEFAULT 0," +
656 Part.CONTENT_TYPE + " TEXT," +
657 Part.NAME + " TEXT," +
658 Part.CHARSET + " INTEGER," +
659 Part.CONTENT_DISPOSITION + " TEXT," +
660 Part.FILENAME + " TEXT," +
661 Part.CONTENT_ID + " TEXT," +
662 Part.CONTENT_LOCATION + " TEXT," +
663 Part.CT_START + " INTEGER," +
664 Part.CT_TYPE + " TEXT," +
Mark Wagnerf0a9e902009-06-19 16:00:13 -0700665 Part._DATA + " TEXT," +
666 Part.TEXT + " TEXT);");
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800667
668 db.execSQL("CREATE TABLE " + MmsProvider.TABLE_RATE + " (" +
669 Rate.SENT_TIME + " INTEGER);");
670
671 db.execSQL("CREATE TABLE " + MmsProvider.TABLE_DRM + " (" +
672 BaseColumns._ID + " INTEGER PRIMARY KEY," +
673 "_data TEXT);");
Ye Wen72f13552015-03-10 14:17:13 -0700674
675 // Restricted view of pdu table, only sent/received messages without wap pushes
676 db.execSQL("CREATE VIEW " + MmsProvider.VIEW_PDU_RESTRICTED + " AS " +
677 "SELECT * FROM " + MmsProvider.TABLE_PDU + " WHERE " +
678 "(" + Mms.MESSAGE_BOX + "=" + Mms.MESSAGE_BOX_INBOX +
679 " OR " +
680 Mms.MESSAGE_BOX + "=" + Mms.MESSAGE_BOX_SENT + ")" +
681 " AND " +
682 "(" + Mms.MESSAGE_TYPE + "!=" + PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND + ");");
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800683 }
684
Tom Taylor49c9ede2012-09-09 09:41:50 -0700685 // Unlike the other trigger-creating functions, this function can be called multiple times
686 // without harm.
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800687 private void createMmsTriggers(SQLiteDatabase db) {
688 // Cleans up parts when a MM is deleted.
Tom Taylor49c9ede2012-09-09 09:41:50 -0700689 db.execSQL("DROP TRIGGER IF EXISTS part_cleanup");
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800690 db.execSQL("CREATE TRIGGER part_cleanup DELETE ON " + MmsProvider.TABLE_PDU + " " +
Tom Taylor49c9ede2012-09-09 09:41:50 -0700691 "BEGIN " +
692 " DELETE FROM " + MmsProvider.TABLE_PART +
693 " WHERE " + Part.MSG_ID + "=old._id;" +
694 "END;");
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800695
696 // Cleans up address info when a MM is deleted.
Tom Taylor49c9ede2012-09-09 09:41:50 -0700697 db.execSQL("DROP TRIGGER IF EXISTS addr_cleanup");
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800698 db.execSQL("CREATE TRIGGER addr_cleanup DELETE ON " + MmsProvider.TABLE_PDU + " " +
Tom Taylor49c9ede2012-09-09 09:41:50 -0700699 "BEGIN " +
700 " DELETE FROM " + MmsProvider.TABLE_ADDR +
701 " WHERE " + Addr.MSG_ID + "=old._id;" +
702 "END;");
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800703
704 // Delete obsolete delivery-report, read-report while deleting their
705 // associated Send.req.
Tom Taylor49c9ede2012-09-09 09:41:50 -0700706 db.execSQL("DROP TRIGGER IF EXISTS cleanup_delivery_and_read_report");
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800707 db.execSQL("CREATE TRIGGER cleanup_delivery_and_read_report " +
Tom Taylor49c9ede2012-09-09 09:41:50 -0700708 "AFTER DELETE ON " + MmsProvider.TABLE_PDU + " " +
709 "WHEN old." + Mms.MESSAGE_TYPE + "=" + PduHeaders.MESSAGE_TYPE_SEND_REQ + " " +
710 "BEGIN " +
711 " DELETE FROM " + MmsProvider.TABLE_PDU +
712 " WHERE (" + Mms.MESSAGE_TYPE + "=" + PduHeaders.MESSAGE_TYPE_DELIVERY_IND +
713 " OR " + Mms.MESSAGE_TYPE + "=" + PduHeaders.MESSAGE_TYPE_READ_ORIG_IND +
714 ")" +
715 " AND " + Mms.MESSAGE_ID + "=old." + Mms.MESSAGE_ID + "; " +
716 "END;");
717
718 db.execSQL("DROP TRIGGER IF EXISTS update_threads_on_insert_part");
719 db.execSQL(PART_UPDATE_THREADS_ON_INSERT_TRIGGER);
720
721 db.execSQL("DROP TRIGGER IF EXISTS update_threads_on_update_part");
722 db.execSQL(PART_UPDATE_THREADS_ON_UPDATE_TRIGGER);
723
Tom Taylor49c9ede2012-09-09 09:41:50 -0700724 db.execSQL("DROP TRIGGER IF EXISTS update_threads_on_update_pdu");
725 db.execSQL(PDU_UPDATE_THREADS_ON_UPDATE_TRIGGER);
726
727 // Delete pending status for a message when it is deleted.
728 db.execSQL("DROP TRIGGER IF EXISTS delete_mms_pending_on_delete");
729 db.execSQL("CREATE TRIGGER delete_mms_pending_on_delete " +
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800730 "AFTER DELETE ON " + MmsProvider.TABLE_PDU + " " +
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800731 "BEGIN " +
Tom Taylor49c9ede2012-09-09 09:41:50 -0700732 " DELETE FROM " + MmsSmsProvider.TABLE_PENDING_MSG +
733 " WHERE " + PendingMessages.MSG_ID + "=old._id; " +
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800734 "END;");
Mark Wagnerf0a9e902009-06-19 16:00:13 -0700735
Tom Taylor49c9ede2012-09-09 09:41:50 -0700736 // When a message is moved out of Outbox, delete its pending status.
737 db.execSQL("DROP TRIGGER IF EXISTS delete_mms_pending_on_update");
738 db.execSQL("CREATE TRIGGER delete_mms_pending_on_update " +
739 "AFTER UPDATE ON " + MmsProvider.TABLE_PDU + " " +
740 "WHEN old." + Mms.MESSAGE_BOX + "=" + Mms.MESSAGE_BOX_OUTBOX +
741 " AND new." + Mms.MESSAGE_BOX + "!=" + Mms.MESSAGE_BOX_OUTBOX + " " +
742 "BEGIN " +
743 " DELETE FROM " + MmsSmsProvider.TABLE_PENDING_MSG +
744 " WHERE " + PendingMessages.MSG_ID + "=new._id; " +
745 "END;");
746
747 // Insert pending status for M-Notification.ind or M-ReadRec.ind
748 // when they are inserted into Inbox/Outbox.
749 db.execSQL("DROP TRIGGER IF EXISTS insert_mms_pending_on_insert");
750 db.execSQL("CREATE TRIGGER insert_mms_pending_on_insert " +
751 "AFTER INSERT ON pdu " +
752 "WHEN new." + Mms.MESSAGE_TYPE + "=" + PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND +
753 " OR new." + Mms.MESSAGE_TYPE + "=" + PduHeaders.MESSAGE_TYPE_READ_REC_IND +
754 " " +
755 "BEGIN " +
756 " INSERT INTO " + MmsSmsProvider.TABLE_PENDING_MSG +
757 " (" + PendingMessages.PROTO_TYPE + "," +
758 " " + PendingMessages.MSG_ID + "," +
759 " " + PendingMessages.MSG_TYPE + "," +
760 " " + PendingMessages.ERROR_TYPE + "," +
761 " " + PendingMessages.ERROR_CODE + "," +
762 " " + PendingMessages.RETRY_INDEX + "," +
763 " " + PendingMessages.DUE_TIME + ") " +
764 " VALUES " +
765 " (" + MmsSms.MMS_PROTO + "," +
766 " new." + BaseColumns._ID + "," +
767 " new." + Mms.MESSAGE_TYPE + ",0,0,0,0);" +
768 "END;");
769
770
771 // Insert pending status for M-Send.req when it is moved into Outbox.
772 db.execSQL("DROP TRIGGER IF EXISTS insert_mms_pending_on_update");
773 db.execSQL("CREATE TRIGGER insert_mms_pending_on_update " +
774 "AFTER UPDATE ON pdu " +
775 "WHEN new." + Mms.MESSAGE_TYPE + "=" + PduHeaders.MESSAGE_TYPE_SEND_REQ +
776 " AND new." + Mms.MESSAGE_BOX + "=" + Mms.MESSAGE_BOX_OUTBOX +
777 " AND old." + Mms.MESSAGE_BOX + "!=" + Mms.MESSAGE_BOX_OUTBOX + " " +
778 "BEGIN " +
779 " INSERT INTO " + MmsSmsProvider.TABLE_PENDING_MSG +
780 " (" + PendingMessages.PROTO_TYPE + "," +
781 " " + PendingMessages.MSG_ID + "," +
782 " " + PendingMessages.MSG_TYPE + "," +
783 " " + PendingMessages.ERROR_TYPE + "," +
784 " " + PendingMessages.ERROR_CODE + "," +
785 " " + PendingMessages.RETRY_INDEX + "," +
786 " " + PendingMessages.DUE_TIME + ") " +
787 " VALUES " +
788 " (" + MmsSms.MMS_PROTO + "," +
789 " new." + BaseColumns._ID + "," +
790 " new." + Mms.MESSAGE_TYPE + ",0,0,0,0);" +
791 "END;");
792
793 // monitor the mms table
794 db.execSQL("DROP TRIGGER IF EXISTS mms_words_update");
795 db.execSQL("CREATE TRIGGER mms_words_update AFTER UPDATE ON part BEGIN UPDATE words " +
796 " SET index_text = NEW.text WHERE (source_id=NEW._id AND table_to_use=2); " +
797 " END;");
798
Tom Taylor49c9ede2012-09-09 09:41:50 -0700799 // Updates threads table whenever a message in pdu is updated.
800 db.execSQL("DROP TRIGGER IF EXISTS pdu_update_thread_date_subject_on_update");
801 db.execSQL("CREATE TRIGGER pdu_update_thread_date_subject_on_update AFTER" +
802 " UPDATE OF " + Mms.DATE + ", " + Mms.SUBJECT + ", " + Mms.MESSAGE_BOX +
803 " ON " + MmsProvider.TABLE_PDU + " " +
804 PDU_UPDATE_THREAD_CONSTRAINTS +
805 PDU_UPDATE_THREAD_DATE_SNIPPET_COUNT_ON_UPDATE);
806
Tom Taylor49c9ede2012-09-09 09:41:50 -0700807 // Updates threads table whenever a message is added to pdu.
808 db.execSQL("DROP TRIGGER IF EXISTS pdu_update_thread_on_insert");
809 db.execSQL("CREATE TRIGGER pdu_update_thread_on_insert AFTER INSERT ON " +
810 MmsProvider.TABLE_PDU + " " +
811 PDU_UPDATE_THREAD_CONSTRAINTS +
812 PDU_UPDATE_THREAD_DATE_SNIPPET_COUNT_ON_UPDATE);
813
814 // Updates threads table whenever a message in pdu is updated.
815 db.execSQL("DROP TRIGGER IF EXISTS pdu_update_thread_read_on_update");
816 db.execSQL("CREATE TRIGGER pdu_update_thread_read_on_update AFTER" +
817 " UPDATE OF " + Mms.READ +
818 " ON " + MmsProvider.TABLE_PDU + " " +
819 PDU_UPDATE_THREAD_CONSTRAINTS +
820 "BEGIN " +
821 PDU_UPDATE_THREAD_READ_BODY +
822 "END;");
823
824 // Update the error flag of threads when delete pending message.
825 db.execSQL("DROP TRIGGER IF EXISTS update_threads_error_on_delete_mms");
826 db.execSQL("CREATE TRIGGER update_threads_error_on_delete_mms " +
827 " BEFORE DELETE ON pdu" +
828 " WHEN OLD._id IN (SELECT DISTINCT msg_id" +
829 " FROM pending_msgs" +
830 " WHERE err_type >= 10) " +
831 "BEGIN " +
832 " UPDATE threads SET error = error - 1" +
833 " WHERE _id = OLD.thread_id; " +
834 "END;");
835
836 // Update the error flag of threads while moving an MM out of Outbox,
837 // which was failed to be sent permanently.
838 db.execSQL("DROP TRIGGER IF EXISTS update_threads_error_on_move_mms");
839 db.execSQL("CREATE TRIGGER update_threads_error_on_move_mms " +
840 " BEFORE UPDATE OF msg_box ON pdu " +
841 " WHEN (OLD.msg_box = 4 AND NEW.msg_box != 4) " +
842 " AND (OLD._id IN (SELECT DISTINCT msg_id" +
843 " FROM pending_msgs" +
844 " WHERE err_type >= 10)) " +
845 "BEGIN " +
846 " UPDATE threads SET error = error - 1" +
847 " WHERE _id = OLD.thread_id; " +
848 "END;");
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800849 }
850
851 private void createSmsTables(SQLiteDatabase db) {
852 // N.B.: Whenever the columns here are changed, the columns in
853 // {@ref MmsSmsProvider} must be changed to match.
854 db.execSQL("CREATE TABLE sms (" +
855 "_id INTEGER PRIMARY KEY," +
856 "thread_id INTEGER," +
857 "address TEXT," +
858 "person INTEGER," +
859 "date INTEGER," +
Fredrik Roubertea5c40c2010-11-18 17:16:23 +0100860 "date_sent INTEGER DEFAULT 0," +
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800861 "protocol INTEGER," +
862 "read INTEGER DEFAULT 0," +
863 "status INTEGER DEFAULT -1," + // a TP-Status value
864 // or -1 if it
865 // status hasn't
866 // been received
867 "type INTEGER," +
868 "reply_path_present INTEGER," +
869 "subject TEXT," +
870 "body TEXT," +
Tom Taylora48a9662009-06-04 14:05:05 -0700871 "service_center TEXT," +
Tom Taylor7d4e56b2009-11-03 17:23:20 -0800872 "locked INTEGER DEFAULT 0," +
Wink Saville72b14732014-11-20 13:06:04 -0800873 "sub_id INTEGER DEFAULT " + SubscriptionManager.INVALID_SUBSCRIPTION_ID + ", " +
Suresh Koleti02354f12014-08-19 16:21:45 +0530874 "phone_id INTEGER DEFAULT -1, " +
Wei Huangdfac5762010-02-25 17:23:51 -0800875 "error_code INTEGER DEFAULT 0," +
Ye Wen49776412014-07-09 16:57:32 -0700876 "creator TEXT," +
yanglv3dd0bab2015-08-24 10:40:19 +0800877 "seen INTEGER DEFAULT 0," +
878 "priority INTEGER DEFAULT -1" +
Tom Taylora48a9662009-06-04 14:05:05 -0700879 ");");
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800880
881 /**
882 * This table is used by the SMS dispatcher to hold
883 * incomplete partial messages until all the parts arrive.
884 */
885 db.execSQL("CREATE TABLE raw (" +
886 "_id INTEGER PRIMARY KEY," +
887 "date INTEGER," +
888 "reference_number INTEGER," + // one per full message
889 "count INTEGER," + // the number of parts
890 "sequence INTEGER," + // the part number of this message
891 "destination_port INTEGER," +
892 "address TEXT," +
Wink Saville72b14732014-11-20 13:06:04 -0800893 "sub_id INTEGER DEFAULT " + SubscriptionManager.INVALID_SUBSCRIPTION_ID + ", " +
Suresh Koleti02354f12014-08-19 16:21:45 +0530894 "phone_id INTEGER DEFAULT -1, " +
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800895 "pdu TEXT);"); // the raw PDU for this part
896
897 db.execSQL("CREATE TABLE attachments (" +
898 "sms_id INTEGER," +
899 "content_url TEXT," +
900 "offset INTEGER);");
901
902 /**
903 * This table is used by the SMS dispatcher to hold pending
904 * delivery status report intents.
905 */
906 db.execSQL("CREATE TABLE sr_pending (" +
907 "reference_number INTEGER," +
908 "action TEXT," +
909 "data TEXT);");
Ye Wen72f13552015-03-10 14:17:13 -0700910
911 // Restricted view of sms table, only sent/received messages
912 db.execSQL("CREATE VIEW " + SmsProvider.VIEW_SMS_RESTRICTED + " AS " +
913 "SELECT * FROM " + SmsProvider.TABLE_SMS + " WHERE " +
914 Sms.TYPE + "=" + Sms.MESSAGE_TYPE_INBOX +
915 " OR " +
916 Sms.TYPE + "=" + Sms.MESSAGE_TYPE_SENT + ";");
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800917 }
918
919 private void createCommonTables(SQLiteDatabase db) {
920 // TODO Ensure that each entry is removed when the last use of
921 // any address equivalent to its address is removed.
922
923 /**
924 * This table maps the first instance seen of any particular
925 * MMS/SMS address to an ID, which is then used as its
926 * canonical representation. If the same address or an
927 * equivalent address (as determined by our Sqlite
928 * PHONE_NUMBERS_EQUAL extension) is seen later, this same ID
Tom Taylor09710ce2011-12-06 16:10:34 -0800929 * will be used. The _id is created with AUTOINCREMENT so it
930 * will never be reused again if a recipient is deleted.
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800931 */
932 db.execSQL("CREATE TABLE canonical_addresses (" +
Tom Taylor09710ce2011-12-06 16:10:34 -0800933 "_id INTEGER PRIMARY KEY AUTOINCREMENT," +
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800934 "address TEXT);");
935
936 /**
937 * This table maps the subject and an ordered set of recipient
938 * IDs, separated by spaces, to a unique thread ID. The IDs
939 * come from the canonical_addresses table. This works
940 * because messages are considered to be part of the same
941 * thread if they have the same subject (or a null subject)
942 * and the same set of recipients.
943 */
944 db.execSQL("CREATE TABLE threads (" +
Tom Taylor1ab48002011-04-19 14:15:06 -0700945 Threads._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800946 Threads.DATE + " INTEGER DEFAULT 0," +
947 Threads.MESSAGE_COUNT + " INTEGER DEFAULT 0," +
948 Threads.RECIPIENT_IDS + " TEXT," +
949 Threads.SNIPPET + " TEXT," +
950 Threads.SNIPPET_CHARSET + " INTEGER DEFAULT 0," +
951 Threads.READ + " INTEGER DEFAULT 1," +
Ye Wen82fc72b2014-07-29 10:42:54 -0700952 Threads.ARCHIVED + " INTEGER DEFAULT 0," +
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800953 Threads.TYPE + " INTEGER DEFAULT 0," +
The Android Open Source Project5f1e43f2009-03-05 14:34:39 -0800954 Threads.ERROR + " INTEGER DEFAULT 0," +
955 Threads.HAS_ATTACHMENT + " INTEGER DEFAULT 0);");
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800956
957 /**
958 * This table stores the queue of messages to be sent/downloaded.
959 */
960 db.execSQL("CREATE TABLE " + MmsSmsProvider.TABLE_PENDING_MSG +" (" +
961 PendingMessages._ID + " INTEGER PRIMARY KEY," +
962 PendingMessages.PROTO_TYPE + " INTEGER," +
963 PendingMessages.MSG_ID + " INTEGER," +
964 PendingMessages.MSG_TYPE + " INTEGER," +
965 PendingMessages.ERROR_TYPE + " INTEGER," +
966 PendingMessages.ERROR_CODE + " INTEGER," +
967 PendingMessages.RETRY_INDEX + " INTEGER NOT NULL DEFAULT 0," +
968 PendingMessages.DUE_TIME + " INTEGER," +
Wink Saville72b14732014-11-20 13:06:04 -0800969 PendingMessages.SUBSCRIPTION_ID + " INTEGER DEFAULT " +
Wink Savillea42e4172014-12-09 18:55:22 -0800970 SubscriptionManager.INVALID_SUBSCRIPTION_ID + ", " +
Suresh Koleti02354f12014-08-19 16:21:45 +0530971 PendingMessages.PHONE_ID + " INTEGER DEFAULT 0, " +
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800972 PendingMessages.LAST_TRY + " INTEGER);");
973
974 }
975
976 // TODO Check the query plans for these triggers.
977 private void createCommonTriggers(SQLiteDatabase db) {
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800978 // Updates threads table whenever a message is added to sms.
979 db.execSQL("CREATE TRIGGER sms_update_thread_on_insert AFTER INSERT ON sms " +
980 SMS_UPDATE_THREAD_DATE_SNIPPET_COUNT_ON_UPDATE);
981
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800982 // Updates threads table whenever a message in sms is updated.
983 db.execSQL("CREATE TRIGGER sms_update_thread_date_subject_on_update AFTER" +
984 " UPDATE OF " + Sms.DATE + ", " + Sms.BODY + ", " + Sms.TYPE +
985 " ON sms " +
986 SMS_UPDATE_THREAD_DATE_SNIPPET_COUNT_ON_UPDATE);
987
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800988 // Updates threads table whenever a message in sms is updated.
989 db.execSQL("CREATE TRIGGER sms_update_thread_read_on_update AFTER" +
990 " UPDATE OF " + Sms.READ +
991 " ON sms " +
992 "BEGIN " +
993 SMS_UPDATE_THREAD_READ_BODY +
994 "END;");
995
Tom Taylor527fcce2011-09-21 16:03:40 -0700996 // As of DATABASE_VERSION 55, we've removed these triggers that delete empty threads.
997 // These triggers interfere with saving drafts on brand new threads. Instead of
998 // triggers cleaning up empty threads, the empty threads should be cleaned up by
999 // an explicit call to delete with Threads.OBSOLETE_THREADS_URI.
The Android Open Source Project7236c3a2009-03-03 19:32:44 -08001000
Tom Taylor527fcce2011-09-21 16:03:40 -07001001// // When the last message in a thread is deleted, these
1002// // triggers ensure that the entry for its thread ID is removed
1003// // from the threads table.
1004// db.execSQL("CREATE TRIGGER delete_obsolete_threads_pdu " +
1005// "AFTER DELETE ON pdu " +
1006// "BEGIN " +
1007// " DELETE FROM threads " +
1008// " WHERE " +
1009// " _id = old.thread_id " +
1010// " AND _id NOT IN " +
1011// " (SELECT thread_id FROM sms " +
1012// " UNION SELECT thread_id from pdu); " +
1013// "END;");
1014//
1015// db.execSQL("CREATE TRIGGER delete_obsolete_threads_when_update_pdu " +
1016// "AFTER UPDATE OF " + Mms.THREAD_ID + " ON pdu " +
1017// "WHEN old." + Mms.THREAD_ID + " != new." + Mms.THREAD_ID + " " +
1018// "BEGIN " +
1019// " DELETE FROM threads " +
1020// " WHERE " +
1021// " _id = old.thread_id " +
1022// " AND _id NOT IN " +
1023// " (SELECT thread_id FROM sms " +
1024// " UNION SELECT thread_id from pdu); " +
1025// "END;");
1026
The Android Open Source Project7236c3a2009-03-03 19:32:44 -08001027 // TODO Add triggers for SMS retry-status management.
1028
1029 // Update the error flag of threads when the error type of
1030 // a pending MM is updated.
1031 db.execSQL("CREATE TRIGGER update_threads_error_on_update_mms " +
1032 " AFTER UPDATE OF err_type ON pending_msgs " +
1033 " WHEN (OLD.err_type < 10 AND NEW.err_type >= 10)" +
1034 " OR (OLD.err_type >= 10 AND NEW.err_type < 10) " +
1035 "BEGIN" +
1036 " UPDATE threads SET error = " +
1037 " CASE" +
1038 " WHEN NEW.err_type >= 10 THEN error + 1" +
1039 " ELSE error - 1" +
1040 " END " +
1041 " WHERE _id =" +
1042 " (SELECT DISTINCT thread_id" +
1043 " FROM pdu" +
1044 " WHERE _id = NEW.msg_id); " +
1045 "END;");
1046
The Android Open Source Project7236c3a2009-03-03 19:32:44 -08001047 // Update the error flag of threads after a text message was
1048 // failed to send/receive.
1049 db.execSQL("CREATE TRIGGER update_threads_error_on_update_sms " +
1050 " AFTER UPDATE OF type ON sms" +
1051 " WHEN (OLD.type != 5 AND NEW.type = 5)" +
1052 " OR (OLD.type = 5 AND NEW.type != 5) " +
1053 "BEGIN " +
1054 " UPDATE threads SET error = " +
1055 " CASE" +
1056 " WHEN NEW.type = 5 THEN error + 1" +
1057 " ELSE error - 1" +
1058 " END " +
1059 " WHERE _id = NEW.thread_id; " +
1060 "END;");
1061 }
1062
1063 @Override
1064 public void onUpgrade(SQLiteDatabase db, int oldVersion, int currentVersion) {
1065 Log.w(TAG, "Upgrading database from version " + oldVersion
1066 + " to " + currentVersion + ".");
1067
1068 switch (oldVersion) {
The Android Open Source Project5f1e43f2009-03-05 14:34:39 -08001069 case 40:
1070 if (currentVersion <= 40) {
The Android Open Source Project7236c3a2009-03-03 19:32:44 -08001071 return;
The Android Open Source Project5f1e43f2009-03-05 14:34:39 -08001072 }
1073
1074 db.beginTransaction();
1075 try {
1076 upgradeDatabaseToVersion41(db);
1077 db.setTransactionSuccessful();
1078 } catch (Throwable ex) {
1079 Log.e(TAG, ex.getMessage(), ex);
1080 break;
1081 } finally {
1082 db.endTransaction();
1083 }
1084 // fall through
1085 case 41:
1086 if (currentVersion <= 41) {
1087 return;
1088 }
Mark Wagnerf0a9e902009-06-19 16:00:13 -07001089
The Android Open Source Project5f1e43f2009-03-05 14:34:39 -08001090 db.beginTransaction();
1091 try {
1092 upgradeDatabaseToVersion42(db);
1093 db.setTransactionSuccessful();
1094 } catch (Throwable ex) {
1095 Log.e(TAG, ex.getMessage(), ex);
1096 break;
1097 } finally {
1098 db.endTransaction();
1099 }
1100 // fall through
1101 case 42:
1102 if (currentVersion <= 42) {
1103 return;
1104 }
Mark Wagnerf0a9e902009-06-19 16:00:13 -07001105
The Android Open Source Project5f1e43f2009-03-05 14:34:39 -08001106 db.beginTransaction();
1107 try {
1108 upgradeDatabaseToVersion43(db);
1109 db.setTransactionSuccessful();
1110 } catch (Throwable ex) {
1111 Log.e(TAG, ex.getMessage(), ex);
1112 break;
1113 } finally {
1114 db.endTransaction();
1115 }
Wei Huang2ad5ba82009-03-24 20:01:04 -07001116 // fall through
1117 case 43:
1118 if (currentVersion <= 43) {
1119 return;
1120 }
1121
1122 db.beginTransaction();
1123 try {
1124 upgradeDatabaseToVersion44(db);
1125 db.setTransactionSuccessful();
1126 } catch (Throwable ex) {
1127 Log.e(TAG, ex.getMessage(), ex);
1128 break;
1129 } finally {
1130 db.endTransaction();
1131 }
Tom Taylorddf267c2009-10-28 18:14:55 -07001132 // fall through
Tom Taylora48a9662009-06-04 14:05:05 -07001133 case 44:
1134 if (currentVersion <= 44) {
1135 return;
1136 }
1137
1138 db.beginTransaction();
1139 try {
1140 upgradeDatabaseToVersion45(db);
1141 db.setTransactionSuccessful();
1142 } catch (Throwable ex) {
1143 Log.e(TAG, ex.getMessage(), ex);
1144 break;
1145 } finally {
1146 db.endTransaction();
1147 }
Tom Taylorddf267c2009-10-28 18:14:55 -07001148 // fall through
Mark Wagnerf0a9e902009-06-19 16:00:13 -07001149 case 45:
1150 if (currentVersion <= 45) {
1151 return;
1152 }
1153 db.beginTransaction();
1154 try {
1155 upgradeDatabaseToVersion46(db);
1156 db.setTransactionSuccessful();
1157 } catch (Throwable ex) {
1158 Log.e(TAG, ex.getMessage(), ex);
1159 break;
1160 } finally {
1161 db.endTransaction();
1162 }
Wei Huang1047ab42009-09-29 20:53:26 -07001163 // fall through
1164 case 46:
1165 if (currentVersion <= 46) {
1166 return;
1167 }
1168
1169 db.beginTransaction();
1170 try {
1171 upgradeDatabaseToVersion47(db);
1172 db.setTransactionSuccessful();
1173 } catch (Throwable ex) {
1174 Log.e(TAG, ex.getMessage(), ex);
1175 break;
1176 } finally {
1177 db.endTransaction();
1178 }
Tom Taylorddf267c2009-10-28 18:14:55 -07001179 // fall through
1180 case 47:
1181 if (currentVersion <= 47) {
1182 return;
1183 }
1184
1185 db.beginTransaction();
1186 try {
1187 upgradeDatabaseToVersion48(db);
1188 db.setTransactionSuccessful();
1189 } catch (Throwable ex) {
1190 Log.e(TAG, ex.getMessage(), ex);
1191 break;
1192 } finally {
1193 db.endTransaction();
1194 }
Wei Huangdfac5762010-02-25 17:23:51 -08001195 // fall through
Mark Wagner8e5ee782010-01-04 17:39:06 -08001196 case 48:
1197 if (currentVersion <= 48) {
1198 return;
1199 }
1200
1201 db.beginTransaction();
1202 try {
Tom Taylor7ad939e2010-01-15 14:03:29 -08001203 createWordsTables(db);
Mark Wagner8e5ee782010-01-04 17:39:06 -08001204 db.setTransactionSuccessful();
1205 } catch (Throwable ex) {
1206 Log.e(TAG, ex.getMessage(), ex);
1207 break;
1208 } finally {
1209 db.endTransaction();
1210 }
Wei Huangdfac5762010-02-25 17:23:51 -08001211 // fall through
Tom Taylora6e44cb2010-03-01 09:58:36 -08001212 case 49:
1213 if (currentVersion <= 49) {
1214 return;
1215 }
1216 db.beginTransaction();
1217 try {
1218 createThreadIdIndex(db);
1219 db.setTransactionSuccessful();
1220 } catch (Throwable ex) {
1221 Log.e(TAG, ex.getMessage(), ex);
1222 break; // force to destroy all old data;
1223 } finally {
1224 db.endTransaction();
1225 }
Wei Huangdfac5762010-02-25 17:23:51 -08001226 // fall through
1227 case 50:
1228 if (currentVersion <= 50) {
1229 return;
1230 }
The Android Open Source Project7236c3a2009-03-03 19:32:44 -08001231
Wei Huangdfac5762010-02-25 17:23:51 -08001232 db.beginTransaction();
1233 try {
1234 upgradeDatabaseToVersion51(db);
1235 db.setTransactionSuccessful();
1236 } catch (Throwable ex) {
1237 Log.e(TAG, ex.getMessage(), ex);
1238 break;
1239 } finally {
1240 db.endTransaction();
1241 }
Tom Taylorfc0eb2f2010-03-11 15:54:15 -08001242 // fall through
1243 case 51:
1244 if (currentVersion <= 51) {
1245 return;
1246 }
Tom Taylor8a4060e2010-03-22 17:08:55 -07001247 // 52 was adding a new meta_data column, but that was removed.
Tom Taylorfc0eb2f2010-03-11 15:54:15 -08001248 // fall through
Tom Taylor1e47c482010-03-12 16:14:50 -08001249 case 52:
1250 if (currentVersion <= 52) {
1251 return;
1252 }
Wei Huangdfac5762010-02-25 17:23:51 -08001253
Tom Taylor1e47c482010-03-12 16:14:50 -08001254 db.beginTransaction();
1255 try {
1256 upgradeDatabaseToVersion53(db);
1257 db.setTransactionSuccessful();
1258 } catch (Throwable ex) {
1259 Log.e(TAG, ex.getMessage(), ex);
1260 break;
1261 } finally {
1262 db.endTransaction();
1263 }
Fredrik Roubertea5c40c2010-11-18 17:16:23 +01001264 // fall through
1265 case 53:
1266 if (currentVersion <= 53) {
1267 return;
1268 }
1269
1270 db.beginTransaction();
1271 try {
1272 upgradeDatabaseToVersion54(db);
1273 db.setTransactionSuccessful();
1274 } catch (Throwable ex) {
1275 Log.e(TAG, ex.getMessage(), ex);
1276 break;
1277 } finally {
1278 db.endTransaction();
1279 }
Tom Taylor527fcce2011-09-21 16:03:40 -07001280 // fall through
1281 case 54:
1282 if (currentVersion <= 54) {
1283 return;
1284 }
1285
1286 db.beginTransaction();
1287 try {
1288 upgradeDatabaseToVersion55(db);
1289 db.setTransactionSuccessful();
1290 } catch (Throwable ex) {
1291 Log.e(TAG, ex.getMessage(), ex);
1292 break;
1293 } finally {
1294 db.endTransaction();
1295 }
Tom Taylorf88d1d62012-09-07 13:38:39 -07001296 // fall through
1297 case 55:
1298 if (currentVersion <= 55) {
1299 return;
1300 }
1301
1302 db.beginTransaction();
1303 try {
1304 upgradeDatabaseToVersion56(db);
1305 db.setTransactionSuccessful();
1306 } catch (Throwable ex) {
1307 Log.e(TAG, ex.getMessage(), ex);
1308 break;
1309 } finally {
1310 db.endTransaction();
1311 }
Tom Taylor1a45ce52012-10-17 11:36:26 -07001312 // fall through
1313 case 56:
1314 if (currentVersion <= 56) {
1315 return;
1316 }
1317
1318 db.beginTransaction();
1319 try {
1320 upgradeDatabaseToVersion57(db);
1321 db.setTransactionSuccessful();
1322 } catch (Throwable ex) {
1323 Log.e(TAG, ex.getMessage(), ex);
1324 break;
1325 } finally {
1326 db.endTransaction();
1327 }
Ye Wencfb8bbd2014-06-17 09:00:38 -07001328 // fall through
1329 case 57:
1330 if (currentVersion <= 57) {
1331 return;
1332 }
1333
1334 db.beginTransaction();
1335 try {
1336 upgradeDatabaseToVersion58(db);
1337 db.setTransactionSuccessful();
1338 } catch (Throwable ex) {
1339 Log.e(TAG, ex.getMessage(), ex);
1340 break;
1341 } finally {
1342 db.endTransaction();
1343 }
Ye Wen49776412014-07-09 16:57:32 -07001344 // fall through
1345 case 58:
1346 if (currentVersion <= 58) {
1347 return;
1348 }
1349
1350 db.beginTransaction();
1351 try {
1352 upgradeDatabaseToVersion59(db);
1353 db.setTransactionSuccessful();
1354 } catch (Throwable ex) {
1355 Log.e(TAG, ex.getMessage(), ex);
1356 break;
1357 } finally {
1358 db.endTransaction();
1359 }
Ye Wen82fc72b2014-07-29 10:42:54 -07001360 // fall through
1361 case 59:
1362 if (currentVersion <= 59) {
1363 return;
1364 }
1365
1366 db.beginTransaction();
1367 try {
1368 upgradeDatabaseToVersion60(db);
1369 db.setTransactionSuccessful();
1370 } catch (Throwable ex) {
1371 Log.e(TAG, ex.getMessage(), ex);
1372 break;
1373 } finally {
1374 db.endTransaction();
1375 }
Ye Wen72f13552015-03-10 14:17:13 -07001376 // fall through
1377 case 60:
1378 if (currentVersion <= 60) {
1379 return;
1380 }
1381
1382 db.beginTransaction();
1383 try {
1384 upgradeDatabaseToVersion61(db);
1385 db.setTransactionSuccessful();
1386 } catch (Throwable ex) {
1387 Log.e(TAG, ex.getMessage(), ex);
1388 break;
1389 } finally {
1390 db.endTransaction();
1391 }
Wei Huangdfac5762010-02-25 17:23:51 -08001392 return;
Tom Taylora6e44cb2010-03-01 09:58:36 -08001393 }
Mark Wagnerf0a9e902009-06-19 16:00:13 -07001394
The Android Open Source Project5f1e43f2009-03-05 14:34:39 -08001395 Log.e(TAG, "Destroying all old data.");
1396 dropAll(db);
The Android Open Source Project7236c3a2009-03-03 19:32:44 -08001397 onCreate(db);
1398 }
1399
Prasath Balakrishnan1dfaed12015-11-18 20:36:17 +05301400 @Override
1401 public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
1402 // Do Nothing
1403 Log.i(TAG, "oldVersion: " + oldVersion + " newVersion: " + newVersion);
1404 }
1405
The Android Open Source Project5f1e43f2009-03-05 14:34:39 -08001406 private void dropAll(SQLiteDatabase db) {
1407 // Clean the database out in order to start over from scratch.
1408 // We don't need to drop our triggers here because SQLite automatically
1409 // drops a trigger when its attached database is dropped.
The Android Open Source Project7236c3a2009-03-03 19:32:44 -08001410 db.execSQL("DROP TABLE IF EXISTS canonical_addresses");
1411 db.execSQL("DROP TABLE IF EXISTS threads");
1412 db.execSQL("DROP TABLE IF EXISTS " + MmsSmsProvider.TABLE_PENDING_MSG);
The Android Open Source Project7236c3a2009-03-03 19:32:44 -08001413 db.execSQL("DROP TABLE IF EXISTS sms");
The Android Open Source Project7236c3a2009-03-03 19:32:44 -08001414 db.execSQL("DROP TABLE IF EXISTS raw");
1415 db.execSQL("DROP TABLE IF EXISTS attachments");
1416 db.execSQL("DROP TABLE IF EXISTS thread_ids");
1417 db.execSQL("DROP TABLE IF EXISTS sr_pending");
The Android Open Source Project7236c3a2009-03-03 19:32:44 -08001418 db.execSQL("DROP TABLE IF EXISTS " + MmsProvider.TABLE_PDU + ";");
1419 db.execSQL("DROP TABLE IF EXISTS " + MmsProvider.TABLE_ADDR + ";");
1420 db.execSQL("DROP TABLE IF EXISTS " + MmsProvider.TABLE_PART + ";");
1421 db.execSQL("DROP TABLE IF EXISTS " + MmsProvider.TABLE_RATE + ";");
1422 db.execSQL("DROP TABLE IF EXISTS " + MmsProvider.TABLE_DRM + ";");
1423 }
1424
The Android Open Source Project7236c3a2009-03-03 19:32:44 -08001425 private void upgradeDatabaseToVersion41(SQLiteDatabase db) {
1426 db.execSQL("DROP TRIGGER IF EXISTS update_threads_error_on_move_mms");
1427 db.execSQL("CREATE TRIGGER update_threads_error_on_move_mms " +
1428 " BEFORE UPDATE OF msg_box ON pdu " +
1429 " WHEN (OLD.msg_box = 4 AND NEW.msg_box != 4) " +
1430 " AND (OLD._id IN (SELECT DISTINCT msg_id" +
1431 " FROM pending_msgs" +
1432 " WHERE err_type >= 10)) " +
1433 "BEGIN " +
1434 " UPDATE threads SET error = error - 1" +
1435 " WHERE _id = OLD.thread_id; " +
1436 "END;");
1437 }
Mark Wagnerf0a9e902009-06-19 16:00:13 -07001438
The Android Open Source Project7236c3a2009-03-03 19:32:44 -08001439 private void upgradeDatabaseToVersion42(SQLiteDatabase db) {
1440 db.execSQL("DROP TRIGGER IF EXISTS sms_update_thread_on_delete");
1441 db.execSQL("DROP TRIGGER IF EXISTS delete_obsolete_threads_sms");
1442 db.execSQL("DROP TRIGGER IF EXISTS update_threads_error_on_delete_sms");
1443 }
Mark Wagnerf0a9e902009-06-19 16:00:13 -07001444
The Android Open Source Project5f1e43f2009-03-05 14:34:39 -08001445 private void upgradeDatabaseToVersion43(SQLiteDatabase db) {
1446 // Add 'has_attachment' column to threads table.
1447 db.execSQL("ALTER TABLE threads ADD COLUMN has_attachment INTEGER DEFAULT 0");
1448
Wei Huang1047ab42009-09-29 20:53:26 -07001449 updateThreadsAttachmentColumn(db);
The Android Open Source Project5f1e43f2009-03-05 14:34:39 -08001450
kaiyizcd21c4f2015-01-30 11:22:36 +08001451 // Add insert triggers for keeping it up to date.
The Android Open Source Project5f1e43f2009-03-05 14:34:39 -08001452 db.execSQL(PART_UPDATE_THREADS_ON_INSERT_TRIGGER);
The Android Open Source Project5f1e43f2009-03-05 14:34:39 -08001453 }
Wei Huang2ad5ba82009-03-24 20:01:04 -07001454
1455 private void upgradeDatabaseToVersion44(SQLiteDatabase db) {
Wei Huang1047ab42009-09-29 20:53:26 -07001456 updateThreadsAttachmentColumn(db);
Wei Huang2ad5ba82009-03-24 20:01:04 -07001457
1458 // add the update trigger for keeping the threads up to date.
1459 db.execSQL(PART_UPDATE_THREADS_ON_UPDATE_TRIGGER);
1460 }
Tom Taylora48a9662009-06-04 14:05:05 -07001461
1462 private void upgradeDatabaseToVersion45(SQLiteDatabase db) {
1463 // Add 'locked' column to sms table.
Tom Taylorfc0eb2f2010-03-11 15:54:15 -08001464 db.execSQL("ALTER TABLE sms ADD COLUMN " + Sms.LOCKED + " INTEGER DEFAULT 0");
Tom Taylora48a9662009-06-04 14:05:05 -07001465
1466 // Add 'locked' column to pdu table.
1467 db.execSQL("ALTER TABLE pdu ADD COLUMN " + Mms.LOCKED + " INTEGER DEFAULT 0");
1468 }
1469
Mark Wagnerf0a9e902009-06-19 16:00:13 -07001470 private void upgradeDatabaseToVersion46(SQLiteDatabase db) {
1471 // add the "text" column for caching inline text (e.g. strings) instead of
1472 // putting them in an external file
1473 db.execSQL("ALTER TABLE part ADD COLUMN " + Part.TEXT + " TEXT");
1474
1475 Cursor textRows = db.query(
1476 "part",
1477 new String[] { Part._ID, Part._DATA, Part.TEXT},
1478 "ct = 'text/plain' OR ct == 'application/smil'",
1479 null,
1480 null,
1481 null,
1482 null);
1483 ArrayList<String> filesToDelete = new ArrayList<String>();
1484 try {
Jeff Hamilton0ebbb482010-05-13 02:08:56 -05001485 db.beginTransaction();
Mark Wagnerf0a9e902009-06-19 16:00:13 -07001486 if (textRows != null) {
Mark Wagnerf0a9e902009-06-19 16:00:13 -07001487 int partDataColumn = textRows.getColumnIndex(Part._DATA);
Mark Wagnerf0a9e902009-06-19 16:00:13 -07001488
1489 // This code is imperfect in that we can't guarantee that all the
1490 // backing files get deleted. For example if the system aborts after
1491 // the database is updated but before we complete the process of
1492 // deleting files.
1493 while (textRows.moveToNext()) {
1494 String path = textRows.getString(partDataColumn);
1495 if (path != null) {
1496 try {
1497 InputStream is = new FileInputStream(path);
1498 byte [] data = new byte[is.available()];
1499 is.read(data);
1500 EncodedStringValue v = new EncodedStringValue(data);
Jeff Hamilton0ebbb482010-05-13 02:08:56 -05001501 db.execSQL("UPDATE part SET " + Part._DATA + " = NULL, " +
1502 Part.TEXT + " = ?", new String[] { v.getString() });
Mark Wagnerf0a9e902009-06-19 16:00:13 -07001503 is.close();
1504 filesToDelete.add(path);
1505 } catch (IOException e) {
1506 // TODO Auto-generated catch block
1507 e.printStackTrace();
1508 }
1509 }
1510 }
1511 }
Jeff Hamilton0ebbb482010-05-13 02:08:56 -05001512 db.setTransactionSuccessful();
Mark Wagnerf0a9e902009-06-19 16:00:13 -07001513 } finally {
Jeff Hamilton0ebbb482010-05-13 02:08:56 -05001514 db.endTransaction();
Mark Wagnerf0a9e902009-06-19 16:00:13 -07001515 for (String pathToDelete : filesToDelete) {
1516 try {
1517 (new File(pathToDelete)).delete();
1518 } catch (SecurityException ex) {
1519 Log.e(TAG, "unable to clean up old mms file for " + pathToDelete, ex);
1520 }
1521 }
1522 if (textRows != null) {
1523 textRows.close();
1524 }
1525 }
1526 }
Wei Huang1047ab42009-09-29 20:53:26 -07001527
1528 private void upgradeDatabaseToVersion47(SQLiteDatabase db) {
1529 updateThreadsAttachmentColumn(db);
1530
1531 // add the update trigger for keeping the threads up to date.
1532 db.execSQL(PDU_UPDATE_THREADS_ON_UPDATE_TRIGGER);
1533 }
1534
Tom Taylorddf267c2009-10-28 18:14:55 -07001535 private void upgradeDatabaseToVersion48(SQLiteDatabase db) {
1536 // Add 'error_code' column to sms table.
1537 db.execSQL("ALTER TABLE sms ADD COLUMN error_code INTEGER DEFAULT 0");
1538 }
1539
Wei Huangdfac5762010-02-25 17:23:51 -08001540 private void upgradeDatabaseToVersion51(SQLiteDatabase db) {
1541 db.execSQL("ALTER TABLE sms add COLUMN seen INTEGER DEFAULT 0");
1542 db.execSQL("ALTER TABLE pdu add COLUMN seen INTEGER DEFAULT 0");
Wei Huanga8826622010-03-31 11:33:57 -07001543
1544 try {
1545 // update the existing sms and pdu tables so the new "seen" column is the same as
1546 // the "read" column for each row.
1547 ContentValues contentValues = new ContentValues();
1548 contentValues.put("seen", 1);
1549 int count = db.update("sms", contentValues, "read=1", null);
1550 Log.d(TAG, "[MmsSmsDb] upgradeDatabaseToVersion51: updated " + count +
1551 " rows in sms table to have READ=1");
1552 count = db.update("pdu", contentValues, "read=1", null);
1553 Log.d(TAG, "[MmsSmsDb] upgradeDatabaseToVersion51: updated " + count +
1554 " rows in pdu table to have READ=1");
1555 } catch (Exception ex) {
1556 Log.e(TAG, "[MmsSmsDb] upgradeDatabaseToVersion51 caught ", ex);
1557 }
Wei Huangdfac5762010-02-25 17:23:51 -08001558 }
1559
Fredrik Roubertea5c40c2010-11-18 17:16:23 +01001560 private void upgradeDatabaseToVersion53(SQLiteDatabase db) {
1561 db.execSQL("DROP TRIGGER IF EXISTS pdu_update_thread_read_on_update");
1562
1563 // Updates threads table whenever a message in pdu is updated.
1564 db.execSQL("CREATE TRIGGER pdu_update_thread_read_on_update AFTER" +
1565 " UPDATE OF " + Mms.READ +
1566 " ON " + MmsProvider.TABLE_PDU + " " +
1567 PDU_UPDATE_THREAD_CONSTRAINTS +
1568 "BEGIN " +
1569 PDU_UPDATE_THREAD_READ_BODY +
1570 "END;");
1571 }
1572
1573 private void upgradeDatabaseToVersion54(SQLiteDatabase db) {
1574 // Add 'date_sent' column to sms table.
1575 db.execSQL("ALTER TABLE sms ADD COLUMN " + Sms.DATE_SENT + " INTEGER DEFAULT 0");
1576
1577 // Add 'date_sent' column to pdu table.
1578 db.execSQL("ALTER TABLE pdu ADD COLUMN " + Mms.DATE_SENT + " INTEGER DEFAULT 0");
1579 }
1580
Tom Taylor527fcce2011-09-21 16:03:40 -07001581 private void upgradeDatabaseToVersion55(SQLiteDatabase db) {
1582 // Drop removed triggers
1583 db.execSQL("DROP TRIGGER IF EXISTS delete_obsolete_threads_pdu");
1584 db.execSQL("DROP TRIGGER IF EXISTS delete_obsolete_threads_when_update_pdu");
1585 }
1586
Tom Taylorf88d1d62012-09-07 13:38:39 -07001587 private void upgradeDatabaseToVersion56(SQLiteDatabase db) {
1588 // Add 'text_only' column to pdu table.
1589 db.execSQL("ALTER TABLE " + MmsProvider.TABLE_PDU + " ADD COLUMN " + Mms.TEXT_ONLY +
1590 " INTEGER DEFAULT 0");
1591 }
1592
Tom Taylor1a45ce52012-10-17 11:36:26 -07001593 private void upgradeDatabaseToVersion57(SQLiteDatabase db) {
1594 // Clear out bad rows, those with empty threadIds, from the pdu table.
1595 db.execSQL("DELETE FROM " + MmsProvider.TABLE_PDU + " WHERE " + Mms.THREAD_ID + " IS NULL");
1596 }
1597
Ye Wencfb8bbd2014-06-17 09:00:38 -07001598 private void upgradeDatabaseToVersion58(SQLiteDatabase db) {
Wink Savillea42e4172014-12-09 18:55:22 -08001599 db.execSQL("ALTER TABLE " + MmsProvider.TABLE_PDU +
1600 " ADD COLUMN " + Mms.SUBSCRIPTION_ID
1601 + " INTEGER DEFAULT " + SubscriptionManager.INVALID_SUBSCRIPTION_ID);
1602 db.execSQL("ALTER TABLE " + MmsSmsProvider.TABLE_PENDING_MSG
1603 +" ADD COLUMN " + "pending_sub_id"
1604 + " INTEGER DEFAULT " + SubscriptionManager.INVALID_SUBSCRIPTION_ID);
1605 db.execSQL("ALTER TABLE " + SmsProvider.TABLE_SMS
1606 + " ADD COLUMN " + Sms.SUBSCRIPTION_ID
1607 + " INTEGER DEFAULT " + SubscriptionManager.INVALID_SUBSCRIPTION_ID);
1608 db.execSQL("ALTER TABLE " + SmsProvider.TABLE_RAW
1609 +" ADD COLUMN " + Sms.SUBSCRIPTION_ID
1610 + " INTEGER DEFAULT " + SubscriptionManager.INVALID_SUBSCRIPTION_ID);
Ye Wencfb8bbd2014-06-17 09:00:38 -07001611 }
1612
Ye Wen49776412014-07-09 16:57:32 -07001613 private void upgradeDatabaseToVersion59(SQLiteDatabase db) {
1614 db.execSQL("ALTER TABLE " + MmsProvider.TABLE_PDU +" ADD COLUMN "
Ye Wen49776412014-07-09 16:57:32 -07001615 + Mms.CREATOR + " TEXT");
1616 db.execSQL("ALTER TABLE " + SmsProvider.TABLE_SMS +" ADD COLUMN "
Ye Wen49776412014-07-09 16:57:32 -07001617 + Sms.CREATOR + " TEXT");
1618 }
1619
Ye Wen82fc72b2014-07-29 10:42:54 -07001620 private void upgradeDatabaseToVersion60(SQLiteDatabase db) {
1621 db.execSQL("ALTER TABLE " + MmsSmsProvider.TABLE_THREADS +" ADD COLUMN "
1622 + Threads.ARCHIVED + " INTEGER DEFAULT 0");
1623 }
1624
Ye Wen72f13552015-03-10 14:17:13 -07001625 private void upgradeDatabaseToVersion61(SQLiteDatabase db) {
1626 db.execSQL("CREATE VIEW " + SmsProvider.VIEW_SMS_RESTRICTED + " AS " +
1627 "SELECT * FROM " + SmsProvider.TABLE_SMS + " WHERE " +
1628 Sms.TYPE + "=" + Sms.MESSAGE_TYPE_INBOX +
1629 " OR " +
1630 Sms.TYPE + "=" + Sms.MESSAGE_TYPE_SENT + ";");
1631 db.execSQL("CREATE VIEW " + MmsProvider.VIEW_PDU_RESTRICTED + " AS " +
1632 "SELECT * FROM " + MmsProvider.TABLE_PDU + " WHERE " +
1633 "(" + Mms.MESSAGE_BOX + "=" + Mms.MESSAGE_BOX_INBOX +
1634 " OR " +
1635 Mms.MESSAGE_BOX + "=" + Mms.MESSAGE_BOX_SENT + ")" +
1636 " AND " +
1637 "(" + Mms.MESSAGE_TYPE + "!=" + PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND + ");");
Suresh Koleti02354f12014-08-19 16:21:45 +05301638 db.execSQL("ALTER TABLE " + MmsProvider.TABLE_PDU +
1639 " ADD COLUMN " + Mms.PHONE_ID
1640 + " INTEGER DEFAULT -1");
1641 db.execSQL("ALTER TABLE " + MmsSmsProvider.TABLE_PENDING_MSG
1642 +" ADD COLUMN " + "pending_sub_id"
1643 + " INTEGER DEFAULT 0");
1644 db.execSQL("ALTER TABLE " + SmsProvider.TABLE_SMS
1645 + " ADD COLUMN " + Sms.PHONE_ID
1646 + " INTEGER DEFAULT -1");
1647 db.execSQL("ALTER TABLE " + SmsProvider.TABLE_RAW
1648 +" ADD COLUMN " + Sms.PHONE_ID
1649 + " INTEGER DEFAULT -1");
Ye Wen72f13552015-03-10 14:17:13 -07001650 }
1651
yanglv3dd0bab2015-08-24 10:40:19 +08001652 private void checkAndUpdateSmsTable(SQLiteDatabase db) {
1653 try {
1654 db.query(SmsProvider.TABLE_SMS, new String[] {"priority"}, null, null, null, null,
1655 null);
1656 } catch (SQLiteException e) {
1657 Log.e(TAG, "checkAndUpgradeSmsTable: ex. ", e);
1658 if (e.getMessage().startsWith(NO_SUCH_COLUMN_EXCEPTION_MESSAGE)) {
1659 db.execSQL("ALTER TABLE " + SmsProvider.TABLE_SMS + " ADD COLUMN "
1660 + "priority INTEGER DEFAULT -1");
1661 }
1662 }
1663 }
1664
Tom Taylor1ab48002011-04-19 14:15:06 -07001665 @Override
1666 public synchronized SQLiteDatabase getWritableDatabase() {
1667 SQLiteDatabase db = super.getWritableDatabase();
1668
Tom Taylor10faf3f2011-04-27 10:05:03 -07001669 if (!sTriedAutoIncrement) {
1670 sTriedAutoIncrement = true;
Tom Taylor15156cd2012-11-15 14:15:46 -08001671 boolean hasAutoIncrementThreads = hasAutoIncrement(db, MmsSmsProvider.TABLE_THREADS);
Tom Taylor09710ce2011-12-06 16:10:34 -08001672 boolean hasAutoIncrementAddresses = hasAutoIncrement(db, "canonical_addresses");
Tom Taylor49c9ede2012-09-09 09:41:50 -07001673 boolean hasAutoIncrementPart = hasAutoIncrement(db, "part");
1674 boolean hasAutoIncrementPdu = hasAutoIncrement(db, "pdu");
Tom Taylor09710ce2011-12-06 16:10:34 -08001675 Log.d(TAG, "[getWritableDatabase] hasAutoIncrementThreads: " + hasAutoIncrementThreads +
Tom Taylor49c9ede2012-09-09 09:41:50 -07001676 " hasAutoIncrementAddresses: " + hasAutoIncrementAddresses +
1677 " hasAutoIncrementPart: " + hasAutoIncrementPart +
1678 " hasAutoIncrementPdu: " + hasAutoIncrementPdu);
Tom Taylor09710ce2011-12-06 16:10:34 -08001679 boolean autoIncrementThreadsSuccess = true;
1680 boolean autoIncrementAddressesSuccess = true;
Tom Taylor49c9ede2012-09-09 09:41:50 -07001681 boolean autoIncrementPartSuccess = true;
1682 boolean autoIncrementPduSuccess = true;
Tom Taylor09710ce2011-12-06 16:10:34 -08001683 if (!hasAutoIncrementThreads) {
Tom Taylor1ab48002011-04-19 14:15:06 -07001684 db.beginTransaction();
1685 try {
Tom Taylor10faf3f2011-04-27 10:05:03 -07001686 if (false && sFakeLowStorageTest) {
1687 Log.d(TAG, "[getWritableDatabase] mFakeLowStorageTest is true " +
1688 " - fake exception");
1689 throw new Exception("FakeLowStorageTest");
1690 }
Tom Taylor09710ce2011-12-06 16:10:34 -08001691 upgradeThreadsTableToAutoIncrement(db); // a no-op if already upgraded
Tom Taylor1ab48002011-04-19 14:15:06 -07001692 db.setTransactionSuccessful();
1693 } catch (Throwable ex) {
Tom Taylor09710ce2011-12-06 16:10:34 -08001694 Log.e(TAG, "Failed to add autoIncrement to threads;: " + ex.getMessage(), ex);
1695 autoIncrementThreadsSuccess = false;
Tom Taylor1ab48002011-04-19 14:15:06 -07001696 } finally {
1697 db.endTransaction();
1698 }
1699 }
Tom Taylor09710ce2011-12-06 16:10:34 -08001700 if (!hasAutoIncrementAddresses) {
1701 db.beginTransaction();
1702 try {
1703 if (false && sFakeLowStorageTest) {
1704 Log.d(TAG, "[getWritableDatabase] mFakeLowStorageTest is true " +
1705 " - fake exception");
1706 throw new Exception("FakeLowStorageTest");
1707 }
1708 upgradeAddressTableToAutoIncrement(db); // a no-op if already upgraded
1709 db.setTransactionSuccessful();
1710 } catch (Throwable ex) {
1711 Log.e(TAG, "Failed to add autoIncrement to canonical_addresses: " +
1712 ex.getMessage(), ex);
1713 autoIncrementAddressesSuccess = false;
1714 } finally {
1715 db.endTransaction();
1716 }
1717 }
Tom Taylor49c9ede2012-09-09 09:41:50 -07001718 if (!hasAutoIncrementPart) {
1719 db.beginTransaction();
1720 try {
1721 if (false && sFakeLowStorageTest) {
1722 Log.d(TAG, "[getWritableDatabase] mFakeLowStorageTest is true " +
1723 " - fake exception");
1724 throw new Exception("FakeLowStorageTest");
1725 }
1726 upgradePartTableToAutoIncrement(db); // a no-op if already upgraded
1727 db.setTransactionSuccessful();
1728 } catch (Throwable ex) {
1729 Log.e(TAG, "Failed to add autoIncrement to part: " +
1730 ex.getMessage(), ex);
1731 autoIncrementPartSuccess = false;
1732 } finally {
1733 db.endTransaction();
1734 }
1735 }
1736 if (!hasAutoIncrementPdu) {
1737 db.beginTransaction();
1738 try {
1739 if (false && sFakeLowStorageTest) {
1740 Log.d(TAG, "[getWritableDatabase] mFakeLowStorageTest is true " +
1741 " - fake exception");
1742 throw new Exception("FakeLowStorageTest");
1743 }
1744 upgradePduTableToAutoIncrement(db); // a no-op if already upgraded
1745 db.setTransactionSuccessful();
1746 } catch (Throwable ex) {
1747 Log.e(TAG, "Failed to add autoIncrement to pdu: " +
1748 ex.getMessage(), ex);
1749 autoIncrementPduSuccess = false;
1750 } finally {
1751 db.endTransaction();
1752 }
1753 }
1754 if (autoIncrementThreadsSuccess &&
1755 autoIncrementAddressesSuccess &&
1756 autoIncrementPartSuccess &&
1757 autoIncrementPduSuccess) {
Tom Taylor09710ce2011-12-06 16:10:34 -08001758 if (mLowStorageMonitor != null) {
1759 // We've already updated the database. This receiver is no longer necessary.
1760 Log.d(TAG, "Unregistering mLowStorageMonitor - we've upgraded");
1761 mContext.unregisterReceiver(mLowStorageMonitor);
1762 mLowStorageMonitor = null;
1763 }
1764 } else {
1765 if (sFakeLowStorageTest) {
1766 sFakeLowStorageTest = false;
1767 }
1768
1769 // We failed, perhaps because of low storage. Turn on a receiver to watch for
1770 // storage space.
1771 if (mLowStorageMonitor == null) {
1772 Log.d(TAG, "[getWritableDatabase] turning on storage monitor");
1773 mLowStorageMonitor = new LowStorageMonitor();
1774 IntentFilter intentFilter = new IntentFilter();
1775 intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_LOW);
1776 intentFilter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
1777 mContext.registerReceiver(mLowStorageMonitor, intentFilter);
1778 }
1779 }
Tom Taylor1ab48002011-04-19 14:15:06 -07001780 }
1781 return db;
1782 }
1783
Tom Taylor09710ce2011-12-06 16:10:34 -08001784 // Determine whether a particular table has AUTOINCREMENT in its schema.
1785 private boolean hasAutoIncrement(SQLiteDatabase db, String tableName) {
Tom Taylor1ab48002011-04-19 14:15:06 -07001786 boolean result = false;
Tom Taylor09710ce2011-12-06 16:10:34 -08001787 String query = "SELECT sql FROM sqlite_master WHERE type='table' AND name='" +
1788 tableName + "'";
Tom Taylor1ab48002011-04-19 14:15:06 -07001789 Cursor c = db.rawQuery(query, null);
1790 if (c != null) {
1791 try {
1792 if (c.moveToFirst()) {
1793 String schema = c.getString(0);
1794 result = schema != null ? schema.contains("AUTOINCREMENT") : false;
Tom Taylor09710ce2011-12-06 16:10:34 -08001795 Log.d(TAG, "[MmsSmsDb] tableName: " + tableName + " hasAutoIncrement: " +
1796 schema + " result: " + result);
Tom Taylor1ab48002011-04-19 14:15:06 -07001797 }
1798 } finally {
1799 c.close();
1800 }
1801 }
1802 return result;
1803 }
1804
1805 // upgradeThreadsTableToAutoIncrement() is called to add the AUTOINCREMENT keyword to
1806 // the threads table. This could fail if the user has a lot of conversations and not enough
1807 // storage to make a copy of the threads table. That's ok. This upgrade is optional. It'll
1808 // be called again next time the device is rebooted.
1809 private void upgradeThreadsTableToAutoIncrement(SQLiteDatabase db) {
Tom Taylor15156cd2012-11-15 14:15:46 -08001810 if (hasAutoIncrement(db, MmsSmsProvider.TABLE_THREADS)) {
Tom Taylor1ab48002011-04-19 14:15:06 -07001811 Log.d(TAG, "[MmsSmsDb] upgradeThreadsTableToAutoIncrement: already upgraded");
1812 return;
1813 }
1814 Log.d(TAG, "[MmsSmsDb] upgradeThreadsTableToAutoIncrement: upgrading");
1815
1816 // Make the _id of the threads table autoincrement so we never re-use thread ids
1817 // Have to create a new temp threads table. Copy all the info from the old table.
1818 // Drop the old table and rename the new table to that of the old.
1819 db.execSQL("CREATE TABLE threads_temp (" +
1820 Threads._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
1821 Threads.DATE + " INTEGER DEFAULT 0," +
1822 Threads.MESSAGE_COUNT + " INTEGER DEFAULT 0," +
1823 Threads.RECIPIENT_IDS + " TEXT," +
1824 Threads.SNIPPET + " TEXT," +
1825 Threads.SNIPPET_CHARSET + " INTEGER DEFAULT 0," +
1826 Threads.READ + " INTEGER DEFAULT 1," +
1827 Threads.TYPE + " INTEGER DEFAULT 0," +
1828 Threads.ERROR + " INTEGER DEFAULT 0," +
1829 Threads.HAS_ATTACHMENT + " INTEGER DEFAULT 0);");
1830
1831 db.execSQL("INSERT INTO threads_temp SELECT * from threads;");
1832 db.execSQL("DROP TABLE threads;");
1833 db.execSQL("ALTER TABLE threads_temp RENAME TO threads;");
1834 }
1835
Tom Taylor09710ce2011-12-06 16:10:34 -08001836 // upgradeAddressTableToAutoIncrement() is called to add the AUTOINCREMENT keyword to
1837 // the canonical_addresses table. This could fail if the user has a lot of people they've
1838 // messaged with and not enough storage to make a copy of the canonical_addresses table.
1839 // That's ok. This upgrade is optional. It'll be called again next time the device is rebooted.
1840 private void upgradeAddressTableToAutoIncrement(SQLiteDatabase db) {
1841 if (hasAutoIncrement(db, "canonical_addresses")) {
1842 Log.d(TAG, "[MmsSmsDb] upgradeAddressTableToAutoIncrement: already upgraded");
1843 return;
1844 }
1845 Log.d(TAG, "[MmsSmsDb] upgradeAddressTableToAutoIncrement: upgrading");
1846
1847 // Make the _id of the canonical_addresses table autoincrement so we never re-use ids
1848 // Have to create a new temp canonical_addresses table. Copy all the info from the old
1849 // table. Drop the old table and rename the new table to that of the old.
1850 db.execSQL("CREATE TABLE canonical_addresses_temp (_id INTEGER PRIMARY KEY AUTOINCREMENT," +
1851 "address TEXT);");
1852
1853 db.execSQL("INSERT INTO canonical_addresses_temp SELECT * from canonical_addresses;");
1854 db.execSQL("DROP TABLE canonical_addresses;");
1855 db.execSQL("ALTER TABLE canonical_addresses_temp RENAME TO canonical_addresses;");
1856 }
1857
Tom Taylor49c9ede2012-09-09 09:41:50 -07001858 // upgradePartTableToAutoIncrement() is called to add the AUTOINCREMENT keyword to
1859 // the part table. This could fail if the user has a lot of sound/video/picture attachments
1860 // and not enough storage to make a copy of the part table.
1861 // That's ok. This upgrade is optional. It'll be called again next time the device is rebooted.
1862 private void upgradePartTableToAutoIncrement(SQLiteDatabase db) {
1863 if (hasAutoIncrement(db, "part")) {
1864 Log.d(TAG, "[MmsSmsDb] upgradePartTableToAutoIncrement: already upgraded");
1865 return;
1866 }
1867 Log.d(TAG, "[MmsSmsDb] upgradePartTableToAutoIncrement: upgrading");
1868
1869 // Make the _id of the part table autoincrement so we never re-use ids
1870 // Have to create a new temp part table. Copy all the info from the old
1871 // table. Drop the old table and rename the new table to that of the old.
1872 db.execSQL("CREATE TABLE part_temp (" +
1873 Part._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
1874 Part.MSG_ID + " INTEGER," +
1875 Part.SEQ + " INTEGER DEFAULT 0," +
1876 Part.CONTENT_TYPE + " TEXT," +
1877 Part.NAME + " TEXT," +
1878 Part.CHARSET + " INTEGER," +
1879 Part.CONTENT_DISPOSITION + " TEXT," +
1880 Part.FILENAME + " TEXT," +
1881 Part.CONTENT_ID + " TEXT," +
1882 Part.CONTENT_LOCATION + " TEXT," +
1883 Part.CT_START + " INTEGER," +
1884 Part.CT_TYPE + " TEXT," +
1885 Part._DATA + " TEXT," +
1886 Part.TEXT + " TEXT);");
1887
1888 db.execSQL("INSERT INTO part_temp SELECT * from part;");
1889 db.execSQL("DROP TABLE part;");
1890 db.execSQL("ALTER TABLE part_temp RENAME TO part;");
1891
1892 // part-related triggers get tossed when the part table is dropped -- rebuild them.
1893 createMmsTriggers(db);
1894 }
1895
1896 // upgradePduTableToAutoIncrement() is called to add the AUTOINCREMENT keyword to
1897 // the pdu table. This could fail if the user has a lot of mms messages
1898 // and not enough storage to make a copy of the pdu table.
1899 // That's ok. This upgrade is optional. It'll be called again next time the device is rebooted.
1900 private void upgradePduTableToAutoIncrement(SQLiteDatabase db) {
1901 if (hasAutoIncrement(db, "pdu")) {
1902 Log.d(TAG, "[MmsSmsDb] upgradePduTableToAutoIncrement: already upgraded");
1903 return;
1904 }
1905 Log.d(TAG, "[MmsSmsDb] upgradePduTableToAutoIncrement: upgrading");
1906
1907 // Make the _id of the part table autoincrement so we never re-use ids
1908 // Have to create a new temp part table. Copy all the info from the old
1909 // table. Drop the old table and rename the new table to that of the old.
1910 db.execSQL("CREATE TABLE pdu_temp (" +
1911 Mms._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
1912 Mms.THREAD_ID + " INTEGER," +
1913 Mms.DATE + " INTEGER," +
1914 Mms.DATE_SENT + " INTEGER DEFAULT 0," +
1915 Mms.MESSAGE_BOX + " INTEGER," +
1916 Mms.READ + " INTEGER DEFAULT 0," +
1917 Mms.MESSAGE_ID + " TEXT," +
1918 Mms.SUBJECT + " TEXT," +
1919 Mms.SUBJECT_CHARSET + " INTEGER," +
1920 Mms.CONTENT_TYPE + " TEXT," +
1921 Mms.CONTENT_LOCATION + " TEXT," +
1922 Mms.EXPIRY + " INTEGER," +
1923 Mms.MESSAGE_CLASS + " TEXT," +
1924 Mms.MESSAGE_TYPE + " INTEGER," +
1925 Mms.MMS_VERSION + " INTEGER," +
1926 Mms.MESSAGE_SIZE + " INTEGER," +
1927 Mms.PRIORITY + " INTEGER," +
1928 Mms.READ_REPORT + " INTEGER," +
1929 Mms.REPORT_ALLOWED + " INTEGER," +
1930 Mms.RESPONSE_STATUS + " INTEGER," +
1931 Mms.STATUS + " INTEGER," +
1932 Mms.TRANSACTION_ID + " TEXT," +
1933 Mms.RETRIEVE_STATUS + " INTEGER," +
1934 Mms.RETRIEVE_TEXT + " TEXT," +
1935 Mms.RETRIEVE_TEXT_CHARSET + " INTEGER," +
1936 Mms.READ_STATUS + " INTEGER," +
1937 Mms.CONTENT_CLASS + " INTEGER," +
1938 Mms.RESPONSE_TEXT + " TEXT," +
1939 Mms.DELIVERY_TIME + " INTEGER," +
1940 Mms.DELIVERY_REPORT + " INTEGER," +
1941 Mms.LOCKED + " INTEGER DEFAULT 0," +
Wink Savillea42e4172014-12-09 18:55:22 -08001942 Mms.SUBSCRIPTION_ID + " INTEGER DEFAULT "
1943 + SubscriptionManager.INVALID_SUBSCRIPTION_ID + ", " +
Suresh Koleti02354f12014-08-19 16:21:45 +05301944 Mms.PHONE_ID + " INTEGER DEFAULT -1," +
Tom Taylor49c9ede2012-09-09 09:41:50 -07001945 Mms.SEEN + " INTEGER DEFAULT 0," +
1946 Mms.TEXT_ONLY + " INTEGER DEFAULT 0" +
1947 ");");
1948
1949 db.execSQL("INSERT INTO pdu_temp SELECT * from pdu;");
1950 db.execSQL("DROP TABLE pdu;");
1951 db.execSQL("ALTER TABLE pdu_temp RENAME TO pdu;");
1952
1953 // pdu-related triggers get tossed when the part table is dropped -- rebuild them.
1954 createMmsTriggers(db);
1955 }
1956
Prasath Balakrishnan1dfaed12015-11-18 20:36:17 +05301957 private boolean createSharedPrefForUpgrade() {
1958 String FILENAME = "upgradeSmsMmsDb";
1959 File prefFile = new File("/data/data/" + mContext.getPackageName()
1960 + "/shared_prefs/" + FILENAME + ".xml");
1961
1962 if (!prefFile.exists()) {
1963 Editor editor;
1964 Log.d(TAG, "Shared Preference Created with name: " + FILENAME);
1965 SharedPreferences pref = mContext.getSharedPreferences(FILENAME,
1966 mContext.MODE_PRIVATE);
1967 editor = pref.edit();
1968 editor.putBoolean("isupgraded", true);
1969 editor.commit();
1970 return true;
1971 } else {
1972 Log.d(TAG, "Skipping upgrade/Upgrade already Done");
1973 return false;
1974 }
1975 }
1976
1977 private void upgradeSmsMmsDb(SQLiteDatabase db) {
1978 if (createSharedPrefForUpgrade()) {
1979 db.beginTransaction();
1980 try {
1981 upgradeDatabaseSmsMms(db);
1982 db.setTransactionSuccessful();
1983 } catch (Throwable ex) {
1984 Log.e(TAG, ex.getMessage(), ex);
1985 } finally {
1986 db.endTransaction();
1987 }
1988 }
1989 }
1990
1991 private void upgradeDatabaseSmsMms(SQLiteDatabase db) {
1992 db.execSQL("CREATE VIEW IF NOT EXISTS " + SmsProvider.VIEW_SMS_RESTRICTED +
1993 " AS " + "SELECT * FROM " + SmsProvider.TABLE_SMS + " WHERE " +
1994 Sms.TYPE + "=" + Sms.MESSAGE_TYPE_INBOX +
1995 " OR " +
1996 Sms.TYPE + "=" + Sms.MESSAGE_TYPE_SENT + ";");
1997 db.execSQL("CREATE VIEW IF NOT EXISTS " + MmsProvider.VIEW_PDU_RESTRICTED +
1998 " AS " + "SELECT * FROM " + MmsProvider.TABLE_PDU + " WHERE " +
1999 "(" + Mms.MESSAGE_BOX + "=" + Mms.MESSAGE_BOX_INBOX +
2000 " OR " +
2001 Mms.MESSAGE_BOX + "=" + Mms.MESSAGE_BOX_SENT + ")" +
2002 " AND " +
2003 "(" + Mms.MESSAGE_TYPE + "!=" +
2004 PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND + ");");
2005 }
2006
Tom Taylor10faf3f2011-04-27 10:05:03 -07002007 private class LowStorageMonitor extends BroadcastReceiver {
2008
2009 public LowStorageMonitor() {
2010 }
2011
2012 public void onReceive(Context context, Intent intent) {
2013 String action = intent.getAction();
2014
2015 Log.d(TAG, "[LowStorageMonitor] onReceive intent " + action);
2016
2017 if (Intent.ACTION_DEVICE_STORAGE_OK.equals(action)) {
2018 sTriedAutoIncrement = false; // try to upgrade on the next getWriteableDatabase
2019 }
2020 }
2021 }
2022
Wei Huang1047ab42009-09-29 20:53:26 -07002023 private void updateThreadsAttachmentColumn(SQLiteDatabase db) {
2024 // Set the values of that column correctly based on the current
2025 // contents of the database.
2026 db.execSQL("UPDATE threads SET has_attachment=1 WHERE _id IN " +
2027 " (SELECT DISTINCT pdu.thread_id FROM part " +
2028 " JOIN pdu ON pdu._id=part.mid " +
2029 " WHERE part.ct != 'text/plain' AND part.ct != 'application/smil')");
2030 }
The Android Open Source Project7236c3a2009-03-03 19:32:44 -08002031}