blob: 4091284570b713a41962b502f3edbf1982f52249 [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;
21import android.content.ContentValues;
22import android.content.Context;
23import android.content.Intent;
24import android.content.UriMatcher;
25import android.database.Cursor;
26import android.database.sqlite.SQLiteDatabase;
Tom Taylor3ad9da42014-01-16 13:57:11 -080027import android.database.sqlite.SQLiteException;
The Android Open Source Project7236c3a2009-03-03 19:32:44 -080028import android.database.sqlite.SQLiteOpenHelper;
29import android.database.sqlite.SQLiteQueryBuilder;
30import android.net.Uri;
Ye Wene07acb92014-11-19 12:06:05 -080031import android.os.Binder;
Tom Taylorc2db47d2012-03-27 15:15:39 -070032import android.os.FileUtils;
The Android Open Source Project7236c3a2009-03-03 19:32:44 -080033import android.os.ParcelFileDescriptor;
Amith Yamasani43f9fb22014-09-10 15:56:47 -070034import android.os.UserHandle;
The Android Open Source Project7236c3a2009-03-03 19:32:44 -080035import android.provider.BaseColumns;
Mark Wagner8e5ee782010-01-04 17:39:06 -080036import android.provider.Telephony;
Yusuf T. Mobile21c25bc2009-06-16 13:40:38 -070037import android.provider.Telephony.CanonicalAddressesColumns;
The Android Open Source Project7236c3a2009-03-03 19:32:44 -080038import android.provider.Telephony.Mms;
The Android Open Source Project7236c3a2009-03-03 19:32:44 -080039import android.provider.Telephony.Mms.Addr;
40import android.provider.Telephony.Mms.Part;
41import android.provider.Telephony.Mms.Rate;
Ye Wene07acb92014-11-19 12:06:05 -080042import android.provider.Telephony.MmsSms;
43import android.provider.Telephony.Threads;
The Android Open Source Project7236c3a2009-03-03 19:32:44 -080044import android.text.TextUtils;
The Android Open Source Project7236c3a2009-03-03 19:32:44 -080045import android.util.Log;
46
Tom Taylorb1bae652010-03-08 16:33:42 -080047import com.google.android.mms.pdu.PduHeaders;
Tom Taylorc2db47d2012-03-27 15:15:39 -070048import com.google.android.mms.util.DownloadDrmHelper;
Tom Taylorc71e7702010-01-28 09:23:12 -080049
The Android Open Source Project7236c3a2009-03-03 19:32:44 -080050import java.io.File;
51import java.io.FileNotFoundException;
52import java.io.IOException;
kaiyizcd21c4f2015-01-30 11:22:36 +080053import java.util.HashSet;
Amith Yamasani43f9fb22014-09-10 15:56:47 -070054
The Android Open Source Project7236c3a2009-03-03 19:32:44 -080055/**
56 * The class to provide base facility to access MMS related content,
57 * which is stored in a SQLite database and in the file system.
58 */
59public class MmsProvider extends ContentProvider {
60 static final String TABLE_PDU = "pdu";
61 static final String TABLE_ADDR = "addr";
62 static final String TABLE_PART = "part";
63 static final String TABLE_RATE = "rate";
64 static final String TABLE_DRM = "drm";
Mark Wagner8e5ee782010-01-04 17:39:06 -080065 static final String TABLE_WORDS = "words";
Ye Wen72f13552015-03-10 14:17:13 -070066 static final String VIEW_PDU_RESTRICTED = "pdu_restricted";
The Android Open Source Project7236c3a2009-03-03 19:32:44 -080067
Ye Weneaa93e62015-01-06 13:08:53 -080068 // The name of parts directory. The full dir is "app_parts".
69 private static final String PARTS_DIR_NAME = "parts";
Tom Taylorc2db47d2012-03-27 15:15:39 -070070
The Android Open Source Project7236c3a2009-03-03 19:32:44 -080071 @Override
72 public boolean onCreate() {
Ye Wenb2ce2d32014-07-28 14:49:30 -070073 setAppOps(AppOpsManager.OP_READ_SMS, AppOpsManager.OP_WRITE_SMS);
74 mOpenHelper = MmsSmsDatabaseHelper.getInstance(getContext());
The Android Open Source Project7236c3a2009-03-03 19:32:44 -080075 return true;
76 }
77
Ye Wen72f13552015-03-10 14:17:13 -070078 /**
79 * Return the proper view of "pdu" table for the current access status.
80 *
81 * @param accessRestricted If the access is restricted
82 * @return the table/view name of the mms data
83 */
84 public static String getPduTable(boolean accessRestricted) {
85 return accessRestricted ? VIEW_PDU_RESTRICTED : TABLE_PDU;
86 }
87
The Android Open Source Project7236c3a2009-03-03 19:32:44 -080088 @Override
89 public Cursor query(Uri uri, String[] projection,
90 String selection, String[] selectionArgs, String sortOrder) {
Ye Wen72f13552015-03-10 14:17:13 -070091 // First check if a restricted view of the "pdu" table should be used based on the
92 // caller's identity. Only system, phone or the default sms app can have full access
93 // of mms data. For other apps, we present a restricted view which only contains sent
94 // or received messages, without wap pushes.
95 final boolean accessRestricted = ProviderUtil.isAccessRestricted(
96 getContext(), getCallingPackage(), Binder.getCallingUid());
97 final String pduTable = getPduTable(accessRestricted);
98
The Android Open Source Project7236c3a2009-03-03 19:32:44 -080099 SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
100
101 // Generate the body of the query.
102 int match = sURLMatcher.match(uri);
103 if (LOCAL_LOGV) {
104 Log.v(TAG, "Query uri=" + uri + ", match=" + match);
105 }
106
107 switch (match) {
108 case MMS_ALL:
Ye Wen72f13552015-03-10 14:17:13 -0700109 constructQueryForBox(qb, Mms.MESSAGE_BOX_ALL, pduTable);
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800110 break;
111 case MMS_INBOX:
Ye Wen72f13552015-03-10 14:17:13 -0700112 constructQueryForBox(qb, Mms.MESSAGE_BOX_INBOX, pduTable);
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800113 break;
114 case MMS_SENT:
Ye Wen72f13552015-03-10 14:17:13 -0700115 constructQueryForBox(qb, Mms.MESSAGE_BOX_SENT, pduTable);
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800116 break;
117 case MMS_DRAFTS:
Ye Wen72f13552015-03-10 14:17:13 -0700118 constructQueryForBox(qb, Mms.MESSAGE_BOX_DRAFTS, pduTable);
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800119 break;
120 case MMS_OUTBOX:
Ye Wen72f13552015-03-10 14:17:13 -0700121 constructQueryForBox(qb, Mms.MESSAGE_BOX_OUTBOX, pduTable);
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800122 break;
123 case MMS_ALL_ID:
Ye Wen72f13552015-03-10 14:17:13 -0700124 qb.setTables(pduTable);
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800125 qb.appendWhere(Mms._ID + "=" + uri.getPathSegments().get(0));
126 break;
127 case MMS_INBOX_ID:
128 case MMS_SENT_ID:
129 case MMS_DRAFTS_ID:
130 case MMS_OUTBOX_ID:
Ye Wen72f13552015-03-10 14:17:13 -0700131 qb.setTables(pduTable);
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800132 qb.appendWhere(Mms._ID + "=" + uri.getPathSegments().get(1));
133 qb.appendWhere(" AND " + Mms.MESSAGE_BOX + "="
134 + getMessageBoxByMatch(match));
135 break;
136 case MMS_ALL_PART:
137 qb.setTables(TABLE_PART);
138 break;
139 case MMS_MSG_PART:
140 qb.setTables(TABLE_PART);
141 qb.appendWhere(Part.MSG_ID + "=" + uri.getPathSegments().get(0));
142 break;
143 case MMS_PART_ID:
144 qb.setTables(TABLE_PART);
145 qb.appendWhere(Part._ID + "=" + uri.getPathSegments().get(1));
146 break;
147 case MMS_MSG_ADDR:
148 qb.setTables(TABLE_ADDR);
149 qb.appendWhere(Addr.MSG_ID + "=" + uri.getPathSegments().get(0));
150 break;
151 case MMS_REPORT_STATUS:
152 /*
153 SELECT DISTINCT address,
154 T.delivery_status AS delivery_status,
155 T.read_status AS read_status
156 FROM addr
157 INNER JOIN (SELECT P1._id AS id1, P2._id AS id2, P3._id AS id3,
158 ifnull(P2.st, 0) AS delivery_status,
159 ifnull(P3.read_status, 0) AS read_status
160 FROM pdu P1
161 INNER JOIN pdu P2
162 ON P1.m_id = P2.m_id AND P2.m_type = 134
163 LEFT JOIN pdu P3
164 ON P1.m_id = P3.m_id AND P3.m_type = 136
165 UNION
166 SELECT P1._id AS id1, P2._id AS id2, P3._id AS id3,
167 ifnull(P2.st, 0) AS delivery_status,
168 ifnull(P3.read_status, 0) AS read_status
169 FROM pdu P1
170 INNER JOIN pdu P3
171 ON P1.m_id = P3.m_id AND P3.m_type = 136
172 LEFT JOIN pdu P2
173 ON P1.m_id = P2.m_id AND P2.m_type = 134) T
174 ON (msg_id = id2 AND type = 151)
175 OR (msg_id = id3 AND type = 137)
176 WHERE T.id1 = ?;
177 */
Ye Wen72f13552015-03-10 14:17:13 -0700178 qb.setTables(TABLE_ADDR + " INNER JOIN "
179 + "(SELECT P1._id AS id1, P2._id AS id2, P3._id AS id3, "
180 + "ifnull(P2.st, 0) AS delivery_status, "
181 + "ifnull(P3.read_status, 0) AS read_status "
182 + "FROM " + pduTable + " P1 INNER JOIN " + pduTable + " P2 "
183 + "ON P1.m_id=P2.m_id AND P2.m_type=134 "
184 + "LEFT JOIN " + pduTable + " P3 "
185 + "ON P1.m_id=P3.m_id AND P3.m_type=136 "
186 + "UNION "
187 + "SELECT P1._id AS id1, P2._id AS id2, P3._id AS id3, "
188 + "ifnull(P2.st, 0) AS delivery_status, "
189 + "ifnull(P3.read_status, 0) AS read_status "
190 + "FROM " + pduTable + " P1 INNER JOIN " + pduTable + " P3 "
191 + "ON P1.m_id=P3.m_id AND P3.m_type=136 "
192 + "LEFT JOIN " + pduTable + " P2 "
193 + "ON P1.m_id=P2.m_id AND P2.m_type=134) T "
194 + "ON (msg_id=id2 AND type=151) OR (msg_id=id3 AND type=137)");
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800195 qb.appendWhere("T.id1 = " + uri.getLastPathSegment());
196 qb.setDistinct(true);
197 break;
198 case MMS_REPORT_REQUEST:
199 /*
200 SELECT address, d_rpt, rr
201 FROM addr join pdu on pdu._id = addr.msg_id
202 WHERE pdu._id = messageId AND addr.type = 151
203 */
204 qb.setTables(TABLE_ADDR + " join " +
Ye Wen72f13552015-03-10 14:17:13 -0700205 pduTable + " on " + pduTable + "._id = addr.msg_id");
206 qb.appendWhere(pduTable + "._id = " + uri.getLastPathSegment());
207 qb.appendWhere(" AND " + TABLE_ADDR + ".type = " + PduHeaders.TO);
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800208 break;
209 case MMS_SENDING_RATE:
210 qb.setTables(TABLE_RATE);
211 break;
212 case MMS_DRM_STORAGE_ID:
213 qb.setTables(TABLE_DRM);
214 qb.appendWhere(BaseColumns._ID + "=" + uri.getLastPathSegment());
215 break;
Tom Taylor6c0ef242009-06-01 12:05:00 -0700216 case MMS_THREADS:
Ye Wen72f13552015-03-10 14:17:13 -0700217 qb.setTables(pduTable + " group by thread_id");
Tom Taylor6c0ef242009-06-01 12:05:00 -0700218 break;
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800219 default:
Wei Huang2914a7a2009-09-23 00:45:36 -0700220 Log.e(TAG, "query: invalid request: " + uri);
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800221 return null;
222 }
223
224 String finalSortOrder = null;
225 if (TextUtils.isEmpty(sortOrder)) {
Ye Wen72f13552015-03-10 14:17:13 -0700226 if (qb.getTables().equals(pduTable)) {
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800227 finalSortOrder = Mms.DATE + " DESC";
228 } else if (qb.getTables().equals(TABLE_PART)) {
229 finalSortOrder = Part.SEQ;
230 }
231 } else {
232 finalSortOrder = sortOrder;
233 }
234
Tom Taylor3ad9da42014-01-16 13:57:11 -0800235 Cursor ret;
236 try {
237 SQLiteDatabase db = mOpenHelper.getReadableDatabase();
238 ret = qb.query(db, projection, selection,
239 selectionArgs, null, null, finalSortOrder);
240 } catch (SQLiteException e) {
241 Log.e(TAG, "returning NULL cursor, query: " + uri, e);
242 return null;
243 }
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800244
245 // TODO: Does this need to be a URI for this provider.
246 ret.setNotificationUri(getContext().getContentResolver(), uri);
247 return ret;
248 }
249
Ye Wen72f13552015-03-10 14:17:13 -0700250 private void constructQueryForBox(SQLiteQueryBuilder qb, int msgBox, String pduTable) {
251 qb.setTables(pduTable);
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800252
253 if (msgBox != Mms.MESSAGE_BOX_ALL) {
254 qb.appendWhere(Mms.MESSAGE_BOX + "=" + msgBox);
255 }
256 }
257
258 @Override
259 public String getType(Uri uri) {
260 int match = sURLMatcher.match(uri);
261 switch (match) {
262 case MMS_ALL:
263 case MMS_INBOX:
264 case MMS_SENT:
265 case MMS_DRAFTS:
266 case MMS_OUTBOX:
267 return VND_ANDROID_DIR_MMS;
268 case MMS_ALL_ID:
269 case MMS_INBOX_ID:
270 case MMS_SENT_ID:
271 case MMS_DRAFTS_ID:
272 case MMS_OUTBOX_ID:
273 return VND_ANDROID_MMS;
274 case MMS_PART_ID: {
275 Cursor cursor = mOpenHelper.getReadableDatabase().query(
276 TABLE_PART, new String[] { Part.CONTENT_TYPE },
277 Part._ID + " = ?", new String[] { uri.getLastPathSegment() },
278 null, null, null);
279 if (cursor != null) {
280 try {
281 if ((cursor.getCount() == 1) && cursor.moveToFirst()) {
282 return cursor.getString(0);
283 } else {
284 Log.e(TAG, "cursor.count() != 1: " + uri);
285 }
286 } finally {
287 cursor.close();
288 }
289 } else {
290 Log.e(TAG, "cursor == null: " + uri);
291 }
292 return "*/*";
293 }
294 case MMS_ALL_PART:
295 case MMS_MSG_PART:
296 case MMS_MSG_ADDR:
297 default:
298 return "*/*";
299 }
300 }
301
302 @Override
303 public Uri insert(Uri uri, ContentValues values) {
Tom Taylor438403e2013-02-21 16:56:01 -0800304 // Don't let anyone insert anything with the _data column
305 if (values != null && values.containsKey(Part._DATA)) {
306 return null;
307 }
Ye Wene07acb92014-11-19 12:06:05 -0800308 final int callerUid = Binder.getCallingUid();
Ye Wen72f13552015-03-10 14:17:13 -0700309 final String callerPkg = getCallingPackage();
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800310 int msgBox = Mms.MESSAGE_BOX_ALL;
311 boolean notify = true;
312
313 int match = sURLMatcher.match(uri);
314 if (LOCAL_LOGV) {
315 Log.v(TAG, "Insert uri=" + uri + ", match=" + match);
316 }
317
318 String table = TABLE_PDU;
319 switch (match) {
320 case MMS_ALL:
321 Object msgBoxObj = values.getAsInteger(Mms.MESSAGE_BOX);
322 if (msgBoxObj != null) {
323 msgBox = (Integer) msgBoxObj;
324 }
325 else {
326 // default to inbox
327 msgBox = Mms.MESSAGE_BOX_INBOX;
328 }
329 break;
330 case MMS_INBOX:
331 msgBox = Mms.MESSAGE_BOX_INBOX;
332 break;
333 case MMS_SENT:
334 msgBox = Mms.MESSAGE_BOX_SENT;
335 break;
336 case MMS_DRAFTS:
337 msgBox = Mms.MESSAGE_BOX_DRAFTS;
338 break;
339 case MMS_OUTBOX:
340 msgBox = Mms.MESSAGE_BOX_OUTBOX;
341 break;
342 case MMS_MSG_PART:
343 notify = false;
344 table = TABLE_PART;
345 break;
346 case MMS_MSG_ADDR:
347 notify = false;
348 table = TABLE_ADDR;
349 break;
350 case MMS_SENDING_RATE:
351 notify = false;
352 table = TABLE_RATE;
353 break;
354 case MMS_DRM_STORAGE:
355 notify = false;
356 table = TABLE_DRM;
357 break;
358 default:
Wei Huang2914a7a2009-09-23 00:45:36 -0700359 Log.e(TAG, "insert: invalid request: " + uri);
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800360 return null;
361 }
362
363 SQLiteDatabase db = mOpenHelper.getWritableDatabase();
364 ContentValues finalValues;
365 Uri res = Mms.CONTENT_URI;
366 long rowId;
367
368 if (table.equals(TABLE_PDU)) {
369 boolean addDate = !values.containsKey(Mms.DATE);
370 boolean addMsgBox = !values.containsKey(Mms.MESSAGE_BOX);
371
372 // Filter keys we don't support yet.
373 filterUnsupportedKeys(values);
374
375 // TODO: Should initialValues be validated, e.g. if it
376 // missed some significant keys?
377 finalValues = new ContentValues(values);
378
379 long timeInMillis = System.currentTimeMillis();
380
381 if (addDate) {
382 finalValues.put(Mms.DATE, timeInMillis / 1000L);
383 }
384
385 if (addMsgBox && (msgBox != Mms.MESSAGE_BOX_ALL)) {
386 finalValues.put(Mms.MESSAGE_BOX, msgBox);
387 }
388
389 if (msgBox != Mms.MESSAGE_BOX_INBOX) {
390 // Mark all non-inbox messages read.
391 finalValues.put(Mms.READ, 1);
392 }
393
Yusuf T. Mobile21c25bc2009-06-16 13:40:38 -0700394 // thread_id
395 Long threadId = values.getAsLong(Mms.THREAD_ID);
396 String address = values.getAsString(CanonicalAddressesColumns.ADDRESS);
397
Tom Taylor59269962012-05-09 14:42:35 -0700398 if (((threadId == null) || (threadId == 0)) && (!TextUtils.isEmpty(address))) {
Yusuf T. Mobile21c25bc2009-06-16 13:40:38 -0700399 finalValues.put(Mms.THREAD_ID, Threads.getOrCreateThreadId(getContext(), address));
400 }
401
Ye Wene07acb92014-11-19 12:06:05 -0800402 if (ProviderUtil.shouldSetCreator(finalValues, callerUid)) {
403 // Only SYSTEM or PHONE can set CREATOR
404 // If caller is not SYSTEM or PHONE, or SYSTEM or PHONE does not set CREATOR
405 // set CREATOR using the truth on caller.
406 // Note: Inferring package name from UID may include unrelated package names
Ye Wen72f13552015-03-10 14:17:13 -0700407 finalValues.put(Telephony.Mms.CREATOR, callerPkg);
Ye Wene07acb92014-11-19 12:06:05 -0800408 }
409
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800410 if ((rowId = db.insert(table, null, finalValues)) <= 0) {
Ye Wene07acb92014-11-19 12:06:05 -0800411 Log.e(TAG, "MmsProvider.insert: failed!");
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800412 return null;
413 }
414
415 res = Uri.parse(res + "/" + rowId);
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800416 } else if (table.equals(TABLE_ADDR)) {
417 finalValues = new ContentValues(values);
418 finalValues.put(Addr.MSG_ID, uri.getPathSegments().get(0));
419
420 if ((rowId = db.insert(table, null, finalValues)) <= 0) {
Ye Wene07acb92014-11-19 12:06:05 -0800421 Log.e(TAG, "Failed to insert address");
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800422 return null;
423 }
424
425 res = Uri.parse(res + "/addr/" + rowId);
426 } else if (table.equals(TABLE_PART)) {
427 finalValues = new ContentValues(values);
428
429 if (match == MMS_MSG_PART) {
430 finalValues.put(Part.MSG_ID, uri.getPathSegments().get(0));
431 }
432
Mark Wagnerf0a9e902009-06-19 16:00:13 -0700433 String contentType = values.getAsString("ct");
Mark Wagner8e5ee782010-01-04 17:39:06 -0800434
Mark Wagnerf0a9e902009-06-19 16:00:13 -0700435 // text/plain and app application/smil store their "data" inline in the
436 // table so there's no need to create the file
Tom Taylorc2db47d2012-03-27 15:15:39 -0700437 boolean plainText = false;
438 boolean smilText = false;
439 if ("text/plain".equals(contentType)) {
440 plainText = true;
441 } else if ("application/smil".equals(contentType)) {
442 smilText = true;
443 }
Mark Wagner8e5ee782010-01-04 17:39:06 -0800444 if (!plainText && !smilText) {
Tom Taylorc2db47d2012-03-27 15:15:39 -0700445 // Use the filename if possible, otherwise use the current time as the name.
446 String contentLocation = values.getAsString("cl");
447 if (!TextUtils.isEmpty(contentLocation)) {
448 File f = new File(contentLocation);
449 contentLocation = "_" + f.getName();
450 } else {
451 contentLocation = "";
452 }
453
Mark Wagnerf0a9e902009-06-19 16:00:13 -0700454 // Generate the '_data' field of the part with default
455 // permission settings.
Ye Weneaa93e62015-01-06 13:08:53 -0800456 String path = getContext().getDir(PARTS_DIR_NAME, 0).getPath()
Tom Taylorc2db47d2012-03-27 15:15:39 -0700457 + "/PART_" + System.currentTimeMillis() + contentLocation;
458
459 if (DownloadDrmHelper.isDrmConvertNeeded(contentType)) {
460 // Adds the .fl extension to the filename if contentType is
461 // "application/vnd.oma.drm.message"
462 path = DownloadDrmHelper.modifyDrmFwLockFileExtension(path);
463 }
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800464
Mark Wagnerf0a9e902009-06-19 16:00:13 -0700465 finalValues.put(Part._DATA, path);
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800466
Mark Wagnerf0a9e902009-06-19 16:00:13 -0700467 File partFile = new File(path);
468 if (!partFile.exists()) {
469 try {
470 if (!partFile.createNewFile()) {
471 throw new IllegalStateException(
472 "Unable to create new partFile: " + path);
473 }
Tom Taylorc2db47d2012-03-27 15:15:39 -0700474 // Give everyone rw permission until we encrypt the file
475 // (in PduPersister.persistData). Once the file is encrypted, the
476 // permissions will be set to 0644.
477 int result = FileUtils.setPermissions(path, 0666, -1, -1);
478 if (LOCAL_LOGV) {
479 Log.d(TAG, "MmsProvider.insert setPermissions result: " + result);
480 }
Mark Wagnerf0a9e902009-06-19 16:00:13 -0700481 } catch (IOException e) {
482 Log.e(TAG, "createNewFile", e);
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800483 throw new IllegalStateException(
484 "Unable to create new partFile: " + path);
485 }
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800486 }
487 }
488
489 if ((rowId = db.insert(table, null, finalValues)) <= 0) {
Ye Wene07acb92014-11-19 12:06:05 -0800490 Log.e(TAG, "MmsProvider.insert: failed!");
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800491 return null;
492 }
493
494 res = Uri.parse(res + "/part/" + rowId);
Mark Wagner8e5ee782010-01-04 17:39:06 -0800495
496 // Don't use a trigger for updating the words table because of a bug
497 // in FTS3. The bug is such that the call to get the last inserted
498 // row is incorrect.
499 if (plainText) {
500 // Update the words table with a corresponding row. The words table
501 // allows us to search for words quickly, without scanning the whole
502 // table;
503 ContentValues cv = new ContentValues();
504
505 // we're using the row id of the part table row but we're also using ids
506 // from the sms table so this divides the space into two large chunks.
507 // The row ids from the part table start at 2 << 32.
508 cv.put(Telephony.MmsSms.WordsTable.ID, (2 << 32) + rowId);
509 cv.put(Telephony.MmsSms.WordsTable.INDEXED_TEXT, values.getAsString("text"));
510 cv.put(Telephony.MmsSms.WordsTable.SOURCE_ROW_ID, rowId);
511 cv.put(Telephony.MmsSms.WordsTable.TABLE_ID, 2);
512 db.insert(TABLE_WORDS, Telephony.MmsSms.WordsTable.INDEXED_TEXT, cv);
513 }
514
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800515 } else if (table.equals(TABLE_RATE)) {
516 long now = values.getAsLong(Rate.SENT_TIME);
517 long oneHourAgo = now - 1000 * 60 * 60;
518 // Delete all unused rows (time earlier than one hour ago).
519 db.delete(table, Rate.SENT_TIME + "<=" + oneHourAgo, null);
520 db.insert(table, null, values);
521 } else if (table.equals(TABLE_DRM)) {
Ye Weneaa93e62015-01-06 13:08:53 -0800522 String path = getContext().getDir(PARTS_DIR_NAME, 0).getPath()
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800523 + "/PART_" + System.currentTimeMillis();
524 finalValues = new ContentValues(1);
525 finalValues.put("_data", path);
526
527 File partFile = new File(path);
528 if (!partFile.exists()) {
529 try {
530 if (!partFile.createNewFile()) {
531 throw new IllegalStateException(
532 "Unable to create new file: " + path);
533 }
534 } catch (IOException e) {
535 Log.e(TAG, "createNewFile", e);
536 throw new IllegalStateException(
537 "Unable to create new file: " + path);
538 }
539 }
540
541 if ((rowId = db.insert(table, null, finalValues)) <= 0) {
Ye Wene07acb92014-11-19 12:06:05 -0800542 Log.e(TAG, "MmsProvider.insert: failed!");
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800543 return null;
544 }
545 res = Uri.parse(res + "/drm/" + rowId);
546 } else {
547 throw new AssertionError("Unknown table type: " + table);
548 }
549
550 if (notify) {
551 notifyChange();
552 }
553 return res;
554 }
555
556 private int getMessageBoxByMatch(int match) {
557 switch (match) {
558 case MMS_INBOX_ID:
559 case MMS_INBOX:
560 return Mms.MESSAGE_BOX_INBOX;
561 case MMS_SENT_ID:
562 case MMS_SENT:
563 return Mms.MESSAGE_BOX_SENT;
564 case MMS_DRAFTS_ID:
565 case MMS_DRAFTS:
566 return Mms.MESSAGE_BOX_DRAFTS;
567 case MMS_OUTBOX_ID:
568 case MMS_OUTBOX:
569 return Mms.MESSAGE_BOX_OUTBOX;
570 default:
571 throw new IllegalArgumentException("bad Arg: " + match);
572 }
573 }
574
575 @Override
576 public int delete(Uri uri, String selection,
577 String[] selectionArgs) {
578 int match = sURLMatcher.match(uri);
579 if (LOCAL_LOGV) {
580 Log.v(TAG, "Delete uri=" + uri + ", match=" + match);
581 }
582
583 String table, extraSelection = null;
584 boolean notify = false;
585
586 switch (match) {
587 case MMS_ALL_ID:
588 case MMS_INBOX_ID:
589 case MMS_SENT_ID:
590 case MMS_DRAFTS_ID:
591 case MMS_OUTBOX_ID:
592 notify = true;
593 table = TABLE_PDU;
594 extraSelection = Mms._ID + "=" + uri.getLastPathSegment();
595 break;
596 case MMS_ALL:
597 case MMS_INBOX:
598 case MMS_SENT:
599 case MMS_DRAFTS:
600 case MMS_OUTBOX:
601 notify = true;
602 table = TABLE_PDU;
603 if (match != MMS_ALL) {
604 int msgBox = getMessageBoxByMatch(match);
605 extraSelection = Mms.MESSAGE_BOX + "=" + msgBox;
606 }
607 break;
608 case MMS_ALL_PART:
609 table = TABLE_PART;
610 break;
611 case MMS_MSG_PART:
612 table = TABLE_PART;
613 extraSelection = Part.MSG_ID + "=" + uri.getPathSegments().get(0);
614 break;
615 case MMS_PART_ID:
616 table = TABLE_PART;
617 extraSelection = Part._ID + "=" + uri.getPathSegments().get(1);
618 break;
619 case MMS_MSG_ADDR:
620 table = TABLE_ADDR;
621 extraSelection = Addr.MSG_ID + "=" + uri.getPathSegments().get(0);
622 break;
623 case MMS_DRM_STORAGE:
624 table = TABLE_DRM;
625 break;
626 default:
627 Log.w(TAG, "No match for URI '" + uri + "'");
628 return 0;
629 }
630
631 String finalSelection = concatSelections(selection, extraSelection);
632 SQLiteDatabase db = mOpenHelper.getWritableDatabase();
633 int deletedRows = 0;
634
635 if (TABLE_PDU.equals(table)) {
636 deletedRows = deleteMessages(getContext(), db, finalSelection,
637 selectionArgs, uri);
638 } else if (TABLE_PART.equals(table)) {
639 deletedRows = deleteParts(db, finalSelection, selectionArgs);
kaiyizcd21c4f2015-01-30 11:22:36 +0800640 cleanUpWords(db);
641 updateHasAttachment(db);
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800642 } else if (TABLE_DRM.equals(table)) {
643 deletedRows = deleteTempDrmData(db, finalSelection, selectionArgs);
644 } else {
645 deletedRows = db.delete(table, finalSelection, selectionArgs);
646 }
647
648 if ((deletedRows > 0) && notify) {
649 notifyChange();
650 }
651 return deletedRows;
652 }
653
654 static int deleteMessages(Context context, SQLiteDatabase db,
655 String selection, String[] selectionArgs, Uri uri) {
kaiyizcd21c4f2015-01-30 11:22:36 +0800656 Cursor cursor = db.query(TABLE_PDU, new String[] { Mms._ID, Mms.THREAD_ID },
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800657 selection, selectionArgs, null, null, null);
658 if (cursor == null) {
659 return 0;
660 }
661
kaiyizcd21c4f2015-01-30 11:22:36 +0800662 HashSet<Long> threadIds = new HashSet<Long>();
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800663 try {
664 if (cursor.getCount() == 0) {
665 return 0;
666 }
667
668 while (cursor.moveToNext()) {
669 deleteParts(db, Part.MSG_ID + " = ?",
670 new String[] { String.valueOf(cursor.getLong(0)) });
kaiyizcd21c4f2015-01-30 11:22:36 +0800671 threadIds.add(cursor.getLong(1));
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800672 }
kaiyizcd21c4f2015-01-30 11:22:36 +0800673 cleanUpWords(db);
674 updateHasAttachment(db);
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800675 } finally {
676 cursor.close();
677 }
678
679 int count = db.delete(TABLE_PDU, selection, selectionArgs);
kaiyizcd21c4f2015-01-30 11:22:36 +0800680 for (long thread : threadIds) {
681 MmsSmsDatabaseHelper.updateThread(db, thread);
682 }
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800683 if (count > 0) {
684 Intent intent = new Intent(Mms.Intents.CONTENT_CHANGED_ACTION);
685 intent.putExtra(Mms.Intents.DELETED_CONTENTS, uri);
686 if (LOCAL_LOGV) {
687 Log.v(TAG, "Broadcasting intent: " + intent);
688 }
689 context.sendBroadcast(intent);
690 }
691 return count;
692 }
693
kaiyizcd21c4f2015-01-30 11:22:36 +0800694 private static void cleanUpWords(SQLiteDatabase db) {
695 db.execSQL("DELETE FROM words WHERE source_id not in (select _id from part) AND "
696 + "table_to_use = 2");
697 }
698
699 private static void updateHasAttachment(SQLiteDatabase db) {
700 db.execSQL("UPDATE threads SET has_attachment = CASE "
701 + "(SELECT COUNT(*) FROM part JOIN pdu WHERE part.mid = pdu._id AND "
702 + "pdu.thread_id = threads._id AND part.ct != 'text/plain' "
703 + "AND part.ct != 'application/smil') WHEN 0 THEN 0 ELSE 1 END");
704 }
705
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800706 private static int deleteParts(SQLiteDatabase db, String selection,
707 String[] selectionArgs) {
708 return deleteDataRows(db, TABLE_PART, selection, selectionArgs);
709 }
710
711 private static int deleteTempDrmData(SQLiteDatabase db, String selection,
712 String[] selectionArgs) {
713 return deleteDataRows(db, TABLE_DRM, selection, selectionArgs);
714 }
715
716 private static int deleteDataRows(SQLiteDatabase db, String table,
717 String selection, String[] selectionArgs) {
718 Cursor cursor = db.query(table, new String[] { "_data" },
719 selection, selectionArgs, null, null, null);
720 if (cursor == null) {
721 // FIXME: This might be an error, ignore it may cause
722 // unpredictable result.
723 return 0;
724 }
725
726 try {
727 if (cursor.getCount() == 0) {
728 return 0;
729 }
730
731 while (cursor.moveToNext()) {
732 try {
733 // Delete the associated files saved on file-system.
Mark Wagnerf0a9e902009-06-19 16:00:13 -0700734 String path = cursor.getString(0);
735 if (path != null) {
736 new File(path).delete();
737 }
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800738 } catch (Throwable ex) {
739 Log.e(TAG, ex.getMessage(), ex);
740 }
741 }
742 } finally {
743 cursor.close();
744 }
745
746 return db.delete(table, selection, selectionArgs);
747 }
748
749 @Override
750 public int update(Uri uri, ContentValues values,
751 String selection, String[] selectionArgs) {
Tom Taylor438403e2013-02-21 16:56:01 -0800752 // Don't let anyone update the _data column
753 if (values != null && values.containsKey(Part._DATA)) {
754 return 0;
755 }
Ye Wene07acb92014-11-19 12:06:05 -0800756 final int callerUid = Binder.getCallingUid();
Ye Wen72f13552015-03-10 14:17:13 -0700757 final String callerPkg = getCallingPackage();
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800758 int match = sURLMatcher.match(uri);
759 if (LOCAL_LOGV) {
760 Log.v(TAG, "Update uri=" + uri + ", match=" + match);
761 }
762
763 boolean notify = false;
764 String msgId = null;
765 String table;
766
767 switch (match) {
768 case MMS_ALL_ID:
769 case MMS_INBOX_ID:
770 case MMS_SENT_ID:
771 case MMS_DRAFTS_ID:
772 case MMS_OUTBOX_ID:
773 msgId = uri.getLastPathSegment();
774 // fall-through
775 case MMS_ALL:
776 case MMS_INBOX:
777 case MMS_SENT:
778 case MMS_DRAFTS:
779 case MMS_OUTBOX:
780 notify = true;
781 table = TABLE_PDU;
782 break;
Tom Taylorc2db47d2012-03-27 15:15:39 -0700783
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800784 case MMS_MSG_PART:
785 case MMS_PART_ID:
786 table = TABLE_PART;
787 break;
Tom Taylorc2db47d2012-03-27 15:15:39 -0700788
789 case MMS_PART_RESET_FILE_PERMISSION:
Ye Weneaa93e62015-01-06 13:08:53 -0800790 String path = getContext().getDir(PARTS_DIR_NAME, 0).getPath() + '/' +
Tom Taylorc2db47d2012-03-27 15:15:39 -0700791 uri.getPathSegments().get(1);
792 // Reset the file permission back to read for everyone but me.
793 int result = FileUtils.setPermissions(path, 0644, -1, -1);
794 if (LOCAL_LOGV) {
795 Log.d(TAG, "MmsProvider.update setPermissions result: " + result +
796 " for path: " + path);
797 }
798 return 0;
799
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800800 default:
801 Log.w(TAG, "Update operation for '" + uri + "' not implemented.");
802 return 0;
803 }
804
805 String extraSelection = null;
806 ContentValues finalValues;
807 if (table.equals(TABLE_PDU)) {
808 // Filter keys that we don't support yet.
809 filterUnsupportedKeys(values);
Ye Wene07acb92014-11-19 12:06:05 -0800810 if (ProviderUtil.shouldRemoveCreator(values, callerUid)) {
811 // CREATOR should not be changed by non-SYSTEM/PHONE apps
Ye Wen72f13552015-03-10 14:17:13 -0700812 Log.w(TAG, callerPkg + " tries to update CREATOR");
Ye Wene07acb92014-11-19 12:06:05 -0800813 values.remove(Mms.CREATOR);
814 }
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800815 finalValues = new ContentValues(values);
816
817 if (msgId != null) {
818 extraSelection = Mms._ID + "=" + msgId;
819 }
820 } else if (table.equals(TABLE_PART)) {
821 finalValues = new ContentValues(values);
822
823 switch (match) {
824 case MMS_MSG_PART:
825 extraSelection = Part.MSG_ID + "=" + uri.getPathSegments().get(0);
826 break;
827 case MMS_PART_ID:
828 extraSelection = Part._ID + "=" + uri.getPathSegments().get(1);
829 break;
830 default:
831 break;
832 }
833 } else {
834 return 0;
835 }
836
837 String finalSelection = concatSelections(selection, extraSelection);
838 SQLiteDatabase db = mOpenHelper.getWritableDatabase();
839 int count = db.update(table, finalValues, finalSelection, selectionArgs);
840 if (notify && (count > 0)) {
841 notifyChange();
842 }
843 return count;
844 }
845
846 @Override
Wei Huang2914a7a2009-09-23 00:45:36 -0700847 public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
Wei Huang2914a7a2009-09-23 00:45:36 -0700848 int match = sURLMatcher.match(uri);
849
850 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Tom Taylor8168ff82013-02-19 14:30:23 -0800851 Log.d(TAG, "openFile: uri=" + uri + ", mode=" + mode + ", match=" + match);
Wei Huang2914a7a2009-09-23 00:45:36 -0700852 }
853
Tom Taylor8168ff82013-02-19 14:30:23 -0800854 if (match != MMS_PART_ID) {
855 return null;
Wei Huang2914a7a2009-09-23 00:45:36 -0700856 }
857
Tom Taylor8168ff82013-02-19 14:30:23 -0800858 // Verify that the _data path points to mms data
859 Cursor c = query(uri, new String[]{"_data"}, null, null, null);
860 int count = (c != null) ? c.getCount() : 0;
861 if (count != 1) {
862 // If there is not exactly one result, throw an appropriate
863 // exception.
864 if (c != null) {
865 c.close();
866 }
867 if (count == 0) {
868 throw new FileNotFoundException("No entry for " + uri);
869 }
870 throw new FileNotFoundException("Multiple items at " + uri);
871 }
872
873 c.moveToFirst();
874 int i = c.getColumnIndex("_data");
875 String path = (i >= 0 ? c.getString(i) : null);
876 c.close();
877
878 if (path == null) {
879 return null;
880 }
881 try {
882 File filePath = new File(path);
883 if (!filePath.getCanonicalPath()
Amith Yamasanida40d6a2015-04-14 13:37:12 -0700884 .startsWith(getContext().getDir(PARTS_DIR_NAME, 0).getCanonicalPath())) {
Ye Weneaa93e62015-01-06 13:08:53 -0800885 Log.e(TAG, "openFile: path "
886 + filePath.getCanonicalPath()
887 + " does not start with "
Amith Yamasanida40d6a2015-04-14 13:37:12 -0700888 + getContext().getDir(PARTS_DIR_NAME, 0).getCanonicalPath());
Ye Weneaa93e62015-01-06 13:08:53 -0800889 // Don't care return value
890 filePath.delete();
Tom Taylor8168ff82013-02-19 14:30:23 -0800891 return null;
892 }
893 } catch (IOException e) {
Ye Weneaa93e62015-01-06 13:08:53 -0800894 Log.e(TAG, "openFile: create path failed " + e, e);
Tom Taylor8168ff82013-02-19 14:30:23 -0800895 return null;
896 }
897
898 return openFileHelper(uri, mode);
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800899 }
900
901 private void filterUnsupportedKeys(ContentValues values) {
902 // Some columns are unsupported. They should therefore
903 // neither be inserted nor updated. Filter them out.
904 values.remove(Mms.DELIVERY_TIME_TOKEN);
905 values.remove(Mms.SENDER_VISIBILITY);
906 values.remove(Mms.REPLY_CHARGING);
907 values.remove(Mms.REPLY_CHARGING_DEADLINE_TOKEN);
908 values.remove(Mms.REPLY_CHARGING_DEADLINE);
909 values.remove(Mms.REPLY_CHARGING_ID);
910 values.remove(Mms.REPLY_CHARGING_SIZE);
911 values.remove(Mms.PREVIOUSLY_SENT_BY);
912 values.remove(Mms.PREVIOUSLY_SENT_DATE);
913 values.remove(Mms.STORE);
914 values.remove(Mms.MM_STATE);
915 values.remove(Mms.MM_FLAGS_TOKEN);
916 values.remove(Mms.MM_FLAGS);
917 values.remove(Mms.STORE_STATUS);
918 values.remove(Mms.STORE_STATUS_TEXT);
919 values.remove(Mms.STORED);
920 values.remove(Mms.TOTALS);
921 values.remove(Mms.MBOX_TOTALS);
922 values.remove(Mms.MBOX_TOTALS_TOKEN);
923 values.remove(Mms.QUOTAS);
924 values.remove(Mms.MBOX_QUOTAS);
925 values.remove(Mms.MBOX_QUOTAS_TOKEN);
926 values.remove(Mms.MESSAGE_COUNT);
927 values.remove(Mms.START);
928 values.remove(Mms.DISTRIBUTION_INDICATOR);
929 values.remove(Mms.ELEMENT_DESCRIPTOR);
930 values.remove(Mms.LIMIT);
931 values.remove(Mms.RECOMMENDED_RETRIEVAL_MODE);
932 values.remove(Mms.RECOMMENDED_RETRIEVAL_MODE_TEXT);
933 values.remove(Mms.STATUS_TEXT);
934 values.remove(Mms.APPLIC_ID);
935 values.remove(Mms.REPLY_APPLIC_ID);
936 values.remove(Mms.AUX_APPLIC_ID);
937 values.remove(Mms.DRM_CONTENT);
938 values.remove(Mms.ADAPTATION_ALLOWED);
939 values.remove(Mms.REPLACE_ID);
940 values.remove(Mms.CANCEL_ID);
941 values.remove(Mms.CANCEL_STATUS);
942
943 // Keys shouldn't be inserted or updated.
944 values.remove(Mms._ID);
945 }
946
947 private void notifyChange() {
948 getContext().getContentResolver().notifyChange(
Amith Yamasani43f9fb22014-09-10 15:56:47 -0700949 MmsSms.CONTENT_URI, null, true, UserHandle.USER_ALL);
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800950 }
951
952 private final static String TAG = "MmsProvider";
953 private final static String VND_ANDROID_MMS = "vnd.android/mms";
954 private final static String VND_ANDROID_DIR_MMS = "vnd.android-dir/mms";
955 private final static boolean DEBUG = false;
Joe Onoratodc946792011-04-07 18:41:15 -0700956 private final static boolean LOCAL_LOGV = false;
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800957
958 private static final int MMS_ALL = 0;
959 private static final int MMS_ALL_ID = 1;
960 private static final int MMS_INBOX = 2;
961 private static final int MMS_INBOX_ID = 3;
962 private static final int MMS_SENT = 4;
963 private static final int MMS_SENT_ID = 5;
964 private static final int MMS_DRAFTS = 6;
965 private static final int MMS_DRAFTS_ID = 7;
966 private static final int MMS_OUTBOX = 8;
967 private static final int MMS_OUTBOX_ID = 9;
968 private static final int MMS_ALL_PART = 10;
969 private static final int MMS_MSG_PART = 11;
970 private static final int MMS_PART_ID = 12;
971 private static final int MMS_MSG_ADDR = 13;
972 private static final int MMS_SENDING_RATE = 14;
Tom Taylor6c0ef242009-06-01 12:05:00 -0700973 private static final int MMS_REPORT_STATUS = 15;
974 private static final int MMS_REPORT_REQUEST = 16;
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800975 private static final int MMS_DRM_STORAGE = 17;
976 private static final int MMS_DRM_STORAGE_ID = 18;
Tom Taylor6c0ef242009-06-01 12:05:00 -0700977 private static final int MMS_THREADS = 19;
Tom Taylorc2db47d2012-03-27 15:15:39 -0700978 private static final int MMS_PART_RESET_FILE_PERMISSION = 20;
The Android Open Source Project7236c3a2009-03-03 19:32:44 -0800979
980 private static final UriMatcher
981 sURLMatcher = new UriMatcher(UriMatcher.NO_MATCH);
982
983 static {
984 sURLMatcher.addURI("mms", null, MMS_ALL);
985 sURLMatcher.addURI("mms", "#", MMS_ALL_ID);
986 sURLMatcher.addURI("mms", "inbox", MMS_INBOX);
987 sURLMatcher.addURI("mms", "inbox/#", MMS_INBOX_ID);
988 sURLMatcher.addURI("mms", "sent", MMS_SENT);
989 sURLMatcher.addURI("mms", "sent/#", MMS_SENT_ID);
990 sURLMatcher.addURI("mms", "drafts", MMS_DRAFTS);
991 sURLMatcher.addURI("mms", "drafts/#", MMS_DRAFTS_ID);
992 sURLMatcher.addURI("mms", "outbox", MMS_OUTBOX);
993 sURLMatcher.addURI("mms", "outbox/#", MMS_OUTBOX_ID);
994 sURLMatcher.addURI("mms", "part", MMS_ALL_PART);
995 sURLMatcher.addURI("mms", "#/part", MMS_MSG_PART);
996 sURLMatcher.addURI("mms", "part/#", MMS_PART_ID);
997 sURLMatcher.addURI("mms", "#/addr", MMS_MSG_ADDR);
998 sURLMatcher.addURI("mms", "rate", MMS_SENDING_RATE);
999 sURLMatcher.addURI("mms", "report-status/#", MMS_REPORT_STATUS);
1000 sURLMatcher.addURI("mms", "report-request/#", MMS_REPORT_REQUEST);
1001 sURLMatcher.addURI("mms", "drm", MMS_DRM_STORAGE);
1002 sURLMatcher.addURI("mms", "drm/#", MMS_DRM_STORAGE_ID);
Tom Taylor6c0ef242009-06-01 12:05:00 -07001003 sURLMatcher.addURI("mms", "threads", MMS_THREADS);
Tom Taylorc2db47d2012-03-27 15:15:39 -07001004 sURLMatcher.addURI("mms", "resetFilePerm/*", MMS_PART_RESET_FILE_PERMISSION);
The Android Open Source Project7236c3a2009-03-03 19:32:44 -08001005 }
1006
1007 private SQLiteOpenHelper mOpenHelper;
1008
The Android Open Source Project7236c3a2009-03-03 19:32:44 -08001009 private static String concatSelections(String selection1, String selection2) {
1010 if (TextUtils.isEmpty(selection1)) {
1011 return selection2;
1012 } else if (TextUtils.isEmpty(selection2)) {
1013 return selection1;
1014 } else {
1015 return selection1 + " AND " + selection2;
1016 }
1017 }
1018}
1019