blob: 74c69f16888a141bfa65d970e5d97499681d9736 [file] [log] [blame]
The Android Open Source Project7236c3a2009-03-03 19:32:44 -08001/*
2 * Copyright (C) 2007 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
19import com.google.android.mms.pdu.PduHeaders;
20
21import android.content.ContentProvider;
22import android.content.ContentValues;
23import android.content.Context;
24import android.content.Intent;
25import android.content.UriMatcher;
26import android.database.Cursor;
27import android.database.sqlite.SQLiteDatabase;
28import android.database.sqlite.SQLiteOpenHelper;
29import android.database.sqlite.SQLiteQueryBuilder;
30import android.net.Uri;
31import android.os.ParcelFileDescriptor;
32import android.provider.BaseColumns;
33import android.provider.Telephony.Mms;
34import android.provider.Telephony.MmsSms;
35import android.provider.Telephony.Mms.Addr;
36import android.provider.Telephony.Mms.Part;
37import android.provider.Telephony.Mms.Rate;
38import android.text.TextUtils;
39import android.util.Config;
40import android.util.Log;
41
42import java.io.File;
43import java.io.FileNotFoundException;
44import java.io.IOException;
45
46/**
47 * The class to provide base facility to access MMS related content,
48 * which is stored in a SQLite database and in the file system.
49 */
50public class MmsProvider extends ContentProvider {
51 static final String TABLE_PDU = "pdu";
52 static final String TABLE_ADDR = "addr";
53 static final String TABLE_PART = "part";
54 static final String TABLE_RATE = "rate";
55 static final String TABLE_DRM = "drm";
56
57 @Override
58 public boolean onCreate() {
59 mOpenHelper = MmsSmsDatabaseHelper.getInstance(getContext());
60 return true;
61 }
62
63 @Override
64 public Cursor query(Uri uri, String[] projection,
65 String selection, String[] selectionArgs, String sortOrder) {
66 SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
67
68 // Generate the body of the query.
69 int match = sURLMatcher.match(uri);
70 if (LOCAL_LOGV) {
71 Log.v(TAG, "Query uri=" + uri + ", match=" + match);
72 }
73
74 switch (match) {
75 case MMS_ALL:
76 constructQueryForBox(qb, Mms.MESSAGE_BOX_ALL);
77 break;
78 case MMS_INBOX:
79 constructQueryForBox(qb, Mms.MESSAGE_BOX_INBOX);
80 break;
81 case MMS_SENT:
82 constructQueryForBox(qb, Mms.MESSAGE_BOX_SENT);
83 break;
84 case MMS_DRAFTS:
85 constructQueryForBox(qb, Mms.MESSAGE_BOX_DRAFTS);
86 break;
87 case MMS_OUTBOX:
88 constructQueryForBox(qb, Mms.MESSAGE_BOX_OUTBOX);
89 break;
90 case MMS_ALL_ID:
91 qb.setTables(TABLE_PDU);
92 qb.appendWhere(Mms._ID + "=" + uri.getPathSegments().get(0));
93 break;
94 case MMS_INBOX_ID:
95 case MMS_SENT_ID:
96 case MMS_DRAFTS_ID:
97 case MMS_OUTBOX_ID:
98 qb.setTables(TABLE_PDU);
99 qb.appendWhere(Mms._ID + "=" + uri.getPathSegments().get(1));
100 qb.appendWhere(" AND " + Mms.MESSAGE_BOX + "="
101 + getMessageBoxByMatch(match));
102 break;
103 case MMS_ALL_PART:
104 qb.setTables(TABLE_PART);
105 break;
106 case MMS_MSG_PART:
107 qb.setTables(TABLE_PART);
108 qb.appendWhere(Part.MSG_ID + "=" + uri.getPathSegments().get(0));
109 break;
110 case MMS_PART_ID:
111 qb.setTables(TABLE_PART);
112 qb.appendWhere(Part._ID + "=" + uri.getPathSegments().get(1));
113 break;
114 case MMS_MSG_ADDR:
115 qb.setTables(TABLE_ADDR);
116 qb.appendWhere(Addr.MSG_ID + "=" + uri.getPathSegments().get(0));
117 break;
118 case MMS_REPORT_STATUS:
119 /*
120 SELECT DISTINCT address,
121 T.delivery_status AS delivery_status,
122 T.read_status AS read_status
123 FROM addr
124 INNER JOIN (SELECT P1._id AS id1, P2._id AS id2, P3._id AS id3,
125 ifnull(P2.st, 0) AS delivery_status,
126 ifnull(P3.read_status, 0) AS read_status
127 FROM pdu P1
128 INNER JOIN pdu P2
129 ON P1.m_id = P2.m_id AND P2.m_type = 134
130 LEFT JOIN pdu P3
131 ON P1.m_id = P3.m_id AND P3.m_type = 136
132 UNION
133 SELECT P1._id AS id1, P2._id AS id2, P3._id AS id3,
134 ifnull(P2.st, 0) AS delivery_status,
135 ifnull(P3.read_status, 0) AS read_status
136 FROM pdu P1
137 INNER JOIN pdu P3
138 ON P1.m_id = P3.m_id AND P3.m_type = 136
139 LEFT JOIN pdu P2
140 ON P1.m_id = P2.m_id AND P2.m_type = 134) T
141 ON (msg_id = id2 AND type = 151)
142 OR (msg_id = id3 AND type = 137)
143 WHERE T.id1 = ?;
144 */
145 qb.setTables("addr INNER JOIN (SELECT P1._id AS id1, P2._id" +
146 " AS id2, P3._id AS id3, ifnull(P2.st, 0) AS" +
147 " delivery_status, ifnull(P3.read_status, 0) AS" +
148 " read_status FROM pdu P1 INNER JOIN pdu P2 ON" +
149 " P1.m_id=P2.m_id AND P2.m_type=134 LEFT JOIN" +
150 " pdu P3 ON P1.m_id=P3.m_id AND P3.m_type=136" +
151 " UNION SELECT P1._id AS id1, P2._id AS id2, P3._id" +
152 " AS id3, ifnull(P2.st, 0) AS delivery_status," +
153 " ifnull(P3.read_status, 0) AS read_status FROM" +
154 " pdu P1 INNER JOIN pdu P3 ON P1.m_id=P3.m_id AND" +
155 " P3.m_type=136 LEFT JOIN pdu P2 ON P1.m_id=P2.m_id" +
156 " AND P2.m_type=134) T ON (msg_id=id2 AND type=151)" +
157 " OR (msg_id=id3 AND type=137)");
158 qb.appendWhere("T.id1 = " + uri.getLastPathSegment());
159 qb.setDistinct(true);
160 break;
161 case MMS_REPORT_REQUEST:
162 /*
163 SELECT address, d_rpt, rr
164 FROM addr join pdu on pdu._id = addr.msg_id
165 WHERE pdu._id = messageId AND addr.type = 151
166 */
167 qb.setTables(TABLE_ADDR + " join " +
168 TABLE_PDU + " on pdu._id = addr.msg_id");
169 qb.appendWhere("pdu._id = " + uri.getLastPathSegment());
170 qb.appendWhere(" AND " + "addr.type = " + PduHeaders.TO);
171 break;
172 case MMS_SENDING_RATE:
173 qb.setTables(TABLE_RATE);
174 break;
175 case MMS_DRM_STORAGE_ID:
176 qb.setTables(TABLE_DRM);
177 qb.appendWhere(BaseColumns._ID + "=" + uri.getLastPathSegment());
178 break;
Tom Taylor6c0ef242009-06-01 12:05:00 -0700179 case MMS_THREADS:
180 qb.setTables("pdu group by thread_id");
181 break;
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800182 default:
Wei Huang2914a7a2009-09-23 00:45:36 -0700183 Log.e(TAG, "query: invalid request: " + uri);
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800184 return null;
185 }
186
187 String finalSortOrder = null;
188 if (TextUtils.isEmpty(sortOrder)) {
189 if (qb.getTables().equals(TABLE_PDU)) {
190 finalSortOrder = Mms.DATE + " DESC";
191 } else if (qb.getTables().equals(TABLE_PART)) {
192 finalSortOrder = Part.SEQ;
193 }
194 } else {
195 finalSortOrder = sortOrder;
196 }
197
198 SQLiteDatabase db = mOpenHelper.getReadableDatabase();
199 Cursor ret = qb.query(db, projection, selection,
200 selectionArgs, null, null, finalSortOrder);
201
202 // TODO: Does this need to be a URI for this provider.
203 ret.setNotificationUri(getContext().getContentResolver(), uri);
204 return ret;
205 }
206
207 private void constructQueryForBox(SQLiteQueryBuilder qb, int msgBox) {
208 qb.setTables(TABLE_PDU);
209
210 if (msgBox != Mms.MESSAGE_BOX_ALL) {
211 qb.appendWhere(Mms.MESSAGE_BOX + "=" + msgBox);
212 }
213 }
214
215 @Override
216 public String getType(Uri uri) {
217 int match = sURLMatcher.match(uri);
218 switch (match) {
219 case MMS_ALL:
220 case MMS_INBOX:
221 case MMS_SENT:
222 case MMS_DRAFTS:
223 case MMS_OUTBOX:
224 return VND_ANDROID_DIR_MMS;
225 case MMS_ALL_ID:
226 case MMS_INBOX_ID:
227 case MMS_SENT_ID:
228 case MMS_DRAFTS_ID:
229 case MMS_OUTBOX_ID:
230 return VND_ANDROID_MMS;
231 case MMS_PART_ID: {
232 Cursor cursor = mOpenHelper.getReadableDatabase().query(
233 TABLE_PART, new String[] { Part.CONTENT_TYPE },
234 Part._ID + " = ?", new String[] { uri.getLastPathSegment() },
235 null, null, null);
236 if (cursor != null) {
237 try {
238 if ((cursor.getCount() == 1) && cursor.moveToFirst()) {
239 return cursor.getString(0);
240 } else {
241 Log.e(TAG, "cursor.count() != 1: " + uri);
242 }
243 } finally {
244 cursor.close();
245 }
246 } else {
247 Log.e(TAG, "cursor == null: " + uri);
248 }
249 return "*/*";
250 }
251 case MMS_ALL_PART:
252 case MMS_MSG_PART:
253 case MMS_MSG_ADDR:
254 default:
255 return "*/*";
256 }
257 }
258
259 @Override
260 public Uri insert(Uri uri, ContentValues values) {
261 int msgBox = Mms.MESSAGE_BOX_ALL;
262 boolean notify = true;
263
264 int match = sURLMatcher.match(uri);
265 if (LOCAL_LOGV) {
266 Log.v(TAG, "Insert uri=" + uri + ", match=" + match);
267 }
268
269 String table = TABLE_PDU;
270 switch (match) {
271 case MMS_ALL:
272 Object msgBoxObj = values.getAsInteger(Mms.MESSAGE_BOX);
273 if (msgBoxObj != null) {
274 msgBox = (Integer) msgBoxObj;
275 }
276 else {
277 // default to inbox
278 msgBox = Mms.MESSAGE_BOX_INBOX;
279 }
280 break;
281 case MMS_INBOX:
282 msgBox = Mms.MESSAGE_BOX_INBOX;
283 break;
284 case MMS_SENT:
285 msgBox = Mms.MESSAGE_BOX_SENT;
286 break;
287 case MMS_DRAFTS:
288 msgBox = Mms.MESSAGE_BOX_DRAFTS;
289 break;
290 case MMS_OUTBOX:
291 msgBox = Mms.MESSAGE_BOX_OUTBOX;
292 break;
293 case MMS_MSG_PART:
294 notify = false;
295 table = TABLE_PART;
296 break;
297 case MMS_MSG_ADDR:
298 notify = false;
299 table = TABLE_ADDR;
300 break;
301 case MMS_SENDING_RATE:
302 notify = false;
303 table = TABLE_RATE;
304 break;
305 case MMS_DRM_STORAGE:
306 notify = false;
307 table = TABLE_DRM;
308 break;
309 default:
Wei Huang2914a7a2009-09-23 00:45:36 -0700310 Log.e(TAG, "insert: invalid request: " + uri);
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800311 return null;
312 }
313
314 SQLiteDatabase db = mOpenHelper.getWritableDatabase();
315 ContentValues finalValues;
316 Uri res = Mms.CONTENT_URI;
317 long rowId;
318
319 if (table.equals(TABLE_PDU)) {
320 boolean addDate = !values.containsKey(Mms.DATE);
321 boolean addMsgBox = !values.containsKey(Mms.MESSAGE_BOX);
322
323 // Filter keys we don't support yet.
324 filterUnsupportedKeys(values);
325
326 // TODO: Should initialValues be validated, e.g. if it
327 // missed some significant keys?
328 finalValues = new ContentValues(values);
329
330 long timeInMillis = System.currentTimeMillis();
331
332 if (addDate) {
333 finalValues.put(Mms.DATE, timeInMillis / 1000L);
334 }
335
336 if (addMsgBox && (msgBox != Mms.MESSAGE_BOX_ALL)) {
337 finalValues.put(Mms.MESSAGE_BOX, msgBox);
338 }
339
340 if (msgBox != Mms.MESSAGE_BOX_INBOX) {
341 // Mark all non-inbox messages read.
342 finalValues.put(Mms.READ, 1);
343 }
344
345 if ((rowId = db.insert(table, null, finalValues)) <= 0) {
346 Log.e(TAG, "MmsProvider.insert: failed! " + finalValues);
347 return null;
348 }
349
350 res = Uri.parse(res + "/" + rowId);
351
352 } else if (table.equals(TABLE_ADDR)) {
353 finalValues = new ContentValues(values);
354 finalValues.put(Addr.MSG_ID, uri.getPathSegments().get(0));
355
356 if ((rowId = db.insert(table, null, finalValues)) <= 0) {
357 Log.e(TAG, "Failed to insert address: " + finalValues);
358 return null;
359 }
360
361 res = Uri.parse(res + "/addr/" + rowId);
362 } else if (table.equals(TABLE_PART)) {
363 finalValues = new ContentValues(values);
364
365 if (match == MMS_MSG_PART) {
366 finalValues.put(Part.MSG_ID, uri.getPathSegments().get(0));
367 }
368
Mark Wagnerf0a9e902009-06-19 16:00:13 -0700369 String contentType = values.getAsString("ct");
370
371 // text/plain and app application/smil store their "data" inline in the
372 // table so there's no need to create the file
373 if (!"text/plain".equals(contentType) && !"application/smil".equals(contentType)) {
374 // Generate the '_data' field of the part with default
375 // permission settings.
376 String path = getContext().getDir("parts", 0).getPath()
377 + "/PART_" + System.currentTimeMillis();
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800378
Mark Wagnerf0a9e902009-06-19 16:00:13 -0700379 finalValues.put(Part._DATA, path);
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800380
Mark Wagnerf0a9e902009-06-19 16:00:13 -0700381 File partFile = new File(path);
382 if (!partFile.exists()) {
383 try {
384 if (!partFile.createNewFile()) {
385 throw new IllegalStateException(
386 "Unable to create new partFile: " + path);
387 }
388 } catch (IOException e) {
389 Log.e(TAG, "createNewFile", e);
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800390 throw new IllegalStateException(
391 "Unable to create new partFile: " + path);
392 }
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800393 }
394 }
395
396 if ((rowId = db.insert(table, null, finalValues)) <= 0) {
397 Log.e(TAG, "MmsProvider.insert: failed! " + finalValues);
398 return null;
399 }
400
401 res = Uri.parse(res + "/part/" + rowId);
402 } else if (table.equals(TABLE_RATE)) {
403 long now = values.getAsLong(Rate.SENT_TIME);
404 long oneHourAgo = now - 1000 * 60 * 60;
405 // Delete all unused rows (time earlier than one hour ago).
406 db.delete(table, Rate.SENT_TIME + "<=" + oneHourAgo, null);
407 db.insert(table, null, values);
408 } else if (table.equals(TABLE_DRM)) {
409 String path = getContext().getDir("parts", 0).getPath()
410 + "/PART_" + System.currentTimeMillis();
411 finalValues = new ContentValues(1);
412 finalValues.put("_data", path);
413
414 File partFile = new File(path);
415 if (!partFile.exists()) {
416 try {
417 if (!partFile.createNewFile()) {
418 throw new IllegalStateException(
419 "Unable to create new file: " + path);
420 }
421 } catch (IOException e) {
422 Log.e(TAG, "createNewFile", e);
423 throw new IllegalStateException(
424 "Unable to create new file: " + path);
425 }
426 }
427
428 if ((rowId = db.insert(table, null, finalValues)) <= 0) {
429 Log.e(TAG, "MmsProvider.insert: failed! " + finalValues);
430 return null;
431 }
432 res = Uri.parse(res + "/drm/" + rowId);
433 } else {
434 throw new AssertionError("Unknown table type: " + table);
435 }
436
437 if (notify) {
438 notifyChange();
439 }
440 return res;
441 }
442
443 private int getMessageBoxByMatch(int match) {
444 switch (match) {
445 case MMS_INBOX_ID:
446 case MMS_INBOX:
447 return Mms.MESSAGE_BOX_INBOX;
448 case MMS_SENT_ID:
449 case MMS_SENT:
450 return Mms.MESSAGE_BOX_SENT;
451 case MMS_DRAFTS_ID:
452 case MMS_DRAFTS:
453 return Mms.MESSAGE_BOX_DRAFTS;
454 case MMS_OUTBOX_ID:
455 case MMS_OUTBOX:
456 return Mms.MESSAGE_BOX_OUTBOX;
457 default:
458 throw new IllegalArgumentException("bad Arg: " + match);
459 }
460 }
461
462 @Override
463 public int delete(Uri uri, String selection,
464 String[] selectionArgs) {
465 int match = sURLMatcher.match(uri);
466 if (LOCAL_LOGV) {
467 Log.v(TAG, "Delete uri=" + uri + ", match=" + match);
468 }
469
470 String table, extraSelection = null;
471 boolean notify = false;
472
473 switch (match) {
474 case MMS_ALL_ID:
475 case MMS_INBOX_ID:
476 case MMS_SENT_ID:
477 case MMS_DRAFTS_ID:
478 case MMS_OUTBOX_ID:
479 notify = true;
480 table = TABLE_PDU;
481 extraSelection = Mms._ID + "=" + uri.getLastPathSegment();
482 break;
483 case MMS_ALL:
484 case MMS_INBOX:
485 case MMS_SENT:
486 case MMS_DRAFTS:
487 case MMS_OUTBOX:
488 notify = true;
489 table = TABLE_PDU;
490 if (match != MMS_ALL) {
491 int msgBox = getMessageBoxByMatch(match);
492 extraSelection = Mms.MESSAGE_BOX + "=" + msgBox;
493 }
494 break;
495 case MMS_ALL_PART:
496 table = TABLE_PART;
497 break;
498 case MMS_MSG_PART:
499 table = TABLE_PART;
500 extraSelection = Part.MSG_ID + "=" + uri.getPathSegments().get(0);
501 break;
502 case MMS_PART_ID:
503 table = TABLE_PART;
504 extraSelection = Part._ID + "=" + uri.getPathSegments().get(1);
505 break;
506 case MMS_MSG_ADDR:
507 table = TABLE_ADDR;
508 extraSelection = Addr.MSG_ID + "=" + uri.getPathSegments().get(0);
509 break;
510 case MMS_DRM_STORAGE:
511 table = TABLE_DRM;
512 break;
513 default:
514 Log.w(TAG, "No match for URI '" + uri + "'");
515 return 0;
516 }
517
518 String finalSelection = concatSelections(selection, extraSelection);
519 SQLiteDatabase db = mOpenHelper.getWritableDatabase();
520 int deletedRows = 0;
521
522 if (TABLE_PDU.equals(table)) {
523 deletedRows = deleteMessages(getContext(), db, finalSelection,
524 selectionArgs, uri);
525 } else if (TABLE_PART.equals(table)) {
526 deletedRows = deleteParts(db, finalSelection, selectionArgs);
527 } else if (TABLE_DRM.equals(table)) {
528 deletedRows = deleteTempDrmData(db, finalSelection, selectionArgs);
529 } else {
530 deletedRows = db.delete(table, finalSelection, selectionArgs);
531 }
532
533 if ((deletedRows > 0) && notify) {
534 notifyChange();
535 }
536 return deletedRows;
537 }
538
539 static int deleteMessages(Context context, SQLiteDatabase db,
540 String selection, String[] selectionArgs, Uri uri) {
541 Cursor cursor = db.query(TABLE_PDU, new String[] { Mms._ID },
542 selection, selectionArgs, null, null, null);
543 if (cursor == null) {
544 return 0;
545 }
546
547 try {
548 if (cursor.getCount() == 0) {
549 return 0;
550 }
551
552 while (cursor.moveToNext()) {
553 deleteParts(db, Part.MSG_ID + " = ?",
554 new String[] { String.valueOf(cursor.getLong(0)) });
555 }
556 } finally {
557 cursor.close();
558 }
559
560 int count = db.delete(TABLE_PDU, selection, selectionArgs);
561 if (count > 0) {
562 Intent intent = new Intent(Mms.Intents.CONTENT_CHANGED_ACTION);
563 intent.putExtra(Mms.Intents.DELETED_CONTENTS, uri);
564 if (LOCAL_LOGV) {
565 Log.v(TAG, "Broadcasting intent: " + intent);
566 }
567 context.sendBroadcast(intent);
568 }
569 return count;
570 }
571
572 private static int deleteParts(SQLiteDatabase db, String selection,
573 String[] selectionArgs) {
574 return deleteDataRows(db, TABLE_PART, selection, selectionArgs);
575 }
576
577 private static int deleteTempDrmData(SQLiteDatabase db, String selection,
578 String[] selectionArgs) {
579 return deleteDataRows(db, TABLE_DRM, selection, selectionArgs);
580 }
581
582 private static int deleteDataRows(SQLiteDatabase db, String table,
583 String selection, String[] selectionArgs) {
584 Cursor cursor = db.query(table, new String[] { "_data" },
585 selection, selectionArgs, null, null, null);
586 if (cursor == null) {
587 // FIXME: This might be an error, ignore it may cause
588 // unpredictable result.
589 return 0;
590 }
591
592 try {
593 if (cursor.getCount() == 0) {
594 return 0;
595 }
596
597 while (cursor.moveToNext()) {
598 try {
599 // Delete the associated files saved on file-system.
Mark Wagnerf0a9e902009-06-19 16:00:13 -0700600 String path = cursor.getString(0);
601 if (path != null) {
602 new File(path).delete();
603 }
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800604 } catch (Throwable ex) {
605 Log.e(TAG, ex.getMessage(), ex);
606 }
607 }
608 } finally {
609 cursor.close();
610 }
611
612 return db.delete(table, selection, selectionArgs);
613 }
614
615 @Override
616 public int update(Uri uri, ContentValues values,
617 String selection, String[] selectionArgs) {
618 int match = sURLMatcher.match(uri);
619 if (LOCAL_LOGV) {
620 Log.v(TAG, "Update uri=" + uri + ", match=" + match);
621 }
622
623 boolean notify = false;
624 String msgId = null;
625 String table;
626
627 switch (match) {
628 case MMS_ALL_ID:
629 case MMS_INBOX_ID:
630 case MMS_SENT_ID:
631 case MMS_DRAFTS_ID:
632 case MMS_OUTBOX_ID:
633 msgId = uri.getLastPathSegment();
634 // fall-through
635 case MMS_ALL:
636 case MMS_INBOX:
637 case MMS_SENT:
638 case MMS_DRAFTS:
639 case MMS_OUTBOX:
640 notify = true;
641 table = TABLE_PDU;
642 break;
643 case MMS_MSG_PART:
644 case MMS_PART_ID:
645 table = TABLE_PART;
646 break;
647 default:
648 Log.w(TAG, "Update operation for '" + uri + "' not implemented.");
649 return 0;
650 }
651
652 String extraSelection = null;
653 ContentValues finalValues;
654 if (table.equals(TABLE_PDU)) {
655 // Filter keys that we don't support yet.
656 filterUnsupportedKeys(values);
657 finalValues = new ContentValues(values);
658
659 if (msgId != null) {
660 extraSelection = Mms._ID + "=" + msgId;
661 }
662 } else if (table.equals(TABLE_PART)) {
663 finalValues = new ContentValues(values);
664
665 switch (match) {
666 case MMS_MSG_PART:
667 extraSelection = Part.MSG_ID + "=" + uri.getPathSegments().get(0);
668 break;
669 case MMS_PART_ID:
670 extraSelection = Part._ID + "=" + uri.getPathSegments().get(1);
671 break;
672 default:
673 break;
674 }
675 } else {
676 return 0;
677 }
678
679 String finalSelection = concatSelections(selection, extraSelection);
680 SQLiteDatabase db = mOpenHelper.getWritableDatabase();
681 int count = db.update(table, finalValues, finalSelection, selectionArgs);
682 if (notify && (count > 0)) {
683 notifyChange();
684 }
685 return count;
686 }
687
Wei Huang2914a7a2009-09-23 00:45:36 -0700688 private ParcelFileDescriptor getTempStoreFd() {
689 String fileName = Mms.ScrapSpace.SCRAP_FILE_PATH;
690 ParcelFileDescriptor pfd = null;
691
692 try {
693 File file = new File(fileName);
694
695 // make sure the path is valid and directories created for this file.
696 File parentFile = file.getParentFile();
697 if (!parentFile.exists() && !parentFile.mkdirs()) {
698 Log.e(TAG, "[MmsProvider] getTempStoreFd: " + parentFile.getPath() +
699 "does not exist!");
700 return null;
701 }
702
703 pfd = ParcelFileDescriptor.open(file,
704 ParcelFileDescriptor.MODE_READ_WRITE
705 | android.os.ParcelFileDescriptor.MODE_CREATE);
706 } catch (Exception ex) {
707 Log.e(TAG, "getTempStoreFd: error creating pfd for " + fileName, ex);
708 }
709
710 return pfd;
711 }
712
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800713 @Override
Wei Huang2914a7a2009-09-23 00:45:36 -0700714 public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
715 // if the url is "content://mms/takePictureTempStore", then it means the requester
716 // wants a file descriptor to write image data to.
717
718 ParcelFileDescriptor fd;
719 int match = sURLMatcher.match(uri);
720
721 if (Log.isLoggable(TAG, Log.VERBOSE)) {
722 Log.d(TAG, "openFile: uri=" + uri + ", mode=" + mode);
723 }
724
725 switch (match) {
726 case MMS_SCRAP_SPACE:
727 fd = getTempStoreFd();
728 break;
729
730 default:
731 fd = openFileHelper(uri, mode);
732 }
733
734 return fd;
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800735 }
736
737 private void filterUnsupportedKeys(ContentValues values) {
738 // Some columns are unsupported. They should therefore
739 // neither be inserted nor updated. Filter them out.
740 values.remove(Mms.DELIVERY_TIME_TOKEN);
741 values.remove(Mms.SENDER_VISIBILITY);
742 values.remove(Mms.REPLY_CHARGING);
743 values.remove(Mms.REPLY_CHARGING_DEADLINE_TOKEN);
744 values.remove(Mms.REPLY_CHARGING_DEADLINE);
745 values.remove(Mms.REPLY_CHARGING_ID);
746 values.remove(Mms.REPLY_CHARGING_SIZE);
747 values.remove(Mms.PREVIOUSLY_SENT_BY);
748 values.remove(Mms.PREVIOUSLY_SENT_DATE);
749 values.remove(Mms.STORE);
750 values.remove(Mms.MM_STATE);
751 values.remove(Mms.MM_FLAGS_TOKEN);
752 values.remove(Mms.MM_FLAGS);
753 values.remove(Mms.STORE_STATUS);
754 values.remove(Mms.STORE_STATUS_TEXT);
755 values.remove(Mms.STORED);
756 values.remove(Mms.TOTALS);
757 values.remove(Mms.MBOX_TOTALS);
758 values.remove(Mms.MBOX_TOTALS_TOKEN);
759 values.remove(Mms.QUOTAS);
760 values.remove(Mms.MBOX_QUOTAS);
761 values.remove(Mms.MBOX_QUOTAS_TOKEN);
762 values.remove(Mms.MESSAGE_COUNT);
763 values.remove(Mms.START);
764 values.remove(Mms.DISTRIBUTION_INDICATOR);
765 values.remove(Mms.ELEMENT_DESCRIPTOR);
766 values.remove(Mms.LIMIT);
767 values.remove(Mms.RECOMMENDED_RETRIEVAL_MODE);
768 values.remove(Mms.RECOMMENDED_RETRIEVAL_MODE_TEXT);
769 values.remove(Mms.STATUS_TEXT);
770 values.remove(Mms.APPLIC_ID);
771 values.remove(Mms.REPLY_APPLIC_ID);
772 values.remove(Mms.AUX_APPLIC_ID);
773 values.remove(Mms.DRM_CONTENT);
774 values.remove(Mms.ADAPTATION_ALLOWED);
775 values.remove(Mms.REPLACE_ID);
776 values.remove(Mms.CANCEL_ID);
777 values.remove(Mms.CANCEL_STATUS);
778
779 // Keys shouldn't be inserted or updated.
780 values.remove(Mms._ID);
781 }
782
783 private void notifyChange() {
784 getContext().getContentResolver().notifyChange(
785 MmsSms.CONTENT_URI, null);
786 }
787
788 private final static String TAG = "MmsProvider";
789 private final static String VND_ANDROID_MMS = "vnd.android/mms";
790 private final static String VND_ANDROID_DIR_MMS = "vnd.android-dir/mms";
791 private final static boolean DEBUG = false;
792 private final static boolean LOCAL_LOGV = DEBUG ? Config.LOGD : Config.LOGV;
793
794 private static final int MMS_ALL = 0;
795 private static final int MMS_ALL_ID = 1;
796 private static final int MMS_INBOX = 2;
797 private static final int MMS_INBOX_ID = 3;
798 private static final int MMS_SENT = 4;
799 private static final int MMS_SENT_ID = 5;
800 private static final int MMS_DRAFTS = 6;
801 private static final int MMS_DRAFTS_ID = 7;
802 private static final int MMS_OUTBOX = 8;
803 private static final int MMS_OUTBOX_ID = 9;
804 private static final int MMS_ALL_PART = 10;
805 private static final int MMS_MSG_PART = 11;
806 private static final int MMS_PART_ID = 12;
807 private static final int MMS_MSG_ADDR = 13;
808 private static final int MMS_SENDING_RATE = 14;
Tom Taylor6c0ef242009-06-01 12:05:00 -0700809 private static final int MMS_REPORT_STATUS = 15;
810 private static final int MMS_REPORT_REQUEST = 16;
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800811 private static final int MMS_DRM_STORAGE = 17;
812 private static final int MMS_DRM_STORAGE_ID = 18;
Tom Taylor6c0ef242009-06-01 12:05:00 -0700813 private static final int MMS_THREADS = 19;
Wei Huang2914a7a2009-09-23 00:45:36 -0700814 private static final int MMS_SCRAP_SPACE = 20;
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800815
816 private static final UriMatcher
817 sURLMatcher = new UriMatcher(UriMatcher.NO_MATCH);
818
819 static {
820 sURLMatcher.addURI("mms", null, MMS_ALL);
821 sURLMatcher.addURI("mms", "#", MMS_ALL_ID);
822 sURLMatcher.addURI("mms", "inbox", MMS_INBOX);
823 sURLMatcher.addURI("mms", "inbox/#", MMS_INBOX_ID);
824 sURLMatcher.addURI("mms", "sent", MMS_SENT);
825 sURLMatcher.addURI("mms", "sent/#", MMS_SENT_ID);
826 sURLMatcher.addURI("mms", "drafts", MMS_DRAFTS);
827 sURLMatcher.addURI("mms", "drafts/#", MMS_DRAFTS_ID);
828 sURLMatcher.addURI("mms", "outbox", MMS_OUTBOX);
829 sURLMatcher.addURI("mms", "outbox/#", MMS_OUTBOX_ID);
830 sURLMatcher.addURI("mms", "part", MMS_ALL_PART);
831 sURLMatcher.addURI("mms", "#/part", MMS_MSG_PART);
832 sURLMatcher.addURI("mms", "part/#", MMS_PART_ID);
833 sURLMatcher.addURI("mms", "#/addr", MMS_MSG_ADDR);
834 sURLMatcher.addURI("mms", "rate", MMS_SENDING_RATE);
835 sURLMatcher.addURI("mms", "report-status/#", MMS_REPORT_STATUS);
836 sURLMatcher.addURI("mms", "report-request/#", MMS_REPORT_REQUEST);
837 sURLMatcher.addURI("mms", "drm", MMS_DRM_STORAGE);
838 sURLMatcher.addURI("mms", "drm/#", MMS_DRM_STORAGE_ID);
Tom Taylor6c0ef242009-06-01 12:05:00 -0700839 sURLMatcher.addURI("mms", "threads", MMS_THREADS);
Wei Huang2914a7a2009-09-23 00:45:36 -0700840 sURLMatcher.addURI("mms", "scrapSpace", MMS_SCRAP_SPACE);
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800841 }
842
843 private SQLiteOpenHelper mOpenHelper;
844
845 private static String concatSelections(String selection1, String selection2) {
846 if (TextUtils.isEmpty(selection1)) {
847 return selection2;
848 } else if (TextUtils.isEmpty(selection2)) {
849 return selection1;
850 } else {
851 return selection1 + " AND " + selection2;
852 }
853 }
854}
855