Guest User

Untitled

a guest
Mar 30th, 2015
297
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 40.21 KB | None | 0 0
  1. /*
  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.  
  17. package com.android.providers.telephony;
  18.  
  19. import android.app.AppOpsManager;
  20. import android.content.ContentProvider;
  21. import android.content.ContentValues;
  22. import android.content.Context;
  23. import android.content.Intent;
  24. import android.content.UriMatcher;
  25. import android.database.Cursor;
  26. import android.database.sqlite.SQLiteDatabase;
  27. import android.database.sqlite.SQLiteException;
  28. import android.database.sqlite.SQLiteOpenHelper;
  29. import android.database.sqlite.SQLiteQueryBuilder;
  30. import android.net.Uri;
  31. import android.os.Binder;
  32. import android.os.FileUtils;
  33. import android.os.ParcelFileDescriptor;
  34. import android.os.UserHandle;
  35. import android.provider.BaseColumns;
  36. import android.provider.Telephony;
  37. import android.provider.Telephony.CanonicalAddressesColumns;
  38. import android.provider.Telephony.Mms;
  39. import android.provider.Telephony.Mms.Addr;
  40. import android.provider.Telephony.Mms.Part;
  41. import android.provider.Telephony.Mms.Rate;
  42. import android.provider.Telephony.MmsSms;
  43. import android.provider.Telephony.Threads;
  44. import android.text.TextUtils;
  45. import android.util.Log;
  46.  
  47. import com.google.android.mms.pdu.PduHeaders;
  48. import com.google.android.mms.util.DownloadDrmHelper;
  49.  
  50. import java.io.File;
  51. import java.io.FileNotFoundException;
  52. import java.io.IOException;
  53. import java.util.HashSet;
  54.  
  55. /**
  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. */
  59. public 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";
  65. static final String TABLE_WORDS = "words";
  66.  
  67.  
  68. @Override
  69. public boolean onCreate() {
  70. setAppOps(AppOpsManager.OP_READ_MMS, AppOpsManager.OP_WRITE_MMS);
  71. mOpenHelper = MmsSmsDatabaseHelper.getInstance(getContext());
  72. return true;
  73. }
  74.  
  75. @Override
  76. public Cursor query(Uri uri, String[] projection,
  77. String selection, String[] selectionArgs, String sortOrder) {
  78. SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
  79.  
  80. // Generate the body of the query.
  81. int match = sURLMatcher.match(uri);
  82. if (LOCAL_LOGV) {
  83. Log.v(TAG, "Query uri=" + uri + ", match=" + match);
  84. }
  85.  
  86. switch (match) {
  87. case MMS_ALL:
  88. constructQueryForBox(qb, Mms.MESSAGE_BOX_ALL);
  89. break;
  90. case MMS_INBOX:
  91. constructQueryForBox(qb, Mms.MESSAGE_BOX_INBOX);
  92. break;
  93. case MMS_SENT:
  94. constructQueryForBox(qb, Mms.MESSAGE_BOX_SENT);
  95. break;
  96. case MMS_DRAFTS:
  97. constructQueryForBox(qb, Mms.MESSAGE_BOX_DRAFTS);
  98. break;
  99. case MMS_OUTBOX:
  100. constructQueryForBox(qb, Mms.MESSAGE_BOX_OUTBOX);
  101. break;
  102. case MMS_ALL_ID:
  103. qb.setTables(TABLE_PDU);
  104. qb.appendWhere(Mms._ID + "=" + uri.getPathSegments().get(0));
  105. break;
  106. case MMS_INBOX_ID:
  107. case MMS_SENT_ID:
  108. case MMS_DRAFTS_ID:
  109. case MMS_OUTBOX_ID:
  110. qb.setTables(TABLE_PDU);
  111. qb.appendWhere(Mms._ID + "=" + uri.getPathSegments().get(1));
  112. qb.appendWhere(" AND " + Mms.MESSAGE_BOX + "="
  113. + getMessageBoxByMatch(match));
  114. break;
  115. case MMS_ALL_PART:
  116. qb.setTables(TABLE_PART);
  117. break;
  118. case MMS_MSG_PART:
  119. qb.setTables(TABLE_PART);
  120. qb.appendWhere(Part.MSG_ID + "=" + uri.getPathSegments().get(0));
  121. break;
  122. case MMS_PART_ID:
  123. qb.setTables(TABLE_PART);
  124. qb.appendWhere(Part._ID + "=" + uri.getPathSegments().get(1));
  125. break;
  126. case MMS_MSG_ADDR:
  127. qb.setTables(TABLE_ADDR);
  128. qb.appendWhere(Addr.MSG_ID + "=" + uri.getPathSegments().get(0));
  129. break;
  130. case MMS_REPORT_STATUS:
  131. /*
  132. SELECT DISTINCT address,
  133. T.delivery_status AS delivery_status,
  134. T.read_status AS read_status
  135. FROM addr
  136. INNER JOIN (SELECT P1._id AS id1, P2._id AS id2, P3._id AS id3,
  137. ifnull(P2.st, 0) AS delivery_status,
  138. ifnull(P3.read_status, 0) AS read_status
  139. FROM pdu P1
  140. INNER JOIN pdu P2
  141. ON P1.m_id = P2.m_id AND P2.m_type = 134
  142. LEFT JOIN pdu P3
  143. ON P1.m_id = P3.m_id AND P3.m_type = 136
  144. UNION
  145. SELECT P1._id AS id1, P2._id AS id2, P3._id AS id3,
  146. ifnull(P2.st, 0) AS delivery_status,
  147. ifnull(P3.read_status, 0) AS read_status
  148. FROM pdu P1
  149. INNER JOIN pdu P3
  150. ON P1.m_id = P3.m_id AND P3.m_type = 136
  151. LEFT JOIN pdu P2
  152. ON P1.m_id = P2.m_id AND P2.m_type = 134) T
  153. ON (msg_id = id2 AND type = 151)
  154. OR (msg_id = id3 AND type = 137)
  155. WHERE T.id1 = ?;
  156. */
  157. qb.setTables("addr INNER JOIN (SELECT P1._id AS id1, P2._id" +
  158. " AS id2, P3._id AS id3, ifnull(P2.st, 0) AS" +
  159. " delivery_status, ifnull(P3.read_status, 0) AS" +
  160. " read_status FROM pdu P1 INNER JOIN pdu P2 ON" +
  161. " P1.m_id=P2.m_id AND P2.m_type=134 LEFT JOIN" +
  162. " pdu P3 ON P1.m_id=P3.m_id AND P3.m_type=136" +
  163. " UNION SELECT P1._id AS id1, P2._id AS id2, P3._id" +
  164. " AS id3, ifnull(P2.st, 0) AS delivery_status," +
  165. " ifnull(P3.read_status, 0) AS read_status FROM" +
  166. " pdu P1 INNER JOIN pdu P3 ON P1.m_id=P3.m_id AND" +
  167. " P3.m_type=136 LEFT JOIN pdu P2 ON P1.m_id=P2.m_id" +
  168. " AND P2.m_type=134) T ON (msg_id=id2 AND type=151)" +
  169. " OR (msg_id=id3 AND type=137)");
  170. qb.appendWhere("T.id1 = " + uri.getLastPathSegment());
  171. qb.setDistinct(true);
  172. break;
  173. case MMS_REPORT_REQUEST:
  174. /*
  175. SELECT address, d_rpt, rr
  176. FROM addr join pdu on pdu._id = addr.msg_id
  177. WHERE pdu._id = messageId AND addr.type = 151
  178. */
  179. qb.setTables(TABLE_ADDR + " join " +
  180. TABLE_PDU + " on pdu._id = addr.msg_id");
  181. qb.appendWhere("pdu._id = " + uri.getLastPathSegment());
  182. qb.appendWhere(" AND " + "addr.type = " + PduHeaders.TO);
  183. break;
  184. case MMS_SENDING_RATE:
  185. qb.setTables(TABLE_RATE);
  186. break;
  187. case MMS_DRM_STORAGE_ID:
  188. qb.setTables(TABLE_DRM);
  189. qb.appendWhere(BaseColumns._ID + "=" + uri.getLastPathSegment());
  190. break;
  191. case MMS_THREADS:
  192. qb.setTables("pdu group by thread_id");
  193. break;
  194. default:
  195. Log.e(TAG, "query: invalid request: " + uri);
  196. return null;
  197. }
  198.  
  199. String finalSortOrder = null;
  200. if (TextUtils.isEmpty(sortOrder)) {
  201. if (qb.getTables().equals(TABLE_PDU)) {
  202. finalSortOrder = Mms.DATE + " DESC";
  203. } else if (qb.getTables().equals(TABLE_PART)) {
  204. finalSortOrder = Part.SEQ;
  205. }
  206. } else {
  207. finalSortOrder = sortOrder;
  208. }
  209.  
  210. if (projection != null) {
  211. for (int i = 0; i < projection.length; i++) {
  212. if (projection[i].equals("sub_id"))
  213. projection[i] = "phone_id";
  214. }
  215. }
  216.  
  217. Cursor ret;
  218. try {
  219. SQLiteDatabase db = mOpenHelper.getReadableDatabase();
  220. ret = qb.query(db, projection, selection,
  221. selectionArgs, null, null, finalSortOrder);
  222. } catch (SQLiteException e) {
  223. Log.e(TAG, "returning NULL cursor, query: " + uri, e);
  224. return null;
  225. }
  226.  
  227. // TODO: Does this need to be a URI for this provider.
  228. ret.setNotificationUri(getContext().getContentResolver(), uri);
  229. return ret;
  230. }
  231.  
  232. private void constructQueryForBox(SQLiteQueryBuilder qb, int msgBox) {
  233. qb.setTables(TABLE_PDU);
  234.  
  235. if (msgBox != Mms.MESSAGE_BOX_ALL) {
  236. qb.appendWhere(Mms.MESSAGE_BOX + "=" + msgBox);
  237. }
  238. }
  239.  
  240. @Override
  241. public String getType(Uri uri) {
  242. int match = sURLMatcher.match(uri);
  243. switch (match) {
  244. case MMS_ALL:
  245. case MMS_INBOX:
  246. case MMS_SENT:
  247. case MMS_DRAFTS:
  248. case MMS_OUTBOX:
  249. return VND_ANDROID_DIR_MMS;
  250. case MMS_ALL_ID:
  251. case MMS_INBOX_ID:
  252. case MMS_SENT_ID:
  253. case MMS_DRAFTS_ID:
  254. case MMS_OUTBOX_ID:
  255. return VND_ANDROID_MMS;
  256. case MMS_PART_ID: {
  257. Cursor cursor = mOpenHelper.getReadableDatabase().query(
  258. TABLE_PART, new String[] { Part.CONTENT_TYPE },
  259. Part._ID + " = ?", new String[] { uri.getLastPathSegment() },
  260. null, null, null);
  261. if (cursor != null) {
  262. try {
  263. if ((cursor.getCount() == 1) && cursor.moveToFirst()) {
  264. return cursor.getString(0);
  265. } else {
  266. Log.e(TAG, "cursor.count() != 1: " + uri);
  267. }
  268. } finally {
  269. cursor.close();
  270. }
  271. } else {
  272. Log.e(TAG, "cursor == null: " + uri);
  273. }
  274. return "*/*";
  275. }
  276. case MMS_ALL_PART:
  277. case MMS_MSG_PART:
  278. case MMS_MSG_ADDR:
  279. default:
  280. return "*/*";
  281. }
  282. }
  283.  
  284. @Override
  285. public Uri insert(Uri uri, ContentValues values) {
  286. // Don't let anyone insert anything with the _data column
  287. if (values != null && values.containsKey(Part._DATA)) {
  288. return null;
  289. }
  290. final int callerUid = Binder.getCallingUid();
  291. int msgBox = Mms.MESSAGE_BOX_ALL;
  292. boolean notify = true;
  293.  
  294. int match = sURLMatcher.match(uri);
  295. if (LOCAL_LOGV) {
  296. Log.v(TAG, "Insert uri=" + uri + ", match=" + match);
  297. }
  298.  
  299. String table = TABLE_PDU;
  300. switch (match) {
  301. case MMS_ALL:
  302. Object msgBoxObj = values.getAsInteger(Mms.MESSAGE_BOX);
  303. if (msgBoxObj != null) {
  304. msgBox = (Integer) msgBoxObj;
  305. }
  306. else {
  307. // default to inbox
  308. msgBox = Mms.MESSAGE_BOX_INBOX;
  309. }
  310. break;
  311. case MMS_INBOX:
  312. msgBox = Mms.MESSAGE_BOX_INBOX;
  313. break;
  314. case MMS_SENT:
  315. msgBox = Mms.MESSAGE_BOX_SENT;
  316. break;
  317. case MMS_DRAFTS:
  318. msgBox = Mms.MESSAGE_BOX_DRAFTS;
  319. break;
  320. case MMS_OUTBOX:
  321. msgBox = Mms.MESSAGE_BOX_OUTBOX;
  322. break;
  323. case MMS_MSG_PART:
  324. notify = false;
  325. table = TABLE_PART;
  326. break;
  327. case MMS_MSG_ADDR:
  328. notify = false;
  329. table = TABLE_ADDR;
  330. break;
  331. case MMS_SENDING_RATE:
  332. notify = false;
  333. table = TABLE_RATE;
  334. break;
  335. case MMS_DRM_STORAGE:
  336. notify = false;
  337. table = TABLE_DRM;
  338. break;
  339. default:
  340. Log.e(TAG, "insert: invalid request: " + uri);
  341. return null;
  342. }
  343.  
  344. SQLiteDatabase db = mOpenHelper.getWritableDatabase();
  345. ContentValues finalValues;
  346. Uri res = Mms.CONTENT_URI;
  347. long rowId;
  348.  
  349. if (table.equals(TABLE_PDU)) {
  350. boolean addDate = !values.containsKey(Mms.DATE);
  351. boolean addMsgBox = !values.containsKey(Mms.MESSAGE_BOX);
  352.  
  353. // Filter keys we don't support yet.
  354. filterUnsupportedKeys(values);
  355.  
  356. // TODO: Should initialValues be validated, e.g. if it
  357. // missed some significant keys?
  358. finalValues = new ContentValues(values);
  359.  
  360. long timeInMillis = System.currentTimeMillis();
  361.  
  362. if (addDate) {
  363. finalValues.put(Mms.DATE, timeInMillis / 1000L);
  364. }
  365.  
  366. if (addMsgBox && (msgBox != Mms.MESSAGE_BOX_ALL)) {
  367. finalValues.put(Mms.MESSAGE_BOX, msgBox);
  368. }
  369.  
  370. if (msgBox != Mms.MESSAGE_BOX_INBOX) {
  371. // Mark all non-inbox messages read.
  372. finalValues.put(Mms.READ, 1);
  373. }
  374.  
  375. // thread_id
  376. Long threadId = values.getAsLong(Mms.THREAD_ID);
  377. String address = values.getAsString(CanonicalAddressesColumns.ADDRESS);
  378.  
  379. if (((threadId == null) || (threadId == 0)) && (!TextUtils.isEmpty(address))) {
  380. finalValues.put(Mms.THREAD_ID, Threads.getOrCreateThreadId(getContext(), address));
  381. }
  382.  
  383. if (ProviderUtil.shouldSetCreator(finalValues, callerUid)) {
  384. // Only SYSTEM or PHONE can set CREATOR
  385. // If caller is not SYSTEM or PHONE, or SYSTEM or PHONE does not set CREATOR
  386. // set CREATOR using the truth on caller.
  387. // Note: Inferring package name from UID may include unrelated package names
  388. finalValues.put(Telephony.Mms.CREATOR,
  389. ProviderUtil.getPackageNamesByUid(getContext(), callerUid));
  390. }
  391.  
  392. if (finalValues.containsKey("sub_id"))
  393. {
  394. int val = finalValues.getAsInteger("sub_id");
  395. finalValues.remove("sub_id");
  396. finalValues.put("phone_id", val);
  397. }
  398.  
  399. if ((rowId = db.insert(table, null, finalValues)) <= 0) {
  400. Log.e(TAG, "MmsProvider.insert: failed!");
  401. return null;
  402. }
  403.  
  404. res = Uri.parse(res + "/" + rowId);
  405. } else if (table.equals(TABLE_ADDR)) {
  406. finalValues = new ContentValues(values);
  407. finalValues.put(Addr.MSG_ID, uri.getPathSegments().get(0));
  408.  
  409. if (finalValues.containsKey("sub_id"))
  410. {
  411. int val = finalValues.getAsInteger("sub_id");
  412. finalValues.remove("sub_id");
  413. finalValues.put("phone_id", val);
  414. }
  415.  
  416. if ((rowId = db.insert(table, null, finalValues)) <= 0) {
  417. Log.e(TAG, "Failed to insert address");
  418. return null;
  419. }
  420.  
  421. res = Uri.parse(res + "/addr/" + rowId);
  422. } else if (table.equals(TABLE_PART)) {
  423. finalValues = new ContentValues(values);
  424.  
  425. if (match == MMS_MSG_PART) {
  426. finalValues.put(Part.MSG_ID, uri.getPathSegments().get(0));
  427. }
  428.  
  429. String contentType = values.getAsString("ct");
  430.  
  431. // text/plain and app application/smil store their "data" inline in the
  432. // table so there's no need to create the file
  433. boolean plainText = false;
  434. boolean smilText = false;
  435. if ("text/plain".equals(contentType)) {
  436. plainText = true;
  437. } else if ("application/smil".equals(contentType)) {
  438. smilText = true;
  439. }
  440. if (!plainText && !smilText) {
  441. // Use the filename if possible, otherwise use the current time as the name.
  442. String contentLocation = values.getAsString("cl");
  443. if (!TextUtils.isEmpty(contentLocation)) {
  444. File f = new File(contentLocation);
  445. contentLocation = "_" + f.getName();
  446. } else {
  447. contentLocation = "";
  448. }
  449.  
  450. // Generate the '_data' field of the part with default
  451. // permission settings.
  452. String path = getContext().getDir("parts", 0).getPath()
  453. + "/PART_" + System.currentTimeMillis() + contentLocation;
  454.  
  455. if (DownloadDrmHelper.isDrmConvertNeeded(contentType)) {
  456. // Adds the .fl extension to the filename if contentType is
  457. // "application/vnd.oma.drm.message"
  458. path = DownloadDrmHelper.modifyDrmFwLockFileExtension(path);
  459. }
  460.  
  461. finalValues.put(Part._DATA, path);
  462.  
  463. File partFile = new File(path);
  464. if (!partFile.exists()) {
  465. try {
  466. if (!partFile.createNewFile()) {
  467. throw new IllegalStateException(
  468. "Unable to create new partFile: " + path);
  469. }
  470. // Give everyone rw permission until we encrypt the file
  471. // (in PduPersister.persistData). Once the file is encrypted, the
  472. // permissions will be set to 0644.
  473. int result = FileUtils.setPermissions(path, 0666, -1, -1);
  474. if (LOCAL_LOGV) {
  475. Log.d(TAG, "MmsProvider.insert setPermissions result: " + result);
  476. }
  477. } catch (IOException e) {
  478. Log.e(TAG, "createNewFile", e);
  479. throw new IllegalStateException(
  480. "Unable to create new partFile: " + path);
  481. }
  482. }
  483. }
  484.  
  485. if (finalValues.containsKey("sub_id"))
  486. {
  487. int val = finalValues.getAsInteger("sub_id");
  488. finalValues.remove("sub_id");
  489. finalValues.put("phone_id", val);
  490. }
  491.  
  492. if ((rowId = db.insert(table, null, finalValues)) <= 0) {
  493. Log.e(TAG, "MmsProvider.insert: failed!");
  494. return null;
  495. }
  496.  
  497. res = Uri.parse(res + "/part/" + rowId);
  498.  
  499. // Don't use a trigger for updating the words table because of a bug
  500. // in FTS3. The bug is such that the call to get the last inserted
  501. // row is incorrect.
  502. if (plainText) {
  503. // Update the words table with a corresponding row. The words table
  504. // allows us to search for words quickly, without scanning the whole
  505. // table;
  506. ContentValues cv = new ContentValues();
  507.  
  508. // we're using the row id of the part table row but we're also using ids
  509. // from the sms table so this divides the space into two large chunks.
  510. // The row ids from the part table start at 2 << 32.
  511. cv.put(Telephony.MmsSms.WordsTable.ID, (2 << 32) + rowId);
  512. cv.put(Telephony.MmsSms.WordsTable.INDEXED_TEXT, values.getAsString("text"));
  513. cv.put(Telephony.MmsSms.WordsTable.SOURCE_ROW_ID, rowId);
  514. cv.put(Telephony.MmsSms.WordsTable.TABLE_ID, 2);
  515. db.insert(TABLE_WORDS, Telephony.MmsSms.WordsTable.INDEXED_TEXT, cv);
  516. }
  517.  
  518. } else if (table.equals(TABLE_RATE)) {
  519. long now = values.getAsLong(Rate.SENT_TIME);
  520. long oneHourAgo = now - 1000 * 60 * 60;
  521. // Delete all unused rows (time earlier than one hour ago).
  522. db.delete(table, Rate.SENT_TIME + "<=" + oneHourAgo, null);
  523. db.insert(table, null, values);
  524. } else if (table.equals(TABLE_DRM)) {
  525. String path = getContext().getDir("parts", 0).getPath()
  526. + "/PART_" + System.currentTimeMillis();
  527. finalValues = new ContentValues(1);
  528. finalValues.put("_data", path);
  529.  
  530. File partFile = new File(path);
  531. if (!partFile.exists()) {
  532. try {
  533. if (!partFile.createNewFile()) {
  534. throw new IllegalStateException(
  535. "Unable to create new file: " + path);
  536. }
  537. } catch (IOException e) {
  538. Log.e(TAG, "createNewFile", e);
  539. throw new IllegalStateException(
  540. "Unable to create new file: " + path);
  541. }
  542. }
  543.  
  544. if ((rowId = db.insert(table, null, finalValues)) <= 0) {
  545. Log.e(TAG, "MmsProvider.insert: failed!");
  546. return null;
  547. }
  548. res = Uri.parse(res + "/drm/" + rowId);
  549. } else {
  550. throw new AssertionError("Unknown table type: " + table);
  551. }
  552.  
  553. if (notify) {
  554. notifyChange();
  555. }
  556. return res;
  557. }
  558.  
  559. private int getMessageBoxByMatch(int match) {
  560. switch (match) {
  561. case MMS_INBOX_ID:
  562. case MMS_INBOX:
  563. return Mms.MESSAGE_BOX_INBOX;
  564. case MMS_SENT_ID:
  565. case MMS_SENT:
  566. return Mms.MESSAGE_BOX_SENT;
  567. case MMS_DRAFTS_ID:
  568. case MMS_DRAFTS:
  569. return Mms.MESSAGE_BOX_DRAFTS;
  570. case MMS_OUTBOX_ID:
  571. case MMS_OUTBOX:
  572. return Mms.MESSAGE_BOX_OUTBOX;
  573. default:
  574. throw new IllegalArgumentException("bad Arg: " + match);
  575. }
  576. }
  577.  
  578. @Override
  579. public int delete(Uri uri, String selection,
  580. String[] selectionArgs) {
  581. int match = sURLMatcher.match(uri);
  582. if (LOCAL_LOGV) {
  583. Log.v(TAG, "Delete uri=" + uri + ", match=" + match);
  584. }
  585.  
  586. String table, extraSelection = null;
  587. boolean notify = false;
  588.  
  589. switch (match) {
  590. case MMS_ALL_ID:
  591. case MMS_INBOX_ID:
  592. case MMS_SENT_ID:
  593. case MMS_DRAFTS_ID:
  594. case MMS_OUTBOX_ID:
  595. notify = true;
  596. table = TABLE_PDU;
  597. extraSelection = Mms._ID + "=" + uri.getLastPathSegment();
  598. break;
  599. case MMS_ALL:
  600. case MMS_INBOX:
  601. case MMS_SENT:
  602. case MMS_DRAFTS:
  603. case MMS_OUTBOX:
  604. notify = true;
  605. table = TABLE_PDU;
  606. if (match != MMS_ALL) {
  607. int msgBox = getMessageBoxByMatch(match);
  608. extraSelection = Mms.MESSAGE_BOX + "=" + msgBox;
  609. }
  610. break;
  611. case MMS_ALL_PART:
  612. table = TABLE_PART;
  613. break;
  614. case MMS_MSG_PART:
  615. table = TABLE_PART;
  616. extraSelection = Part.MSG_ID + "=" + uri.getPathSegments().get(0);
  617. break;
  618. case MMS_PART_ID:
  619. table = TABLE_PART;
  620. extraSelection = Part._ID + "=" + uri.getPathSegments().get(1);
  621. break;
  622. case MMS_MSG_ADDR:
  623. table = TABLE_ADDR;
  624. extraSelection = Addr.MSG_ID + "=" + uri.getPathSegments().get(0);
  625. break;
  626. case MMS_DRM_STORAGE:
  627. table = TABLE_DRM;
  628. break;
  629. case MMS_THREAD_ID:
  630. notify = true;
  631. table = TABLE_PDU;
  632. extraSelection = Mms.THREAD_ID + "=" + uri.getLastPathSegment();
  633. break;
  634. default:
  635. Log.w(TAG, "No match for URI '" + uri + "'");
  636. return 0;
  637. }
  638.  
  639. String finalSelection = concatSelections(selection, extraSelection);
  640. SQLiteDatabase db = mOpenHelper.getWritableDatabase();
  641. int deletedRows = 0;
  642.  
  643. if (TABLE_PDU.equals(table)) {
  644. deletedRows = deleteMessages(getContext(), db, finalSelection,
  645. selectionArgs, uri);
  646. } else if (TABLE_PART.equals(table)) {
  647. deletedRows = deleteParts(db, finalSelection, selectionArgs);
  648. cleanUpWords(db);
  649. updateHasAttachment(db);
  650. } else if (TABLE_DRM.equals(table)) {
  651. deletedRows = deleteTempDrmData(db, finalSelection, selectionArgs);
  652. } else {
  653. deletedRows = db.delete(table, finalSelection, selectionArgs);
  654. }
  655.  
  656. if ((deletedRows > 0) && notify) {
  657. notifyChange();
  658. }
  659. return deletedRows;
  660. }
  661.  
  662. static int deleteMessages(Context context, SQLiteDatabase db,
  663. String selection, String[] selectionArgs, Uri uri) {
  664. Cursor cursor = db.query(TABLE_PDU, new String[] { Mms._ID, Mms.THREAD_ID },
  665. selection, selectionArgs, null, null, null);
  666. if (cursor == null) {
  667. return 0;
  668. }
  669.  
  670. HashSet<Long> threadIds = new HashSet<Long>();
  671. try {
  672. if (cursor.getCount() == 0) {
  673. return 0;
  674. }
  675.  
  676. while (cursor.moveToNext()) {
  677. deleteParts(db, Part.MSG_ID + " = ?",
  678. new String[] { String.valueOf(cursor.getLong(0)) });
  679. threadIds.add(cursor.getLong(1));
  680. }
  681. cleanUpWords(db);
  682. updateHasAttachment(db);
  683. } finally {
  684. cursor.close();
  685. }
  686.  
  687. int count = db.delete(TABLE_PDU, selection, selectionArgs);
  688. for (long thread : threadIds) {
  689. MmsSmsDatabaseHelper.updateThread(db, thread);
  690. }
  691. if (count > 0) {
  692. Intent intent = new Intent(Mms.Intents.CONTENT_CHANGED_ACTION);
  693. intent.putExtra(Mms.Intents.DELETED_CONTENTS, uri);
  694. if (LOCAL_LOGV) {
  695. Log.v(TAG, "Broadcasting intent: " + intent);
  696. }
  697. context.sendBroadcast(intent);
  698. }
  699. return count;
  700. }
  701.  
  702. private static void cleanUpWords(SQLiteDatabase db) {
  703. db.execSQL("DELETE FROM words WHERE source_id not in (select _id from part) AND "
  704. + "table_to_use = 2");
  705. }
  706.  
  707. private static void updateHasAttachment(SQLiteDatabase db) {
  708. db.execSQL("UPDATE threads SET has_attachment = CASE "
  709. + "(SELECT COUNT(*) FROM part JOIN pdu WHERE part.mid = pdu._id AND "
  710. + "pdu.thread_id = threads._id AND part.ct != 'text/plain' "
  711. + "AND part.ct != 'application/smil') WHEN 0 THEN 0 ELSE 1 END");
  712. }
  713.  
  714. private static int deleteParts(SQLiteDatabase db, String selection,
  715. String[] selectionArgs) {
  716. return deleteDataRows(db, TABLE_PART, selection, selectionArgs);
  717. }
  718.  
  719. private static int deleteTempDrmData(SQLiteDatabase db, String selection,
  720. String[] selectionArgs) {
  721. return deleteDataRows(db, TABLE_DRM, selection, selectionArgs);
  722. }
  723.  
  724. private static int deleteDataRows(SQLiteDatabase db, String table,
  725. String selection, String[] selectionArgs) {
  726. Cursor cursor = db.query(table, new String[] { "_data" },
  727. selection, selectionArgs, null, null, null);
  728. if (cursor == null) {
  729. // FIXME: This might be an error, ignore it may cause
  730. // unpredictable result.
  731. return 0;
  732. }
  733.  
  734. try {
  735. if (cursor.getCount() == 0) {
  736. return 0;
  737. }
  738.  
  739. while (cursor.moveToNext()) {
  740. try {
  741. // Delete the associated files saved on file-system.
  742. String path = cursor.getString(0);
  743. if (path != null) {
  744. new File(path).delete();
  745. }
  746. } catch (Throwable ex) {
  747. Log.e(TAG, ex.getMessage(), ex);
  748. }
  749. }
  750. } finally {
  751. cursor.close();
  752. }
  753.  
  754. return db.delete(table, selection, selectionArgs);
  755. }
  756.  
  757. @Override
  758. public int update(Uri uri, ContentValues values,
  759. String selection, String[] selectionArgs) {
  760. // Don't let anyone update the _data column
  761. if (values != null && values.containsKey(Part._DATA)) {
  762. return 0;
  763. }
  764. final int callerUid = Binder.getCallingUid();
  765. int match = sURLMatcher.match(uri);
  766. if (LOCAL_LOGV) {
  767. Log.v(TAG, "Update uri=" + uri + ", match=" + match);
  768. }
  769.  
  770. boolean notify = false;
  771. String msgId = null;
  772. String table;
  773.  
  774. switch (match) {
  775. case MMS_ALL_ID:
  776. case MMS_INBOX_ID:
  777. case MMS_SENT_ID:
  778. case MMS_DRAFTS_ID:
  779. case MMS_OUTBOX_ID:
  780. msgId = uri.getLastPathSegment();
  781. // fall-through
  782. case MMS_ALL:
  783. case MMS_INBOX:
  784. case MMS_SENT:
  785. case MMS_DRAFTS:
  786. case MMS_OUTBOX:
  787. notify = true;
  788. table = TABLE_PDU;
  789. break;
  790.  
  791. case MMS_MSG_PART:
  792. case MMS_PART_ID:
  793. table = TABLE_PART;
  794. break;
  795.  
  796. case MMS_PART_RESET_FILE_PERMISSION:
  797. String path = getContext().getDir("parts", 0).getPath() + '/' +
  798. uri.getPathSegments().get(1);
  799. // Reset the file permission back to read for everyone but me.
  800. int result = FileUtils.setPermissions(path, 0644, -1, -1);
  801. if (LOCAL_LOGV) {
  802. Log.d(TAG, "MmsProvider.update setPermissions result: " + result +
  803. " for path: " + path);
  804. }
  805. return 0;
  806.  
  807. default:
  808. Log.w(TAG, "Update operation for '" + uri + "' not implemented.");
  809. return 0;
  810. }
  811.  
  812. String extraSelection = null;
  813. ContentValues finalValues;
  814. if (table.equals(TABLE_PDU)) {
  815. // Filter keys that we don't support yet.
  816. filterUnsupportedKeys(values);
  817. if (ProviderUtil.shouldRemoveCreator(values, callerUid)) {
  818. // CREATOR should not be changed by non-SYSTEM/PHONE apps
  819. Log.w(TAG, ProviderUtil.getPackageNamesByUid(getContext(), callerUid) +
  820. " tries to update CREATOR");
  821. values.remove(Mms.CREATOR);
  822. }
  823. finalValues = new ContentValues(values);
  824.  
  825. if (msgId != null) {
  826. extraSelection = Mms._ID + "=" + msgId;
  827. }
  828. } else if (table.equals(TABLE_PART)) {
  829. finalValues = new ContentValues(values);
  830.  
  831. switch (match) {
  832. case MMS_MSG_PART:
  833. extraSelection = Part.MSG_ID + "=" + uri.getPathSegments().get(0);
  834. break;
  835. case MMS_PART_ID:
  836. extraSelection = Part._ID + "=" + uri.getPathSegments().get(1);
  837. break;
  838. default:
  839. break;
  840. }
  841. } else {
  842. return 0;
  843. }
  844.  
  845. String finalSelection = concatSelections(selection, extraSelection);
  846. SQLiteDatabase db = mOpenHelper.getWritableDatabase();
  847. int count = db.update(table, finalValues, finalSelection, selectionArgs);
  848. if (notify && (count > 0)) {
  849. notifyChange();
  850. }
  851. return count;
  852. }
  853.  
  854. @Override
  855. public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
  856. int match = sURLMatcher.match(uri);
  857.  
  858. if (Log.isLoggable(TAG, Log.VERBOSE)) {
  859. Log.d(TAG, "openFile: uri=" + uri + ", mode=" + mode + ", match=" + match);
  860. }
  861.  
  862. if (match != MMS_PART_ID) {
  863. return null;
  864. }
  865.  
  866. // Verify that the _data path points to mms data
  867. Cursor c = query(uri, new String[]{"_data"}, null, null, null);
  868. int count = (c != null) ? c.getCount() : 0;
  869. if (count != 1) {
  870. // If there is not exactly one result, throw an appropriate
  871. // exception.
  872. if (c != null) {
  873. c.close();
  874. }
  875. if (count == 0) {
  876. throw new FileNotFoundException("No entry for " + uri);
  877. }
  878. throw new FileNotFoundException("Multiple items at " + uri);
  879. }
  880.  
  881. c.moveToFirst();
  882. int i = c.getColumnIndex("_data");
  883. String path = (i >= 0 ? c.getString(i) : null);
  884. c.close();
  885.  
  886. if (path == null) {
  887. return null;
  888. }
  889. try {
  890. File filePath = new File(path);
  891. if (!filePath.getCanonicalPath()
  892. .startsWith(getContext().getApplicationInfo().dataDir + "/app_parts/")) {
  893. return null;
  894. }
  895. } catch (IOException e) {
  896. return null;
  897. }
  898.  
  899. return openFileHelper(uri, mode);
  900. }
  901.  
  902. private void filterUnsupportedKeys(ContentValues values) {
  903. // Some columns are unsupported. They should therefore
  904. // neither be inserted nor updated. Filter them out.
  905. values.remove(Mms.DELIVERY_TIME_TOKEN);
  906. values.remove(Mms.SENDER_VISIBILITY);
  907. values.remove(Mms.REPLY_CHARGING);
  908. values.remove(Mms.REPLY_CHARGING_DEADLINE_TOKEN);
  909. values.remove(Mms.REPLY_CHARGING_DEADLINE);
  910. values.remove(Mms.REPLY_CHARGING_ID);
  911. values.remove(Mms.REPLY_CHARGING_SIZE);
  912. values.remove(Mms.PREVIOUSLY_SENT_BY);
  913. values.remove(Mms.PREVIOUSLY_SENT_DATE);
  914. values.remove(Mms.STORE);
  915. values.remove(Mms.MM_STATE);
  916. values.remove(Mms.MM_FLAGS_TOKEN);
  917. values.remove(Mms.MM_FLAGS);
  918. values.remove(Mms.STORE_STATUS);
  919. values.remove(Mms.STORE_STATUS_TEXT);
  920. values.remove(Mms.STORED);
  921. values.remove(Mms.TOTALS);
  922. values.remove(Mms.MBOX_TOTALS);
  923. values.remove(Mms.MBOX_TOTALS_TOKEN);
  924. values.remove(Mms.QUOTAS);
  925. values.remove(Mms.MBOX_QUOTAS);
  926. values.remove(Mms.MBOX_QUOTAS_TOKEN);
  927. values.remove(Mms.MESSAGE_COUNT);
  928. values.remove(Mms.START);
  929. values.remove(Mms.DISTRIBUTION_INDICATOR);
  930. values.remove(Mms.ELEMENT_DESCRIPTOR);
  931. values.remove(Mms.LIMIT);
  932. values.remove(Mms.RECOMMENDED_RETRIEVAL_MODE);
  933. values.remove(Mms.RECOMMENDED_RETRIEVAL_MODE_TEXT);
  934. values.remove(Mms.STATUS_TEXT);
  935. values.remove(Mms.APPLIC_ID);
  936. values.remove(Mms.REPLY_APPLIC_ID);
  937. values.remove(Mms.AUX_APPLIC_ID);
  938. values.remove(Mms.DRM_CONTENT);
  939. values.remove(Mms.ADAPTATION_ALLOWED);
  940. values.remove(Mms.REPLACE_ID);
  941. values.remove(Mms.CANCEL_ID);
  942. values.remove(Mms.CANCEL_STATUS);
  943.  
  944. // Keys shouldn't be inserted or updated.
  945. values.remove(Mms._ID);
  946. }
  947.  
  948. private void notifyChange() {
  949. getContext().getContentResolver().notifyChange(
  950. MmsSms.CONTENT_URI, null, true, UserHandle.USER_ALL);
  951. }
  952.  
  953. private final static String TAG = "MmsProvider";
  954. private final static String VND_ANDROID_MMS = "vnd.android/mms";
  955. private final static String VND_ANDROID_DIR_MMS = "vnd.android-dir/mms";
  956. private final static boolean DEBUG = false;
  957. private final static boolean LOCAL_LOGV = false;
  958.  
  959. private static final int MMS_ALL = 0;
  960. private static final int MMS_ALL_ID = 1;
  961. private static final int MMS_INBOX = 2;
  962. private static final int MMS_INBOX_ID = 3;
  963. private static final int MMS_SENT = 4;
  964. private static final int MMS_SENT_ID = 5;
  965. private static final int MMS_DRAFTS = 6;
  966. private static final int MMS_DRAFTS_ID = 7;
  967. private static final int MMS_OUTBOX = 8;
  968. private static final int MMS_OUTBOX_ID = 9;
  969. private static final int MMS_ALL_PART = 10;
  970. private static final int MMS_MSG_PART = 11;
  971. private static final int MMS_PART_ID = 12;
  972. private static final int MMS_MSG_ADDR = 13;
  973. private static final int MMS_SENDING_RATE = 14;
  974. private static final int MMS_REPORT_STATUS = 15;
  975. private static final int MMS_REPORT_REQUEST = 16;
  976. private static final int MMS_DRM_STORAGE = 17;
  977. private static final int MMS_DRM_STORAGE_ID = 18;
  978. private static final int MMS_THREADS = 19;
  979. private static final int MMS_PART_RESET_FILE_PERMISSION = 20;
  980. private static final int MMS_THREAD_ID = 21;
  981.  
  982. private static final UriMatcher
  983. sURLMatcher = new UriMatcher(UriMatcher.NO_MATCH);
  984.  
  985. static {
  986. sURLMatcher.addURI("mms", null, MMS_ALL);
  987. sURLMatcher.addURI("mms", "#", MMS_ALL_ID);
  988. sURLMatcher.addURI("mms", "inbox", MMS_INBOX);
  989. sURLMatcher.addURI("mms", "inbox/#", MMS_INBOX_ID);
  990. sURLMatcher.addURI("mms", "sent", MMS_SENT);
  991. sURLMatcher.addURI("mms", "sent/#", MMS_SENT_ID);
  992. sURLMatcher.addURI("mms", "drafts", MMS_DRAFTS);
  993. sURLMatcher.addURI("mms", "drafts/#", MMS_DRAFTS_ID);
  994. sURLMatcher.addURI("mms", "outbox", MMS_OUTBOX);
  995. sURLMatcher.addURI("mms", "outbox/#", MMS_OUTBOX_ID);
  996. sURLMatcher.addURI("mms", "part", MMS_ALL_PART);
  997. sURLMatcher.addURI("mms", "#/part", MMS_MSG_PART);
  998. sURLMatcher.addURI("mms", "part/#", MMS_PART_ID);
  999. sURLMatcher.addURI("mms", "#/addr", MMS_MSG_ADDR);
  1000. sURLMatcher.addURI("mms", "rate", MMS_SENDING_RATE);
  1001. sURLMatcher.addURI("mms", "report-status/#", MMS_REPORT_STATUS);
  1002. sURLMatcher.addURI("mms", "report-request/#", MMS_REPORT_REQUEST);
  1003. sURLMatcher.addURI("mms", "drm", MMS_DRM_STORAGE);
  1004. sURLMatcher.addURI("mms", "drm/#", MMS_DRM_STORAGE_ID);
  1005. sURLMatcher.addURI("mms", "threads", MMS_THREADS);
  1006. sURLMatcher.addURI("mms", "resetFilePerm/*", MMS_PART_RESET_FILE_PERMISSION);
  1007. sURLMatcher.addURI("mms", "thread/#", MMS_THREAD_ID);
  1008. }
  1009.  
  1010. private SQLiteOpenHelper mOpenHelper;
  1011.  
  1012. private static String concatSelections(String selection1, String selection2) {
  1013. if (TextUtils.isEmpty(selection1)) {
  1014. return selection2;
  1015. } else if (TextUtils.isEmpty(selection2)) {
  1016. return selection1;
  1017. } else {
  1018. return selection1 + " AND " + selection2;
  1019. }
  1020. }
  1021. }
Advertisement
Add Comment
Please, Sign In to add comment