blob: c75c6ad35aca5b264d93ab1f5b8329281097662c [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
Dianne Hackbornf27792f2013-02-04 18:26:53 -080019import android.app.AppOpsManager;
The Android Open Source Project7236c3a2009-03-03 19:32:44 -080020import android.content.ContentProvider;
kaiyiz81ee3bc2015-02-06 13:43:48 +080021import android.content.ContentUris;
The Android Open Source Project7236c3a2009-03-03 19:32:44 -080022import android.content.ContentValues;
23import android.content.Context;
24import android.content.Intent;
25import android.content.UriMatcher;
26import android.database.Cursor;
kaiyiz81ee3bc2015-02-06 13:43:48 +080027import android.database.MatrixCursor;
The Android Open Source Project7236c3a2009-03-03 19:32:44 -080028import android.database.sqlite.SQLiteDatabase;
Tom Taylor3ad9da42014-01-16 13:57:11 -080029import android.database.sqlite.SQLiteException;
The Android Open Source Project7236c3a2009-03-03 19:32:44 -080030import android.database.sqlite.SQLiteOpenHelper;
31import android.database.sqlite.SQLiteQueryBuilder;
32import android.net.Uri;
Ye Wene07acb92014-11-19 12:06:05 -080033import android.os.Binder;
Tom Taylorc2db47d2012-03-27 15:15:39 -070034import android.os.FileUtils;
The Android Open Source Project7236c3a2009-03-03 19:32:44 -080035import android.os.ParcelFileDescriptor;
Amith Yamasani43f9fb22014-09-10 15:56:47 -070036import android.os.UserHandle;
The Android Open Source Project7236c3a2009-03-03 19:32:44 -080037import android.provider.BaseColumns;
Mark Wagner8e5ee782010-01-04 17:39:06 -080038import android.provider.Telephony;
Yusuf T. Mobile21c25bc2009-06-16 13:40:38 -070039import android.provider.Telephony.CanonicalAddressesColumns;
The Android Open Source Project7236c3a2009-03-03 19:32:44 -080040import android.provider.Telephony.Mms;
The Android Open Source Project7236c3a2009-03-03 19:32:44 -080041import android.provider.Telephony.Mms.Addr;
42import android.provider.Telephony.Mms.Part;
43import android.provider.Telephony.Mms.Rate;
Ye Wene07acb92014-11-19 12:06:05 -080044import android.provider.Telephony.MmsSms;
45import android.provider.Telephony.Threads;
The Android Open Source Project7236c3a2009-03-03 19:32:44 -080046import android.text.TextUtils;
The Android Open Source Project7236c3a2009-03-03 19:32:44 -080047import android.util.Log;
48
kaiyiz81ee3bc2015-02-06 13:43:48 +080049import com.google.android.mms.MmsException;
50import com.google.android.mms.pdu.GenericPdu;
51import com.google.android.mms.pdu.PduComposer;
52import com.google.android.mms.pdu.RetrieveConf;
Tom Taylorb1bae652010-03-08 16:33:42 -080053import com.google.android.mms.pdu.PduHeaders;
kaiyiz81ee3bc2015-02-06 13:43:48 +080054import com.google.android.mms.pdu.PduPersister;
55import com.google.android.mms.pdu.PduParser;
56import com.google.android.mms.pdu.SendReq;
Tom Taylorc2db47d2012-03-27 15:15:39 -070057import com.google.android.mms.util.DownloadDrmHelper;
Tom Taylorc71e7702010-01-28 09:23:12 -080058
The Android Open Source Project7236c3a2009-03-03 19:32:44 -080059import java.io.File;
kaiyiz81ee3bc2015-02-06 13:43:48 +080060import java.io.FileInputStream;
The Android Open Source Project7236c3a2009-03-03 19:32:44 -080061import java.io.FileNotFoundException;
62import java.io.IOException;
kaiyizcd21c4f2015-01-30 11:22:36 +080063import java.util.HashSet;
Amith Yamasani43f9fb22014-09-10 15:56:47 -070064
The Android Open Source Project7236c3a2009-03-03 19:32:44 -080065/**
66 * The class to provide base facility to access MMS related content,
67 * which is stored in a SQLite database and in the file system.
68 */
69public class MmsProvider extends ContentProvider {
70 static final String TABLE_PDU = "pdu";
71 static final String TABLE_ADDR = "addr";
72 static final String TABLE_PART = "part";
73 static final String TABLE_RATE = "rate";
74 static final String TABLE_DRM = "drm";
Mark Wagner8e5ee782010-01-04 17:39:06 -080075 static final String TABLE_WORDS = "words";
Ye Wen72f13552015-03-10 14:17:13 -070076 static final String VIEW_PDU_RESTRICTED = "pdu_restricted";
The Android Open Source Project7236c3a2009-03-03 19:32:44 -080077
Ye Weneaa93e62015-01-06 13:08:53 -080078 // The name of parts directory. The full dir is "app_parts".
79 private static final String PARTS_DIR_NAME = "parts";
kaiyiz81ee3bc2015-02-06 13:43:48 +080080 static final String COLUMN_PDU_PATH = "pdu_path";
81
82 private final static String[] PDU_COLUMNS = new String[] {
83 "_id",
84 "pdu_path",
85 "pdu_data"
86 };
Tom Taylorc2db47d2012-03-27 15:15:39 -070087
The Android Open Source Project7236c3a2009-03-03 19:32:44 -080088 @Override
89 public boolean onCreate() {
Ye Wenb2ce2d32014-07-28 14:49:30 -070090 setAppOps(AppOpsManager.OP_READ_SMS, AppOpsManager.OP_WRITE_SMS);
91 mOpenHelper = MmsSmsDatabaseHelper.getInstance(getContext());
The Android Open Source Project7236c3a2009-03-03 19:32:44 -080092 return true;
93 }
94
Ye Wen72f13552015-03-10 14:17:13 -070095 /**
96 * Return the proper view of "pdu" table for the current access status.
97 *
98 * @param accessRestricted If the access is restricted
99 * @return the table/view name of the mms data
100 */
101 public static String getPduTable(boolean accessRestricted) {
102 return accessRestricted ? VIEW_PDU_RESTRICTED : TABLE_PDU;
103 }
104
kaiyiz81ee3bc2015-02-06 13:43:48 +0800105 private byte[] getPduDataFromDB(int msgId, int msgType) {
106 Uri uri = ContentUris.withAppendedId(Mms.CONTENT_URI, msgId);
107 PduPersister persister = PduPersister.getPduPersister(getContext());
108 byte[] mmsData = null;
109 try {
110 if (Mms.MESSAGE_BOX_INBOX == msgType
111 || Mms.MESSAGE_BOX_SENT == msgType) {
112 GenericPdu pdu = persister.load(uri);
113 if (pdu != null) {
114 mmsData = new PduComposer(getContext(), pdu).make();
115 }
116 }
117 } catch (MmsException e) {
118 Log.e(TAG, "MmsException e=" + e);
119 }
120 return mmsData;
121 }
122
123 private Cursor getPdus(int itemCount, int dataCount, String[] data) {
124 MatrixCursor cursor = new MatrixCursor(PDU_COLUMNS, 1);
125 long token = Binder.clearCallingIdentity();
126 SQLiteDatabase db = mOpenHelper.getReadableDatabase();
127 db.beginTransaction();
128 try {
129 for (int i = 0; i < dataCount; i++) {
130 int msgId = Integer.parseInt(data[i * itemCount]);
131 int msgType = Integer.parseInt(data[i * itemCount + 1]);
132 String pduPath = data[i * itemCount + 2];
133 byte[] pduData = getPduDataFromDB(msgId, msgType);
134 if (pduData == null || pduData.length == 0) {
135 Log.e(TAG, "can't get msgId:" + msgId + " pdu data.");
136 continue;
137 }
138 Object[] row = new Object[3];
139 row[0] = msgId;
140 row[1] = pduPath;
141 row[2] = pduData;
142 cursor.addRow(row);
143 }
144 db.setTransactionSuccessful();
145 } catch (Exception e) {
146 Log.e(TAG, "Exception e =", e);
147 } finally {
148 Binder.restoreCallingIdentity(token);
149 db.endTransaction();
150 }
151 return cursor;
152 }
153
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800154 @Override
155 public Cursor query(Uri uri, String[] projection,
156 String selection, String[] selectionArgs, String sortOrder) {
Ye Wen72f13552015-03-10 14:17:13 -0700157 // First check if a restricted view of the "pdu" table should be used based on the
158 // caller's identity. Only system, phone or the default sms app can have full access
159 // of mms data. For other apps, we present a restricted view which only contains sent
160 // or received messages, without wap pushes.
161 final boolean accessRestricted = ProviderUtil.isAccessRestricted(
162 getContext(), getCallingPackage(), Binder.getCallingUid());
163 final String pduTable = getPduTable(accessRestricted);
164
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800165 SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
166
167 // Generate the body of the query.
168 int match = sURLMatcher.match(uri);
169 if (LOCAL_LOGV) {
170 Log.v(TAG, "Query uri=" + uri + ", match=" + match);
171 }
172
173 switch (match) {
174 case MMS_ALL:
Ye Wen72f13552015-03-10 14:17:13 -0700175 constructQueryForBox(qb, Mms.MESSAGE_BOX_ALL, pduTable);
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800176 break;
177 case MMS_INBOX:
Ye Wen72f13552015-03-10 14:17:13 -0700178 constructQueryForBox(qb, Mms.MESSAGE_BOX_INBOX, pduTable);
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800179 break;
180 case MMS_SENT:
Ye Wen72f13552015-03-10 14:17:13 -0700181 constructQueryForBox(qb, Mms.MESSAGE_BOX_SENT, pduTable);
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800182 break;
183 case MMS_DRAFTS:
Ye Wen72f13552015-03-10 14:17:13 -0700184 constructQueryForBox(qb, Mms.MESSAGE_BOX_DRAFTS, pduTable);
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800185 break;
186 case MMS_OUTBOX:
Ye Wen72f13552015-03-10 14:17:13 -0700187 constructQueryForBox(qb, Mms.MESSAGE_BOX_OUTBOX, pduTable);
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800188 break;
189 case MMS_ALL_ID:
Ye Wen72f13552015-03-10 14:17:13 -0700190 qb.setTables(pduTable);
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800191 qb.appendWhere(Mms._ID + "=" + uri.getPathSegments().get(0));
192 break;
193 case MMS_INBOX_ID:
194 case MMS_SENT_ID:
195 case MMS_DRAFTS_ID:
196 case MMS_OUTBOX_ID:
Ye Wen72f13552015-03-10 14:17:13 -0700197 qb.setTables(pduTable);
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800198 qb.appendWhere(Mms._ID + "=" + uri.getPathSegments().get(1));
199 qb.appendWhere(" AND " + Mms.MESSAGE_BOX + "="
200 + getMessageBoxByMatch(match));
201 break;
202 case MMS_ALL_PART:
203 qb.setTables(TABLE_PART);
204 break;
205 case MMS_MSG_PART:
206 qb.setTables(TABLE_PART);
207 qb.appendWhere(Part.MSG_ID + "=" + uri.getPathSegments().get(0));
208 break;
209 case MMS_PART_ID:
210 qb.setTables(TABLE_PART);
211 qb.appendWhere(Part._ID + "=" + uri.getPathSegments().get(1));
212 break;
213 case MMS_MSG_ADDR:
214 qb.setTables(TABLE_ADDR);
215 qb.appendWhere(Addr.MSG_ID + "=" + uri.getPathSegments().get(0));
216 break;
217 case MMS_REPORT_STATUS:
218 /*
219 SELECT DISTINCT address,
220 T.delivery_status AS delivery_status,
221 T.read_status AS read_status
222 FROM addr
223 INNER JOIN (SELECT P1._id AS id1, P2._id AS id2, P3._id AS id3,
224 ifnull(P2.st, 0) AS delivery_status,
225 ifnull(P3.read_status, 0) AS read_status
226 FROM pdu P1
227 INNER JOIN pdu P2
228 ON P1.m_id = P2.m_id AND P2.m_type = 134
229 LEFT JOIN pdu P3
230 ON P1.m_id = P3.m_id AND P3.m_type = 136
231 UNION
232 SELECT P1._id AS id1, P2._id AS id2, P3._id AS id3,
233 ifnull(P2.st, 0) AS delivery_status,
234 ifnull(P3.read_status, 0) AS read_status
235 FROM pdu P1
236 INNER JOIN pdu P3
237 ON P1.m_id = P3.m_id AND P3.m_type = 136
238 LEFT JOIN pdu P2
239 ON P1.m_id = P2.m_id AND P2.m_type = 134) T
240 ON (msg_id = id2 AND type = 151)
241 OR (msg_id = id3 AND type = 137)
242 WHERE T.id1 = ?;
243 */
Ye Wen72f13552015-03-10 14:17:13 -0700244 qb.setTables(TABLE_ADDR + " INNER JOIN "
245 + "(SELECT P1._id AS id1, P2._id AS id2, P3._id AS id3, "
246 + "ifnull(P2.st, 0) AS delivery_status, "
247 + "ifnull(P3.read_status, 0) AS read_status "
248 + "FROM " + pduTable + " P1 INNER JOIN " + pduTable + " P2 "
249 + "ON P1.m_id=P2.m_id AND P2.m_type=134 "
250 + "LEFT JOIN " + pduTable + " P3 "
251 + "ON P1.m_id=P3.m_id AND P3.m_type=136 "
252 + "UNION "
253 + "SELECT P1._id AS id1, P2._id AS id2, P3._id AS id3, "
254 + "ifnull(P2.st, 0) AS delivery_status, "
255 + "ifnull(P3.read_status, 0) AS read_status "
256 + "FROM " + pduTable + " P1 INNER JOIN " + pduTable + " P3 "
257 + "ON P1.m_id=P3.m_id AND P3.m_type=136 "
258 + "LEFT JOIN " + pduTable + " P2 "
259 + "ON P1.m_id=P2.m_id AND P2.m_type=134) T "
260 + "ON (msg_id=id2 AND type=151) OR (msg_id=id3 AND type=137)");
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800261 qb.appendWhere("T.id1 = " + uri.getLastPathSegment());
262 qb.setDistinct(true);
263 break;
264 case MMS_REPORT_REQUEST:
265 /*
266 SELECT address, d_rpt, rr
267 FROM addr join pdu on pdu._id = addr.msg_id
268 WHERE pdu._id = messageId AND addr.type = 151
269 */
270 qb.setTables(TABLE_ADDR + " join " +
Ye Wen72f13552015-03-10 14:17:13 -0700271 pduTable + " on " + pduTable + "._id = addr.msg_id");
272 qb.appendWhere(pduTable + "._id = " + uri.getLastPathSegment());
273 qb.appendWhere(" AND " + TABLE_ADDR + ".type = " + PduHeaders.TO);
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800274 break;
275 case MMS_SENDING_RATE:
276 qb.setTables(TABLE_RATE);
277 break;
278 case MMS_DRM_STORAGE_ID:
279 qb.setTables(TABLE_DRM);
280 qb.appendWhere(BaseColumns._ID + "=" + uri.getLastPathSegment());
281 break;
Tom Taylor6c0ef242009-06-01 12:05:00 -0700282 case MMS_THREADS:
Ye Wen72f13552015-03-10 14:17:13 -0700283 qb.setTables(pduTable + " group by thread_id");
Tom Taylor6c0ef242009-06-01 12:05:00 -0700284 break;
kaiyiz81ee3bc2015-02-06 13:43:48 +0800285 case MMS_GET_PDU:
286 int itemCount = Integer.parseInt(uri.getQueryParameter("item_count"));
287 int dataCount = Integer.parseInt(uri.getQueryParameter("data_count"));
288 String split = uri.getQueryParameter("data_split");
289 String[] data = null;
290 if (!TextUtils.isEmpty(uri.getQueryParameter("data"))) {
291 data = uri.getQueryParameter("data").split(split);
292 Log.d(TAG, "data.length :" + data.length);
293 return getPdus(itemCount, dataCount, data);
294 } else {
295 Log.e(TAG, "MMS get pdu date return null");
296 return null;
297 }
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800298 default:
Wei Huang2914a7a2009-09-23 00:45:36 -0700299 Log.e(TAG, "query: invalid request: " + uri);
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800300 return null;
301 }
302
303 String finalSortOrder = null;
304 if (TextUtils.isEmpty(sortOrder)) {
Ye Wen72f13552015-03-10 14:17:13 -0700305 if (qb.getTables().equals(pduTable)) {
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800306 finalSortOrder = Mms.DATE + " DESC";
307 } else if (qb.getTables().equals(TABLE_PART)) {
308 finalSortOrder = Part.SEQ;
309 }
310 } else {
311 finalSortOrder = sortOrder;
312 }
313
Tom Taylor3ad9da42014-01-16 13:57:11 -0800314 Cursor ret;
315 try {
316 SQLiteDatabase db = mOpenHelper.getReadableDatabase();
317 ret = qb.query(db, projection, selection,
318 selectionArgs, null, null, finalSortOrder);
319 } catch (SQLiteException e) {
320 Log.e(TAG, "returning NULL cursor, query: " + uri, e);
321 return null;
322 }
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800323
324 // TODO: Does this need to be a URI for this provider.
325 ret.setNotificationUri(getContext().getContentResolver(), uri);
326 return ret;
327 }
328
Ye Wen72f13552015-03-10 14:17:13 -0700329 private void constructQueryForBox(SQLiteQueryBuilder qb, int msgBox, String pduTable) {
330 qb.setTables(pduTable);
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800331
332 if (msgBox != Mms.MESSAGE_BOX_ALL) {
333 qb.appendWhere(Mms.MESSAGE_BOX + "=" + msgBox);
334 }
335 }
336
337 @Override
338 public String getType(Uri uri) {
339 int match = sURLMatcher.match(uri);
340 switch (match) {
341 case MMS_ALL:
342 case MMS_INBOX:
343 case MMS_SENT:
344 case MMS_DRAFTS:
345 case MMS_OUTBOX:
346 return VND_ANDROID_DIR_MMS;
347 case MMS_ALL_ID:
348 case MMS_INBOX_ID:
349 case MMS_SENT_ID:
350 case MMS_DRAFTS_ID:
351 case MMS_OUTBOX_ID:
352 return VND_ANDROID_MMS;
353 case MMS_PART_ID: {
354 Cursor cursor = mOpenHelper.getReadableDatabase().query(
355 TABLE_PART, new String[] { Part.CONTENT_TYPE },
356 Part._ID + " = ?", new String[] { uri.getLastPathSegment() },
357 null, null, null);
358 if (cursor != null) {
359 try {
360 if ((cursor.getCount() == 1) && cursor.moveToFirst()) {
361 return cursor.getString(0);
362 } else {
363 Log.e(TAG, "cursor.count() != 1: " + uri);
364 }
365 } finally {
366 cursor.close();
367 }
368 } else {
369 Log.e(TAG, "cursor == null: " + uri);
370 }
371 return "*/*";
372 }
373 case MMS_ALL_PART:
374 case MMS_MSG_PART:
375 case MMS_MSG_ADDR:
376 default:
377 return "*/*";
378 }
379 }
380
kaiyiz81ee3bc2015-02-06 13:43:48 +0800381 private byte[] getPduDataFromFile(String pduPath) {
382 FileInputStream fileInputStream = null;
383 byte[] data = null;
384 try {
385 File pduFile = new File(pduPath);
386 data = new byte[(int)pduFile.length()];
387 fileInputStream = new FileInputStream(pduFile);
388 fileInputStream.read(data);
389 } catch (Exception e) {
390 Log.e(TAG, "read file exception :", e);
391 } finally {
392 try {
393 if (fileInputStream != null) {
394 fileInputStream.close();
395 }
396 } catch (Exception e) {
397 Log.e(TAG, "close file stream exception :", e);
398 }
399 }
400 return data;
401 }
402
403 private Uri restorePduFile(Uri uri, String pduPath) {
404 Uri msgUri = null;
405 if (uri == null || TextUtils.isEmpty(pduPath)) {
406 return null;
407 }
408
409 try {
410 byte[] pduData = getPduDataFromFile(pduPath);
411 PduPersister pduPersister = PduPersister.getPduPersister(getContext());
412 if (pduData != null && pduData.length > 0) {
413 if (Mms.Sent.CONTENT_URI.equals(uri)
414 || Mms.Inbox.CONTENT_URI.equals(uri)) {
415 GenericPdu pdu = new PduParser(pduData, true).parse();
416 msgUri = pduPersister.persist(
417 pdu, uri, true, false, null);
418 } else {
419 Log.e(TAG,"Unsupported uri :" + uri);
420 }
421 }
422 } catch (MmsException e) {
423 Log.e(TAG, "MmsException: ", e);
424 }
425 return msgUri;
426 }
427
428 private String getPduPath(String dir, ContentValues values) {
429 if (dir != null && values != null && values.containsKey(COLUMN_PDU_PATH)) {
430 String path = values.getAsString(COLUMN_PDU_PATH);
431 if (!TextUtils.isEmpty(path)) {
432 return dir + "/" + path;
433 }
434 }
435 return null;
436 }
437
438 private int restoreMms(Uri uri, ContentValues values, String dir) {
439 int count = 0;
440 Uri msgUri = restorePduFile(uri, getPduPath(dir, values));
441 if (msgUri != null) {
442 String selection = Mms._ID + "=" + msgUri.getLastPathSegment();
443 values.remove(COLUMN_PDU_PATH);
444 ContentValues finalValues = new ContentValues(values);
445 // now only support bulkInsert pdu table.
446 SQLiteDatabase db = mOpenHelper.getReadableDatabase();
447 count = db.update(TABLE_PDU, finalValues, selection, null);
448 }
449 return count;
450 }
451
452 @Override
453 public int bulkInsert(Uri uri, ContentValues[] values) {
454 String dir = uri.getQueryParameter("restore_dir");
455 if (TextUtils.isEmpty(dir)) {
456 return super.bulkInsert(uri, values);
457 }
458
459 Uri insertUri = null;
460 int match = sURLMatcher.match(uri);
461 switch (match) {
462 case MMS_INBOX:
463 insertUri = Mms.Inbox.CONTENT_URI;
464 break;
465 case MMS_SENT:
466 insertUri = Mms.Sent.CONTENT_URI;
467 break;
468 default:
469 return 0;
470 }
471
472 long token = Binder.clearCallingIdentity();
473 int count = 0;
474 SQLiteDatabase db = mOpenHelper.getReadableDatabase();
475 db.beginTransaction();
476 try {
477 for (ContentValues value : values) {
478 count += restoreMms(insertUri, value, dir);
479 }
480
481 Log.d(TAG, "bulkInsert request count: " + values.length
482 + " successfully count : " + count);
483 if (count == values.length) {
484 db.setTransactionSuccessful();
485 }
486 return count;
487 } finally {
488 db.endTransaction();
489 Binder.restoreCallingIdentity(token);
490 }
491 }
492
493
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800494 @Override
495 public Uri insert(Uri uri, ContentValues values) {
Tom Taylor438403e2013-02-21 16:56:01 -0800496 // Don't let anyone insert anything with the _data column
497 if (values != null && values.containsKey(Part._DATA)) {
498 return null;
499 }
Ye Wene07acb92014-11-19 12:06:05 -0800500 final int callerUid = Binder.getCallingUid();
Ye Wen72f13552015-03-10 14:17:13 -0700501 final String callerPkg = getCallingPackage();
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800502 int msgBox = Mms.MESSAGE_BOX_ALL;
503 boolean notify = true;
504
505 int match = sURLMatcher.match(uri);
506 if (LOCAL_LOGV) {
507 Log.v(TAG, "Insert uri=" + uri + ", match=" + match);
508 }
509
510 String table = TABLE_PDU;
511 switch (match) {
512 case MMS_ALL:
513 Object msgBoxObj = values.getAsInteger(Mms.MESSAGE_BOX);
514 if (msgBoxObj != null) {
515 msgBox = (Integer) msgBoxObj;
516 }
517 else {
518 // default to inbox
519 msgBox = Mms.MESSAGE_BOX_INBOX;
520 }
521 break;
522 case MMS_INBOX:
523 msgBox = Mms.MESSAGE_BOX_INBOX;
524 break;
525 case MMS_SENT:
526 msgBox = Mms.MESSAGE_BOX_SENT;
527 break;
528 case MMS_DRAFTS:
529 msgBox = Mms.MESSAGE_BOX_DRAFTS;
530 break;
531 case MMS_OUTBOX:
532 msgBox = Mms.MESSAGE_BOX_OUTBOX;
533 break;
534 case MMS_MSG_PART:
535 notify = false;
536 table = TABLE_PART;
537 break;
538 case MMS_MSG_ADDR:
539 notify = false;
540 table = TABLE_ADDR;
541 break;
542 case MMS_SENDING_RATE:
543 notify = false;
544 table = TABLE_RATE;
545 break;
546 case MMS_DRM_STORAGE:
547 notify = false;
548 table = TABLE_DRM;
549 break;
550 default:
Wei Huang2914a7a2009-09-23 00:45:36 -0700551 Log.e(TAG, "insert: invalid request: " + uri);
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800552 return null;
553 }
554
555 SQLiteDatabase db = mOpenHelper.getWritableDatabase();
556 ContentValues finalValues;
557 Uri res = Mms.CONTENT_URI;
558 long rowId;
559
560 if (table.equals(TABLE_PDU)) {
561 boolean addDate = !values.containsKey(Mms.DATE);
562 boolean addMsgBox = !values.containsKey(Mms.MESSAGE_BOX);
563
564 // Filter keys we don't support yet.
565 filterUnsupportedKeys(values);
566
567 // TODO: Should initialValues be validated, e.g. if it
568 // missed some significant keys?
569 finalValues = new ContentValues(values);
570
571 long timeInMillis = System.currentTimeMillis();
572
573 if (addDate) {
574 finalValues.put(Mms.DATE, timeInMillis / 1000L);
575 }
576
577 if (addMsgBox && (msgBox != Mms.MESSAGE_BOX_ALL)) {
578 finalValues.put(Mms.MESSAGE_BOX, msgBox);
579 }
580
581 if (msgBox != Mms.MESSAGE_BOX_INBOX) {
582 // Mark all non-inbox messages read.
583 finalValues.put(Mms.READ, 1);
584 }
585
Yusuf T. Mobile21c25bc2009-06-16 13:40:38 -0700586 // thread_id
587 Long threadId = values.getAsLong(Mms.THREAD_ID);
588 String address = values.getAsString(CanonicalAddressesColumns.ADDRESS);
589
Tom Taylor59269962012-05-09 14:42:35 -0700590 if (((threadId == null) || (threadId == 0)) && (!TextUtils.isEmpty(address))) {
Yusuf T. Mobile21c25bc2009-06-16 13:40:38 -0700591 finalValues.put(Mms.THREAD_ID, Threads.getOrCreateThreadId(getContext(), address));
592 }
593
Ye Wene07acb92014-11-19 12:06:05 -0800594 if (ProviderUtil.shouldSetCreator(finalValues, callerUid)) {
595 // Only SYSTEM or PHONE can set CREATOR
596 // If caller is not SYSTEM or PHONE, or SYSTEM or PHONE does not set CREATOR
597 // set CREATOR using the truth on caller.
598 // Note: Inferring package name from UID may include unrelated package names
Ye Wen72f13552015-03-10 14:17:13 -0700599 finalValues.put(Telephony.Mms.CREATOR, callerPkg);
Ye Wene07acb92014-11-19 12:06:05 -0800600 }
601
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800602 if ((rowId = db.insert(table, null, finalValues)) <= 0) {
Ye Wene07acb92014-11-19 12:06:05 -0800603 Log.e(TAG, "MmsProvider.insert: failed!");
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800604 return null;
605 }
606
607 res = Uri.parse(res + "/" + rowId);
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800608 } else if (table.equals(TABLE_ADDR)) {
609 finalValues = new ContentValues(values);
610 finalValues.put(Addr.MSG_ID, uri.getPathSegments().get(0));
611
612 if ((rowId = db.insert(table, null, finalValues)) <= 0) {
Ye Wene07acb92014-11-19 12:06:05 -0800613 Log.e(TAG, "Failed to insert address");
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800614 return null;
615 }
616
617 res = Uri.parse(res + "/addr/" + rowId);
618 } else if (table.equals(TABLE_PART)) {
619 finalValues = new ContentValues(values);
620
621 if (match == MMS_MSG_PART) {
622 finalValues.put(Part.MSG_ID, uri.getPathSegments().get(0));
623 }
624
Mark Wagnerf0a9e902009-06-19 16:00:13 -0700625 String contentType = values.getAsString("ct");
Mark Wagner8e5ee782010-01-04 17:39:06 -0800626
Mark Wagnerf0a9e902009-06-19 16:00:13 -0700627 // text/plain and app application/smil store their "data" inline in the
628 // table so there's no need to create the file
Tom Taylorc2db47d2012-03-27 15:15:39 -0700629 boolean plainText = false;
630 boolean smilText = false;
631 if ("text/plain".equals(contentType)) {
632 plainText = true;
633 } else if ("application/smil".equals(contentType)) {
634 smilText = true;
635 }
Mark Wagner8e5ee782010-01-04 17:39:06 -0800636 if (!plainText && !smilText) {
Tom Taylorc2db47d2012-03-27 15:15:39 -0700637 // Use the filename if possible, otherwise use the current time as the name.
638 String contentLocation = values.getAsString("cl");
639 if (!TextUtils.isEmpty(contentLocation)) {
640 File f = new File(contentLocation);
641 contentLocation = "_" + f.getName();
642 } else {
643 contentLocation = "";
644 }
645
Mark Wagnerf0a9e902009-06-19 16:00:13 -0700646 // Generate the '_data' field of the part with default
647 // permission settings.
Ye Weneaa93e62015-01-06 13:08:53 -0800648 String path = getContext().getDir(PARTS_DIR_NAME, 0).getPath()
Tom Taylorc2db47d2012-03-27 15:15:39 -0700649 + "/PART_" + System.currentTimeMillis() + contentLocation;
650
651 if (DownloadDrmHelper.isDrmConvertNeeded(contentType)) {
652 // Adds the .fl extension to the filename if contentType is
653 // "application/vnd.oma.drm.message"
654 path = DownloadDrmHelper.modifyDrmFwLockFileExtension(path);
655 }
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800656
Mark Wagnerf0a9e902009-06-19 16:00:13 -0700657 finalValues.put(Part._DATA, path);
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800658
Mark Wagnerf0a9e902009-06-19 16:00:13 -0700659 File partFile = new File(path);
660 if (!partFile.exists()) {
661 try {
662 if (!partFile.createNewFile()) {
663 throw new IllegalStateException(
664 "Unable to create new partFile: " + path);
665 }
Tom Taylorc2db47d2012-03-27 15:15:39 -0700666 // Give everyone rw permission until we encrypt the file
667 // (in PduPersister.persistData). Once the file is encrypted, the
668 // permissions will be set to 0644.
669 int result = FileUtils.setPermissions(path, 0666, -1, -1);
670 if (LOCAL_LOGV) {
671 Log.d(TAG, "MmsProvider.insert setPermissions result: " + result);
672 }
Mark Wagnerf0a9e902009-06-19 16:00:13 -0700673 } catch (IOException e) {
674 Log.e(TAG, "createNewFile", e);
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800675 throw new IllegalStateException(
676 "Unable to create new partFile: " + path);
677 }
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800678 }
679 }
680
681 if ((rowId = db.insert(table, null, finalValues)) <= 0) {
Ye Wene07acb92014-11-19 12:06:05 -0800682 Log.e(TAG, "MmsProvider.insert: failed!");
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800683 return null;
684 }
685
686 res = Uri.parse(res + "/part/" + rowId);
Mark Wagner8e5ee782010-01-04 17:39:06 -0800687
688 // Don't use a trigger for updating the words table because of a bug
689 // in FTS3. The bug is such that the call to get the last inserted
690 // row is incorrect.
691 if (plainText) {
692 // Update the words table with a corresponding row. The words table
693 // allows us to search for words quickly, without scanning the whole
694 // table;
695 ContentValues cv = new ContentValues();
696
697 // we're using the row id of the part table row but we're also using ids
698 // from the sms table so this divides the space into two large chunks.
699 // The row ids from the part table start at 2 << 32.
700 cv.put(Telephony.MmsSms.WordsTable.ID, (2 << 32) + rowId);
701 cv.put(Telephony.MmsSms.WordsTable.INDEXED_TEXT, values.getAsString("text"));
702 cv.put(Telephony.MmsSms.WordsTable.SOURCE_ROW_ID, rowId);
703 cv.put(Telephony.MmsSms.WordsTable.TABLE_ID, 2);
704 db.insert(TABLE_WORDS, Telephony.MmsSms.WordsTable.INDEXED_TEXT, cv);
705 }
706
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800707 } else if (table.equals(TABLE_RATE)) {
708 long now = values.getAsLong(Rate.SENT_TIME);
709 long oneHourAgo = now - 1000 * 60 * 60;
710 // Delete all unused rows (time earlier than one hour ago).
711 db.delete(table, Rate.SENT_TIME + "<=" + oneHourAgo, null);
712 db.insert(table, null, values);
713 } else if (table.equals(TABLE_DRM)) {
Ye Weneaa93e62015-01-06 13:08:53 -0800714 String path = getContext().getDir(PARTS_DIR_NAME, 0).getPath()
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800715 + "/PART_" + System.currentTimeMillis();
716 finalValues = new ContentValues(1);
717 finalValues.put("_data", path);
718
719 File partFile = new File(path);
720 if (!partFile.exists()) {
721 try {
722 if (!partFile.createNewFile()) {
723 throw new IllegalStateException(
724 "Unable to create new file: " + path);
725 }
726 } catch (IOException e) {
727 Log.e(TAG, "createNewFile", e);
728 throw new IllegalStateException(
729 "Unable to create new file: " + path);
730 }
731 }
732
733 if ((rowId = db.insert(table, null, finalValues)) <= 0) {
Ye Wene07acb92014-11-19 12:06:05 -0800734 Log.e(TAG, "MmsProvider.insert: failed!");
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800735 return null;
736 }
737 res = Uri.parse(res + "/drm/" + rowId);
738 } else {
739 throw new AssertionError("Unknown table type: " + table);
740 }
741
742 if (notify) {
743 notifyChange();
744 }
745 return res;
746 }
747
748 private int getMessageBoxByMatch(int match) {
749 switch (match) {
750 case MMS_INBOX_ID:
751 case MMS_INBOX:
752 return Mms.MESSAGE_BOX_INBOX;
753 case MMS_SENT_ID:
754 case MMS_SENT:
755 return Mms.MESSAGE_BOX_SENT;
756 case MMS_DRAFTS_ID:
757 case MMS_DRAFTS:
758 return Mms.MESSAGE_BOX_DRAFTS;
759 case MMS_OUTBOX_ID:
760 case MMS_OUTBOX:
761 return Mms.MESSAGE_BOX_OUTBOX;
762 default:
763 throw new IllegalArgumentException("bad Arg: " + match);
764 }
765 }
766
767 @Override
768 public int delete(Uri uri, String selection,
769 String[] selectionArgs) {
770 int match = sURLMatcher.match(uri);
771 if (LOCAL_LOGV) {
772 Log.v(TAG, "Delete uri=" + uri + ", match=" + match);
773 }
774
775 String table, extraSelection = null;
776 boolean notify = false;
777
778 switch (match) {
779 case MMS_ALL_ID:
780 case MMS_INBOX_ID:
781 case MMS_SENT_ID:
782 case MMS_DRAFTS_ID:
783 case MMS_OUTBOX_ID:
784 notify = true;
785 table = TABLE_PDU;
786 extraSelection = Mms._ID + "=" + uri.getLastPathSegment();
787 break;
788 case MMS_ALL:
789 case MMS_INBOX:
790 case MMS_SENT:
791 case MMS_DRAFTS:
792 case MMS_OUTBOX:
793 notify = true;
794 table = TABLE_PDU;
795 if (match != MMS_ALL) {
796 int msgBox = getMessageBoxByMatch(match);
797 extraSelection = Mms.MESSAGE_BOX + "=" + msgBox;
798 }
799 break;
800 case MMS_ALL_PART:
801 table = TABLE_PART;
802 break;
803 case MMS_MSG_PART:
804 table = TABLE_PART;
805 extraSelection = Part.MSG_ID + "=" + uri.getPathSegments().get(0);
806 break;
807 case MMS_PART_ID:
808 table = TABLE_PART;
809 extraSelection = Part._ID + "=" + uri.getPathSegments().get(1);
810 break;
811 case MMS_MSG_ADDR:
812 table = TABLE_ADDR;
813 extraSelection = Addr.MSG_ID + "=" + uri.getPathSegments().get(0);
814 break;
815 case MMS_DRM_STORAGE:
816 table = TABLE_DRM;
817 break;
818 default:
819 Log.w(TAG, "No match for URI '" + uri + "'");
820 return 0;
821 }
822
823 String finalSelection = concatSelections(selection, extraSelection);
824 SQLiteDatabase db = mOpenHelper.getWritableDatabase();
825 int deletedRows = 0;
826
827 if (TABLE_PDU.equals(table)) {
828 deletedRows = deleteMessages(getContext(), db, finalSelection,
829 selectionArgs, uri);
830 } else if (TABLE_PART.equals(table)) {
831 deletedRows = deleteParts(db, finalSelection, selectionArgs);
kaiyizcd21c4f2015-01-30 11:22:36 +0800832 cleanUpWords(db);
833 updateHasAttachment(db);
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800834 } else if (TABLE_DRM.equals(table)) {
835 deletedRows = deleteTempDrmData(db, finalSelection, selectionArgs);
836 } else {
837 deletedRows = db.delete(table, finalSelection, selectionArgs);
838 }
839
840 if ((deletedRows > 0) && notify) {
841 notifyChange();
842 }
843 return deletedRows;
844 }
845
846 static int deleteMessages(Context context, SQLiteDatabase db,
847 String selection, String[] selectionArgs, Uri uri) {
kaiyizcd21c4f2015-01-30 11:22:36 +0800848 Cursor cursor = db.query(TABLE_PDU, new String[] { Mms._ID, Mms.THREAD_ID },
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800849 selection, selectionArgs, null, null, null);
850 if (cursor == null) {
851 return 0;
852 }
853
kaiyizcd21c4f2015-01-30 11:22:36 +0800854 HashSet<Long> threadIds = new HashSet<Long>();
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800855 try {
856 if (cursor.getCount() == 0) {
857 return 0;
858 }
859
860 while (cursor.moveToNext()) {
861 deleteParts(db, Part.MSG_ID + " = ?",
862 new String[] { String.valueOf(cursor.getLong(0)) });
kaiyizcd21c4f2015-01-30 11:22:36 +0800863 threadIds.add(cursor.getLong(1));
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800864 }
kaiyizcd21c4f2015-01-30 11:22:36 +0800865 cleanUpWords(db);
866 updateHasAttachment(db);
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800867 } finally {
868 cursor.close();
869 }
870
871 int count = db.delete(TABLE_PDU, selection, selectionArgs);
kaiyizcd21c4f2015-01-30 11:22:36 +0800872 for (long thread : threadIds) {
873 MmsSmsDatabaseHelper.updateThread(db, thread);
874 }
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800875 if (count > 0) {
876 Intent intent = new Intent(Mms.Intents.CONTENT_CHANGED_ACTION);
877 intent.putExtra(Mms.Intents.DELETED_CONTENTS, uri);
878 if (LOCAL_LOGV) {
879 Log.v(TAG, "Broadcasting intent: " + intent);
880 }
881 context.sendBroadcast(intent);
882 }
883 return count;
884 }
885
kaiyizcd21c4f2015-01-30 11:22:36 +0800886 private static void cleanUpWords(SQLiteDatabase db) {
887 db.execSQL("DELETE FROM words WHERE source_id not in (select _id from part) AND "
888 + "table_to_use = 2");
889 }
890
891 private static void updateHasAttachment(SQLiteDatabase db) {
892 db.execSQL("UPDATE threads SET has_attachment = CASE "
893 + "(SELECT COUNT(*) FROM part JOIN pdu WHERE part.mid = pdu._id AND "
894 + "pdu.thread_id = threads._id AND part.ct != 'text/plain' "
895 + "AND part.ct != 'application/smil') WHEN 0 THEN 0 ELSE 1 END");
896 }
897
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800898 private static int deleteParts(SQLiteDatabase db, String selection,
899 String[] selectionArgs) {
900 return deleteDataRows(db, TABLE_PART, selection, selectionArgs);
901 }
902
903 private static int deleteTempDrmData(SQLiteDatabase db, String selection,
904 String[] selectionArgs) {
905 return deleteDataRows(db, TABLE_DRM, selection, selectionArgs);
906 }
907
908 private static int deleteDataRows(SQLiteDatabase db, String table,
909 String selection, String[] selectionArgs) {
910 Cursor cursor = db.query(table, new String[] { "_data" },
911 selection, selectionArgs, null, null, null);
912 if (cursor == null) {
913 // FIXME: This might be an error, ignore it may cause
914 // unpredictable result.
915 return 0;
916 }
917
918 try {
919 if (cursor.getCount() == 0) {
920 return 0;
921 }
922
923 while (cursor.moveToNext()) {
924 try {
925 // Delete the associated files saved on file-system.
Mark Wagnerf0a9e902009-06-19 16:00:13 -0700926 String path = cursor.getString(0);
927 if (path != null) {
928 new File(path).delete();
929 }
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800930 } catch (Throwable ex) {
931 Log.e(TAG, ex.getMessage(), ex);
932 }
933 }
934 } finally {
935 cursor.close();
936 }
937
938 return db.delete(table, selection, selectionArgs);
939 }
940
941 @Override
942 public int update(Uri uri, ContentValues values,
943 String selection, String[] selectionArgs) {
Tom Taylor438403e2013-02-21 16:56:01 -0800944 // Don't let anyone update the _data column
945 if (values != null && values.containsKey(Part._DATA)) {
946 return 0;
947 }
Ye Wene07acb92014-11-19 12:06:05 -0800948 final int callerUid = Binder.getCallingUid();
Ye Wen72f13552015-03-10 14:17:13 -0700949 final String callerPkg = getCallingPackage();
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800950 int match = sURLMatcher.match(uri);
951 if (LOCAL_LOGV) {
952 Log.v(TAG, "Update uri=" + uri + ", match=" + match);
953 }
954
955 boolean notify = false;
956 String msgId = null;
957 String table;
958
959 switch (match) {
960 case MMS_ALL_ID:
961 case MMS_INBOX_ID:
962 case MMS_SENT_ID:
963 case MMS_DRAFTS_ID:
964 case MMS_OUTBOX_ID:
965 msgId = uri.getLastPathSegment();
966 // fall-through
967 case MMS_ALL:
968 case MMS_INBOX:
969 case MMS_SENT:
970 case MMS_DRAFTS:
971 case MMS_OUTBOX:
972 notify = true;
973 table = TABLE_PDU;
974 break;
Tom Taylorc2db47d2012-03-27 15:15:39 -0700975
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800976 case MMS_MSG_PART:
977 case MMS_PART_ID:
978 table = TABLE_PART;
979 break;
Tom Taylorc2db47d2012-03-27 15:15:39 -0700980
981 case MMS_PART_RESET_FILE_PERMISSION:
Ye Weneaa93e62015-01-06 13:08:53 -0800982 String path = getContext().getDir(PARTS_DIR_NAME, 0).getPath() + '/' +
Tom Taylorc2db47d2012-03-27 15:15:39 -0700983 uri.getPathSegments().get(1);
984 // Reset the file permission back to read for everyone but me.
985 int result = FileUtils.setPermissions(path, 0644, -1, -1);
986 if (LOCAL_LOGV) {
987 Log.d(TAG, "MmsProvider.update setPermissions result: " + result +
988 " for path: " + path);
989 }
990 return 0;
991
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800992 default:
993 Log.w(TAG, "Update operation for '" + uri + "' not implemented.");
994 return 0;
995 }
996
997 String extraSelection = null;
998 ContentValues finalValues;
999 if (table.equals(TABLE_PDU)) {
1000 // Filter keys that we don't support yet.
1001 filterUnsupportedKeys(values);
Ye Wene07acb92014-11-19 12:06:05 -08001002 if (ProviderUtil.shouldRemoveCreator(values, callerUid)) {
1003 // CREATOR should not be changed by non-SYSTEM/PHONE apps
Ye Wen72f13552015-03-10 14:17:13 -07001004 Log.w(TAG, callerPkg + " tries to update CREATOR");
Ye Wene07acb92014-11-19 12:06:05 -08001005 values.remove(Mms.CREATOR);
1006 }
The Android Open Source Project7236c3a2009-03-03 19:32:44 -08001007 finalValues = new ContentValues(values);
1008
1009 if (msgId != null) {
1010 extraSelection = Mms._ID + "=" + msgId;
1011 }
1012 } else if (table.equals(TABLE_PART)) {
1013 finalValues = new ContentValues(values);
1014
1015 switch (match) {
1016 case MMS_MSG_PART:
1017 extraSelection = Part.MSG_ID + "=" + uri.getPathSegments().get(0);
1018 break;
1019 case MMS_PART_ID:
1020 extraSelection = Part._ID + "=" + uri.getPathSegments().get(1);
1021 break;
1022 default:
1023 break;
1024 }
1025 } else {
1026 return 0;
1027 }
1028
1029 String finalSelection = concatSelections(selection, extraSelection);
1030 SQLiteDatabase db = mOpenHelper.getWritableDatabase();
1031 int count = db.update(table, finalValues, finalSelection, selectionArgs);
1032 if (notify && (count > 0)) {
1033 notifyChange();
1034 }
1035 return count;
1036 }
1037
1038 @Override
Wei Huang2914a7a2009-09-23 00:45:36 -07001039 public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
Wei Huang2914a7a2009-09-23 00:45:36 -07001040 int match = sURLMatcher.match(uri);
1041
1042 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Tom Taylor8168ff82013-02-19 14:30:23 -08001043 Log.d(TAG, "openFile: uri=" + uri + ", mode=" + mode + ", match=" + match);
Wei Huang2914a7a2009-09-23 00:45:36 -07001044 }
1045
Tom Taylor8168ff82013-02-19 14:30:23 -08001046 if (match != MMS_PART_ID) {
1047 return null;
Wei Huang2914a7a2009-09-23 00:45:36 -07001048 }
1049
Tom Taylor8168ff82013-02-19 14:30:23 -08001050 // Verify that the _data path points to mms data
1051 Cursor c = query(uri, new String[]{"_data"}, null, null, null);
1052 int count = (c != null) ? c.getCount() : 0;
1053 if (count != 1) {
1054 // If there is not exactly one result, throw an appropriate
1055 // exception.
1056 if (c != null) {
1057 c.close();
1058 }
1059 if (count == 0) {
1060 throw new FileNotFoundException("No entry for " + uri);
1061 }
1062 throw new FileNotFoundException("Multiple items at " + uri);
1063 }
1064
1065 c.moveToFirst();
1066 int i = c.getColumnIndex("_data");
1067 String path = (i >= 0 ? c.getString(i) : null);
1068 c.close();
1069
1070 if (path == null) {
1071 return null;
1072 }
1073 try {
1074 File filePath = new File(path);
1075 if (!filePath.getCanonicalPath()
Amith Yamasanida40d6a2015-04-14 13:37:12 -07001076 .startsWith(getContext().getDir(PARTS_DIR_NAME, 0).getCanonicalPath())) {
Ye Weneaa93e62015-01-06 13:08:53 -08001077 Log.e(TAG, "openFile: path "
1078 + filePath.getCanonicalPath()
1079 + " does not start with "
Amith Yamasanida40d6a2015-04-14 13:37:12 -07001080 + getContext().getDir(PARTS_DIR_NAME, 0).getCanonicalPath());
Ye Weneaa93e62015-01-06 13:08:53 -08001081 // Don't care return value
1082 filePath.delete();
Tom Taylor8168ff82013-02-19 14:30:23 -08001083 return null;
1084 }
1085 } catch (IOException e) {
Ye Weneaa93e62015-01-06 13:08:53 -08001086 Log.e(TAG, "openFile: create path failed " + e, e);
Tom Taylor8168ff82013-02-19 14:30:23 -08001087 return null;
1088 }
1089
1090 return openFileHelper(uri, mode);
The Android Open Source Project7236c3a2009-03-03 19:32:44 -08001091 }
1092
1093 private void filterUnsupportedKeys(ContentValues values) {
1094 // Some columns are unsupported. They should therefore
1095 // neither be inserted nor updated. Filter them out.
1096 values.remove(Mms.DELIVERY_TIME_TOKEN);
1097 values.remove(Mms.SENDER_VISIBILITY);
1098 values.remove(Mms.REPLY_CHARGING);
1099 values.remove(Mms.REPLY_CHARGING_DEADLINE_TOKEN);
1100 values.remove(Mms.REPLY_CHARGING_DEADLINE);
1101 values.remove(Mms.REPLY_CHARGING_ID);
1102 values.remove(Mms.REPLY_CHARGING_SIZE);
1103 values.remove(Mms.PREVIOUSLY_SENT_BY);
1104 values.remove(Mms.PREVIOUSLY_SENT_DATE);
1105 values.remove(Mms.STORE);
1106 values.remove(Mms.MM_STATE);
1107 values.remove(Mms.MM_FLAGS_TOKEN);
1108 values.remove(Mms.MM_FLAGS);
1109 values.remove(Mms.STORE_STATUS);
1110 values.remove(Mms.STORE_STATUS_TEXT);
1111 values.remove(Mms.STORED);
1112 values.remove(Mms.TOTALS);
1113 values.remove(Mms.MBOX_TOTALS);
1114 values.remove(Mms.MBOX_TOTALS_TOKEN);
1115 values.remove(Mms.QUOTAS);
1116 values.remove(Mms.MBOX_QUOTAS);
1117 values.remove(Mms.MBOX_QUOTAS_TOKEN);
1118 values.remove(Mms.MESSAGE_COUNT);
1119 values.remove(Mms.START);
1120 values.remove(Mms.DISTRIBUTION_INDICATOR);
1121 values.remove(Mms.ELEMENT_DESCRIPTOR);
1122 values.remove(Mms.LIMIT);
1123 values.remove(Mms.RECOMMENDED_RETRIEVAL_MODE);
1124 values.remove(Mms.RECOMMENDED_RETRIEVAL_MODE_TEXT);
1125 values.remove(Mms.STATUS_TEXT);
1126 values.remove(Mms.APPLIC_ID);
1127 values.remove(Mms.REPLY_APPLIC_ID);
1128 values.remove(Mms.AUX_APPLIC_ID);
1129 values.remove(Mms.DRM_CONTENT);
1130 values.remove(Mms.ADAPTATION_ALLOWED);
1131 values.remove(Mms.REPLACE_ID);
1132 values.remove(Mms.CANCEL_ID);
1133 values.remove(Mms.CANCEL_STATUS);
1134
1135 // Keys shouldn't be inserted or updated.
1136 values.remove(Mms._ID);
1137 }
1138
1139 private void notifyChange() {
1140 getContext().getContentResolver().notifyChange(
Amith Yamasani43f9fb22014-09-10 15:56:47 -07001141 MmsSms.CONTENT_URI, null, true, UserHandle.USER_ALL);
The Android Open Source Project7236c3a2009-03-03 19:32:44 -08001142 }
1143
1144 private final static String TAG = "MmsProvider";
1145 private final static String VND_ANDROID_MMS = "vnd.android/mms";
1146 private final static String VND_ANDROID_DIR_MMS = "vnd.android-dir/mms";
1147 private final static boolean DEBUG = false;
Joe Onoratodc946792011-04-07 18:41:15 -07001148 private final static boolean LOCAL_LOGV = false;
The Android Open Source Project7236c3a2009-03-03 19:32:44 -08001149
1150 private static final int MMS_ALL = 0;
1151 private static final int MMS_ALL_ID = 1;
1152 private static final int MMS_INBOX = 2;
1153 private static final int MMS_INBOX_ID = 3;
1154 private static final int MMS_SENT = 4;
1155 private static final int MMS_SENT_ID = 5;
1156 private static final int MMS_DRAFTS = 6;
1157 private static final int MMS_DRAFTS_ID = 7;
1158 private static final int MMS_OUTBOX = 8;
1159 private static final int MMS_OUTBOX_ID = 9;
1160 private static final int MMS_ALL_PART = 10;
1161 private static final int MMS_MSG_PART = 11;
1162 private static final int MMS_PART_ID = 12;
1163 private static final int MMS_MSG_ADDR = 13;
1164 private static final int MMS_SENDING_RATE = 14;
Tom Taylor6c0ef242009-06-01 12:05:00 -07001165 private static final int MMS_REPORT_STATUS = 15;
1166 private static final int MMS_REPORT_REQUEST = 16;
The Android Open Source Project7236c3a2009-03-03 19:32:44 -08001167 private static final int MMS_DRM_STORAGE = 17;
1168 private static final int MMS_DRM_STORAGE_ID = 18;
Tom Taylor6c0ef242009-06-01 12:05:00 -07001169 private static final int MMS_THREADS = 19;
Tom Taylorc2db47d2012-03-27 15:15:39 -07001170 private static final int MMS_PART_RESET_FILE_PERMISSION = 20;
kaiyiz81ee3bc2015-02-06 13:43:48 +08001171 private static final int MMS_GET_PDU = 21;
The Android Open Source Project7236c3a2009-03-03 19:32:44 -08001172
1173 private static final UriMatcher
1174 sURLMatcher = new UriMatcher(UriMatcher.NO_MATCH);
1175
1176 static {
1177 sURLMatcher.addURI("mms", null, MMS_ALL);
1178 sURLMatcher.addURI("mms", "#", MMS_ALL_ID);
1179 sURLMatcher.addURI("mms", "inbox", MMS_INBOX);
1180 sURLMatcher.addURI("mms", "inbox/#", MMS_INBOX_ID);
1181 sURLMatcher.addURI("mms", "sent", MMS_SENT);
1182 sURLMatcher.addURI("mms", "sent/#", MMS_SENT_ID);
1183 sURLMatcher.addURI("mms", "drafts", MMS_DRAFTS);
1184 sURLMatcher.addURI("mms", "drafts/#", MMS_DRAFTS_ID);
1185 sURLMatcher.addURI("mms", "outbox", MMS_OUTBOX);
1186 sURLMatcher.addURI("mms", "outbox/#", MMS_OUTBOX_ID);
1187 sURLMatcher.addURI("mms", "part", MMS_ALL_PART);
1188 sURLMatcher.addURI("mms", "#/part", MMS_MSG_PART);
1189 sURLMatcher.addURI("mms", "part/#", MMS_PART_ID);
1190 sURLMatcher.addURI("mms", "#/addr", MMS_MSG_ADDR);
1191 sURLMatcher.addURI("mms", "rate", MMS_SENDING_RATE);
1192 sURLMatcher.addURI("mms", "report-status/#", MMS_REPORT_STATUS);
1193 sURLMatcher.addURI("mms", "report-request/#", MMS_REPORT_REQUEST);
1194 sURLMatcher.addURI("mms", "drm", MMS_DRM_STORAGE);
1195 sURLMatcher.addURI("mms", "drm/#", MMS_DRM_STORAGE_ID);
Tom Taylor6c0ef242009-06-01 12:05:00 -07001196 sURLMatcher.addURI("mms", "threads", MMS_THREADS);
Tom Taylorc2db47d2012-03-27 15:15:39 -07001197 sURLMatcher.addURI("mms", "resetFilePerm/*", MMS_PART_RESET_FILE_PERMISSION);
kaiyiz81ee3bc2015-02-06 13:43:48 +08001198 sURLMatcher.addURI("mms", "get-pdu", MMS_GET_PDU);
The Android Open Source Project7236c3a2009-03-03 19:32:44 -08001199 }
1200
1201 private SQLiteOpenHelper mOpenHelper;
1202
The Android Open Source Project7236c3a2009-03-03 19:32:44 -08001203 private static String concatSelections(String selection1, String selection2) {
1204 if (TextUtils.isEmpty(selection1)) {
1205 return selection2;
1206 } else if (TextUtils.isEmpty(selection2)) {
1207 return selection1;
1208 } else {
1209 return selection1 + " AND " + selection2;
1210 }
1211 }
1212}
1213