org.sandrob.bouncycastle.jce.spec.ECParameterSpec engineGetSpec() { if (ecSpec != null) { return EC5Util.convertSpec(ecSpec, withCompression); } return ProviderUtil.getEcImplicitlyCa(); }
@Override public Endpoint loadEndpoint(RepositoryInformation repoInfo) throws FedXException { File store = FileUtil.getFileLocation(repoInfo.getLocation()); if (!store.exists()) { throw new FedXRuntimeException( "Store does not exist at '" + repoInfo.getLocation() + ": " + store.getAbsolutePath() + "'."); } try { NativeStore ns = new NativeStoreExt(store); SailRepository repo = new SailRepository(ns); repo.initialize(); ProviderUtil.checkConnectionIfConfigured(repo); Endpoint res = new Endpoint( repoInfo.getId(), repoInfo.getName(), repoInfo.getLocation(), repoInfo.getType(), EndpointClassification.Local); res.setEndpointConfiguration(repoInfo.getEndpointConfiguration()); res.setRepo(repo); // register a federated service manager to deal with this endpoint SAILFederatedService federatedService = new SAILFederatedService(res); federatedService.initialize(); FederatedServiceManager.getInstance().registerService(repoInfo.getName(), federatedService); return res; } catch (RepositoryException e) { throw new FedXException( "Repository " + repoInfo.getId() + " could not be initialized: " + e.getMessage(), e); } }
private void notifyChange(final Uri uri) { final Context context = getContext(); context.getContentResolver().notifyChange(MmsSms.CONTENT_URI, null, true, UserHandle.USER_ALL); ProviderUtil.notifyIfNotDefaultSmsApp(uri, getCallingPackage(), context); }
@Override public Cursor query( Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { // First check if a restricted view of the "pdu" table should be used based on the // caller's identity. Only system, phone or the default sms app can have full access // of mms data. For other apps, we present a restricted view which only contains sent // or received messages, without wap pushes. final boolean accessRestricted = ProviderUtil.isAccessRestricted(getContext(), getCallingPackage(), Binder.getCallingUid()); final String pduTable = getPduTable(accessRestricted); SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); // Generate the body of the query. int match = sURLMatcher.match(uri); if (LOCAL_LOGV) { Log.v(TAG, "Query uri=" + uri + ", match=" + match); } switch (match) { case MMS_ALL: constructQueryForBox(qb, Mms.MESSAGE_BOX_ALL, pduTable); break; case MMS_INBOX: constructQueryForBox(qb, Mms.MESSAGE_BOX_INBOX, pduTable); break; case MMS_SENT: constructQueryForBox(qb, Mms.MESSAGE_BOX_SENT, pduTable); break; case MMS_DRAFTS: constructQueryForBox(qb, Mms.MESSAGE_BOX_DRAFTS, pduTable); break; case MMS_OUTBOX: constructQueryForBox(qb, Mms.MESSAGE_BOX_OUTBOX, pduTable); break; case MMS_ALL_ID: qb.setTables(pduTable); qb.appendWhere(Mms._ID + "=" + uri.getPathSegments().get(0)); break; case MMS_INBOX_ID: case MMS_SENT_ID: case MMS_DRAFTS_ID: case MMS_OUTBOX_ID: qb.setTables(pduTable); qb.appendWhere(Mms._ID + "=" + uri.getPathSegments().get(1)); qb.appendWhere(" AND " + Mms.MESSAGE_BOX + "=" + getMessageBoxByMatch(match)); break; case MMS_ALL_PART: qb.setTables(TABLE_PART); break; case MMS_MSG_PART: qb.setTables(TABLE_PART); qb.appendWhere(Part.MSG_ID + "=" + uri.getPathSegments().get(0)); break; case MMS_PART_ID: qb.setTables(TABLE_PART); qb.appendWhere(Part._ID + "=" + uri.getPathSegments().get(1)); break; case MMS_MSG_ADDR: qb.setTables(TABLE_ADDR); qb.appendWhere(Addr.MSG_ID + "=" + uri.getPathSegments().get(0)); break; case MMS_REPORT_STATUS: /* SELECT DISTINCT address, T.delivery_status AS delivery_status, T.read_status AS read_status FROM addr INNER JOIN (SELECT P1._id AS id1, P2._id AS id2, P3._id AS id3, ifnull(P2.st, 0) AS delivery_status, ifnull(P3.read_status, 0) AS read_status FROM pdu P1 INNER JOIN pdu P2 ON P1.m_id = P2.m_id AND P2.m_type = 134 LEFT JOIN pdu P3 ON P1.m_id = P3.m_id AND P3.m_type = 136 UNION SELECT P1._id AS id1, P2._id AS id2, P3._id AS id3, ifnull(P2.st, 0) AS delivery_status, ifnull(P3.read_status, 0) AS read_status FROM pdu P1 INNER JOIN pdu P3 ON P1.m_id = P3.m_id AND P3.m_type = 136 LEFT JOIN pdu P2 ON P1.m_id = P2.m_id AND P2.m_type = 134) T ON (msg_id = id2 AND type = 151) OR (msg_id = id3 AND type = 137) WHERE T.id1 = ?; */ qb.setTables( TABLE_ADDR + " INNER JOIN " + "(SELECT P1._id AS id1, P2._id AS id2, P3._id AS id3, " + "ifnull(P2.st, 0) AS delivery_status, " + "ifnull(P3.read_status, 0) AS read_status " + "FROM " + pduTable + " P1 INNER JOIN " + pduTable + " P2 " + "ON P1.m_id=P2.m_id AND P2.m_type=134 " + "LEFT JOIN " + pduTable + " P3 " + "ON P1.m_id=P3.m_id AND P3.m_type=136 " + "UNION " + "SELECT P1._id AS id1, P2._id AS id2, P3._id AS id3, " + "ifnull(P2.st, 0) AS delivery_status, " + "ifnull(P3.read_status, 0) AS read_status " + "FROM " + pduTable + " P1 INNER JOIN " + pduTable + " P3 " + "ON P1.m_id=P3.m_id AND P3.m_type=136 " + "LEFT JOIN " + pduTable + " P2 " + "ON P1.m_id=P2.m_id AND P2.m_type=134) T " + "ON (msg_id=id2 AND type=151) OR (msg_id=id3 AND type=137)"); qb.appendWhere("T.id1 = " + uri.getLastPathSegment()); qb.setDistinct(true); break; case MMS_REPORT_REQUEST: /* SELECT address, d_rpt, rr FROM addr join pdu on pdu._id = addr.msg_id WHERE pdu._id = messageId AND addr.type = 151 */ qb.setTables(TABLE_ADDR + " join " + pduTable + " on " + pduTable + "._id = addr.msg_id"); qb.appendWhere(pduTable + "._id = " + uri.getLastPathSegment()); qb.appendWhere(" AND " + TABLE_ADDR + ".type = " + PduHeaders.TO); break; case MMS_SENDING_RATE: qb.setTables(TABLE_RATE); break; case MMS_DRM_STORAGE_ID: qb.setTables(TABLE_DRM); qb.appendWhere(BaseColumns._ID + "=" + uri.getLastPathSegment()); break; case MMS_THREADS: qb.setTables(pduTable + " group by thread_id"); break; default: Log.e(TAG, "query: invalid request: " + uri); return null; } String finalSortOrder = null; if (TextUtils.isEmpty(sortOrder)) { if (qb.getTables().equals(pduTable)) { finalSortOrder = Mms.DATE + " DESC"; } else if (qb.getTables().equals(TABLE_PART)) { finalSortOrder = Part.SEQ; } } else { finalSortOrder = sortOrder; } Cursor ret; try { SQLiteDatabase db = mOpenHelper.getReadableDatabase(); ret = qb.query(db, projection, selection, selectionArgs, null, null, finalSortOrder); } catch (SQLiteException e) { Log.e(TAG, "returning NULL cursor, query: " + uri, e); return null; } // TODO: Does this need to be a URI for this provider. ret.setNotificationUri(getContext().getContentResolver(), uri); return ret; }
@Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { // The _data column is filled internally in MmsProvider, so this check is just to avoid // it from being inadvertently set. This is not supposed to be a protection against // malicious attack, since sql injection could still be attempted to bypass the check. On // the other hand, the MmsProvider does verify that the _data column has an allowed value // before opening any uri/files. if (values != null && values.containsKey(Part._DATA)) { return 0; } final int callerUid = Binder.getCallingUid(); final String callerPkg = getCallingPackage(); int match = sURLMatcher.match(uri); if (LOCAL_LOGV) { Log.v(TAG, "Update uri=" + uri + ", match=" + match); } boolean notify = false; String msgId = null; String table; switch (match) { case MMS_ALL_ID: case MMS_INBOX_ID: case MMS_SENT_ID: case MMS_DRAFTS_ID: case MMS_OUTBOX_ID: msgId = uri.getLastPathSegment(); // fall-through case MMS_ALL: case MMS_INBOX: case MMS_SENT: case MMS_DRAFTS: case MMS_OUTBOX: notify = true; table = TABLE_PDU; break; case MMS_MSG_PART: case MMS_PART_ID: table = TABLE_PART; break; case MMS_PART_RESET_FILE_PERMISSION: String path = getContext().getDir(PARTS_DIR_NAME, 0).getPath() + '/' + uri.getPathSegments().get(1); // Reset the file permission back to read for everyone but me. int result = FileUtils.setPermissions(path, 0644, -1, -1); if (LOCAL_LOGV) { Log.d(TAG, "MmsProvider.update setPermissions result: " + result + " for path: " + path); } return 0; default: Log.w(TAG, "Update operation for '" + uri + "' not implemented."); return 0; } String extraSelection = null; ContentValues finalValues; if (table.equals(TABLE_PDU)) { // Filter keys that we don't support yet. filterUnsupportedKeys(values); if (ProviderUtil.shouldRemoveCreator(values, callerUid)) { // CREATOR should not be changed by non-SYSTEM/PHONE apps Log.w(TAG, callerPkg + " tries to update CREATOR"); values.remove(Mms.CREATOR); } finalValues = new ContentValues(values); if (msgId != null) { extraSelection = Mms._ID + "=" + msgId; } } else if (table.equals(TABLE_PART)) { finalValues = new ContentValues(values); switch (match) { case MMS_MSG_PART: extraSelection = Part.MSG_ID + "=" + uri.getPathSegments().get(0); break; case MMS_PART_ID: extraSelection = Part._ID + "=" + uri.getPathSegments().get(1); break; default: break; } } else { return 0; } String finalSelection = concatSelections(selection, extraSelection); SQLiteDatabase db = mOpenHelper.getWritableDatabase(); int count = db.update(table, finalValues, finalSelection, selectionArgs); if (notify && (count > 0)) { notifyChange(uri); } return count; }
@Override public Uri insert(Uri uri, ContentValues values) { // The _data column is filled internally in MmsProvider, so this check is just to avoid // it from being inadvertently set. This is not supposed to be a protection against // malicious attack, since sql injection could still be attempted to bypass the check. On // the other hand, the MmsProvider does verify that the _data column has an allowed value // before opening any uri/files. if (values != null && values.containsKey(Part._DATA)) { return null; } final int callerUid = Binder.getCallingUid(); final String callerPkg = getCallingPackage(); int msgBox = Mms.MESSAGE_BOX_ALL; boolean notify = true; int match = sURLMatcher.match(uri); if (LOCAL_LOGV) { Log.v(TAG, "Insert uri=" + uri + ", match=" + match); } String table = TABLE_PDU; switch (match) { case MMS_ALL: Object msgBoxObj = values.getAsInteger(Mms.MESSAGE_BOX); if (msgBoxObj != null) { msgBox = (Integer) msgBoxObj; } else { // default to inbox msgBox = Mms.MESSAGE_BOX_INBOX; } break; case MMS_INBOX: msgBox = Mms.MESSAGE_BOX_INBOX; break; case MMS_SENT: msgBox = Mms.MESSAGE_BOX_SENT; break; case MMS_DRAFTS: msgBox = Mms.MESSAGE_BOX_DRAFTS; break; case MMS_OUTBOX: msgBox = Mms.MESSAGE_BOX_OUTBOX; break; case MMS_MSG_PART: notify = false; table = TABLE_PART; break; case MMS_MSG_ADDR: notify = false; table = TABLE_ADDR; break; case MMS_SENDING_RATE: notify = false; table = TABLE_RATE; break; case MMS_DRM_STORAGE: notify = false; table = TABLE_DRM; break; default: Log.e(TAG, "insert: invalid request: " + uri); return null; } SQLiteDatabase db = mOpenHelper.getWritableDatabase(); ContentValues finalValues; Uri res = Mms.CONTENT_URI; long rowId; if (table.equals(TABLE_PDU)) { boolean addDate = !values.containsKey(Mms.DATE); boolean addMsgBox = !values.containsKey(Mms.MESSAGE_BOX); // Filter keys we don't support yet. filterUnsupportedKeys(values); // TODO: Should initialValues be validated, e.g. if it // missed some significant keys? finalValues = new ContentValues(values); long timeInMillis = System.currentTimeMillis(); if (addDate) { finalValues.put(Mms.DATE, timeInMillis / 1000L); } if (addMsgBox && (msgBox != Mms.MESSAGE_BOX_ALL)) { finalValues.put(Mms.MESSAGE_BOX, msgBox); } if (msgBox != Mms.MESSAGE_BOX_INBOX) { // Mark all non-inbox messages read. finalValues.put(Mms.READ, 1); } // thread_id Long threadId = values.getAsLong(Mms.THREAD_ID); String address = values.getAsString(CanonicalAddressesColumns.ADDRESS); if (((threadId == null) || (threadId == 0)) && (!TextUtils.isEmpty(address))) { finalValues.put(Mms.THREAD_ID, Threads.getOrCreateThreadId(getContext(), address)); } if (ProviderUtil.shouldSetCreator(finalValues, callerUid)) { // Only SYSTEM or PHONE can set CREATOR // If caller is not SYSTEM or PHONE, or SYSTEM or PHONE does not set CREATOR // set CREATOR using the truth on caller. // Note: Inferring package name from UID may include unrelated package names finalValues.put(Telephony.Mms.CREATOR, callerPkg); } if ((rowId = db.insert(table, null, finalValues)) <= 0) { Log.e(TAG, "MmsProvider.insert: failed!"); return null; } res = Uri.parse(res + "/" + rowId); } else if (table.equals(TABLE_ADDR)) { finalValues = new ContentValues(values); finalValues.put(Addr.MSG_ID, uri.getPathSegments().get(0)); if ((rowId = db.insert(table, null, finalValues)) <= 0) { Log.e(TAG, "Failed to insert address"); return null; } res = Uri.parse(res + "/addr/" + rowId); } else if (table.equals(TABLE_PART)) { finalValues = new ContentValues(values); if (match == MMS_MSG_PART) { finalValues.put(Part.MSG_ID, uri.getPathSegments().get(0)); } String contentType = values.getAsString("ct"); // text/plain and app application/smil store their "data" inline in the // table so there's no need to create the file boolean plainText = false; boolean smilText = false; if ("text/plain".equals(contentType)) { plainText = true; } else if ("application/smil".equals(contentType)) { smilText = true; } if (!plainText && !smilText) { // Use the filename if possible, otherwise use the current time as the name. String contentLocation = values.getAsString("cl"); if (!TextUtils.isEmpty(contentLocation)) { File f = new File(contentLocation); contentLocation = "_" + f.getName(); } else { contentLocation = ""; } // Generate the '_data' field of the part with default // permission settings. String path = getContext().getDir(PARTS_DIR_NAME, 0).getPath() + "/PART_" + System.currentTimeMillis() + contentLocation; if (DownloadDrmHelper.isDrmConvertNeeded(contentType)) { // Adds the .fl extension to the filename if contentType is // "application/vnd.oma.drm.message" path = DownloadDrmHelper.modifyDrmFwLockFileExtension(path); } finalValues.put(Part._DATA, path); File partFile = new File(path); if (!partFile.exists()) { try { if (!partFile.createNewFile()) { throw new IllegalStateException("Unable to create new partFile: " + path); } // Give everyone rw permission until we encrypt the file // (in PduPersister.persistData). Once the file is encrypted, the // permissions will be set to 0644. int result = FileUtils.setPermissions(path, 0666, -1, -1); if (LOCAL_LOGV) { Log.d(TAG, "MmsProvider.insert setPermissions result: " + result); } } catch (IOException e) { Log.e(TAG, "createNewFile", e); throw new IllegalStateException("Unable to create new partFile: " + path); } } } if ((rowId = db.insert(table, null, finalValues)) <= 0) { Log.e(TAG, "MmsProvider.insert: failed!"); return null; } res = Uri.parse(res + "/part/" + rowId); // Don't use a trigger for updating the words table because of a bug // in FTS3. The bug is such that the call to get the last inserted // row is incorrect. if (plainText) { // Update the words table with a corresponding row. The words table // allows us to search for words quickly, without scanning the whole // table; ContentValues cv = new ContentValues(); // we're using the row id of the part table row but we're also using ids // from the sms table so this divides the space into two large chunks. // The row ids from the part table start at 2 << 32. cv.put(Telephony.MmsSms.WordsTable.ID, (2L << 32) + rowId); cv.put(Telephony.MmsSms.WordsTable.INDEXED_TEXT, values.getAsString("text")); cv.put(Telephony.MmsSms.WordsTable.SOURCE_ROW_ID, rowId); cv.put(Telephony.MmsSms.WordsTable.TABLE_ID, 2); db.insert(TABLE_WORDS, Telephony.MmsSms.WordsTable.INDEXED_TEXT, cv); } } else if (table.equals(TABLE_RATE)) { long now = values.getAsLong(Rate.SENT_TIME); long oneHourAgo = now - 1000 * 60 * 60; // Delete all unused rows (time earlier than one hour ago). db.delete(table, Rate.SENT_TIME + "<=" + oneHourAgo, null); db.insert(table, null, values); } else if (table.equals(TABLE_DRM)) { String path = getContext().getDir(PARTS_DIR_NAME, 0).getPath() + "/PART_" + System.currentTimeMillis(); finalValues = new ContentValues(1); finalValues.put("_data", path); File partFile = new File(path); if (!partFile.exists()) { try { if (!partFile.createNewFile()) { throw new IllegalStateException("Unable to create new file: " + path); } } catch (IOException e) { Log.e(TAG, "createNewFile", e); throw new IllegalStateException("Unable to create new file: " + path); } } if ((rowId = db.insert(table, null, finalValues)) <= 0) { Log.e(TAG, "MmsProvider.insert: failed!"); return null; } res = Uri.parse(res + "/drm/" + rowId); } else { throw new AssertionError("Unknown table type: " + table); } if (notify) { notifyChange(res); } return res; }
@Override public int update(Uri url, ContentValues values, String where, String[] whereArgs) { final int callerUid = Binder.getCallingUid(); int count = 0; String table = TABLE_SMS; String extraWhere = null; SQLiteDatabase db = mOpenHelper.getWritableDatabase(); switch (sURLMatcher.match(url)) { case SMS_RAW_MESSAGE: table = TABLE_RAW; break; case SMS_STATUS_PENDING: table = TABLE_SR_PENDING; break; case SMS_ALL: case SMS_FAILED: case SMS_QUEUED: case SMS_INBOX: case SMS_SENT: case SMS_DRAFT: case SMS_OUTBOX: case SMS_CONVERSATIONS: break; case SMS_ALL_ID: extraWhere = "_id=" + url.getPathSegments().get(0); break; case SMS_INBOX_ID: case SMS_FAILED_ID: case SMS_SENT_ID: case SMS_DRAFT_ID: case SMS_OUTBOX_ID: extraWhere = "_id=" + url.getPathSegments().get(1); break; case SMS_CONVERSATIONS_ID: { String threadId = url.getPathSegments().get(1); try { Integer.parseInt(threadId); } catch (Exception ex) { Log.e(TAG, "Bad conversation thread id: " + threadId); break; } extraWhere = "thread_id=" + threadId; break; } case SMS_STATUS_ID: extraWhere = "_id=" + url.getPathSegments().get(1); break; default: throw new UnsupportedOperationException("URI " + url + " not supported"); } if (table.equals(TABLE_SMS) && ProviderUtil.shouldRemoveCreator(values, callerUid)) { // CREATOR should not be changed by non-SYSTEM/PHONE apps Log.w( TAG, ProviderUtil.getPackageNamesByUid(getContext(), callerUid) + " tries to update CREATOR"); values.remove(Sms.CREATOR); } where = DatabaseUtils.concatenateWhere(where, extraWhere); count = db.update(table, values, where, whereArgs); if (count > 0) { if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.d(TAG, "update " + url + " succeeded"); } notifyChange(url); } return count; }
private Uri insertInner(Uri url, ContentValues initialValues, int callerUid) { ContentValues values; long rowID; int type = Sms.MESSAGE_TYPE_ALL; int match = sURLMatcher.match(url); String table = TABLE_SMS; switch (match) { case SMS_ALL: Integer typeObj = initialValues.getAsInteger(Sms.TYPE); if (typeObj != null) { type = typeObj.intValue(); } else { // default to inbox type = Sms.MESSAGE_TYPE_INBOX; } break; case SMS_INBOX: type = Sms.MESSAGE_TYPE_INBOX; break; case SMS_FAILED: type = Sms.MESSAGE_TYPE_FAILED; break; case SMS_QUEUED: type = Sms.MESSAGE_TYPE_QUEUED; break; case SMS_SENT: type = Sms.MESSAGE_TYPE_SENT; break; case SMS_DRAFT: type = Sms.MESSAGE_TYPE_DRAFT; break; case SMS_OUTBOX: type = Sms.MESSAGE_TYPE_OUTBOX; break; case SMS_RAW_MESSAGE: table = "raw"; break; case SMS_STATUS_PENDING: table = "sr_pending"; break; case SMS_ATTACHMENT: table = "attachments"; break; case SMS_NEW_THREAD_ID: table = "canonical_addresses"; break; default: Log.e(TAG, "Invalid request: " + url); return null; } SQLiteDatabase db = mOpenHelper.getWritableDatabase(); if (table.equals(TABLE_SMS)) { boolean addDate = false; boolean addType = false; // Make sure that the date and type are set if (initialValues == null) { values = new ContentValues(1); addDate = true; addType = true; } else { values = new ContentValues(initialValues); if (!initialValues.containsKey(Sms.DATE)) { addDate = true; } if (!initialValues.containsKey(Sms.TYPE)) { addType = true; } } if (addDate) { values.put(Sms.DATE, new Long(System.currentTimeMillis())); } if (addType && (type != Sms.MESSAGE_TYPE_ALL)) { values.put(Sms.TYPE, Integer.valueOf(type)); } // thread_id Long threadId = values.getAsLong(Sms.THREAD_ID); String address = values.getAsString(Sms.ADDRESS); if (((threadId == null) || (threadId == 0)) && (!TextUtils.isEmpty(address))) { values.put(Sms.THREAD_ID, Threads.getOrCreateThreadId(getContext(), address)); } // If this message is going in as a draft, it should replace any // other draft messages in the thread. Just delete all draft // messages with this thread ID. We could add an OR REPLACE to // the insert below, but we'd have to query to find the old _id // to produce a conflict anyway. if (values.getAsInteger(Sms.TYPE) == Sms.MESSAGE_TYPE_DRAFT) { db.delete( TABLE_SMS, "thread_id=? AND type=?", new String[] { values.getAsString(Sms.THREAD_ID), Integer.toString(Sms.MESSAGE_TYPE_DRAFT) }); } if (type == Sms.MESSAGE_TYPE_INBOX) { // Look up the person if not already filled in. if ((values.getAsLong(Sms.PERSON) == null) && (!TextUtils.isEmpty(address))) { Cursor cursor = null; Uri uri = Uri.withAppendedPath(Contacts.Phones.CONTENT_FILTER_URL, Uri.encode(address)); try { cursor = getContext() .getContentResolver() .query(uri, CONTACT_QUERY_PROJECTION, null, null, null); if (cursor.moveToFirst()) { Long id = Long.valueOf(cursor.getLong(PERSON_ID_COLUMN)); values.put(Sms.PERSON, id); } } catch (Exception ex) { Log.e(TAG, "insert: query contact uri " + uri + " caught ", ex); } finally { if (cursor != null) { cursor.close(); } } } } else { // Mark all non-inbox messages read. values.put(Sms.READ, ONE); } if (ProviderUtil.shouldSetCreator(values, callerUid)) { // Only SYSTEM or PHONE can set CREATOR // If caller is not SYSTEM or PHONE, or SYSTEM or PHONE does not set CREATOR // set CREATOR using the truth on caller. // Note: Inferring package name from UID may include unrelated package names values.put(Sms.CREATOR, ProviderUtil.getPackageNamesByUid(getContext(), callerUid)); } } else { if (initialValues == null) { values = new ContentValues(1); } else { values = initialValues; } } rowID = db.insert(table, "body", values); // Don't use a trigger for updating the words table because of a bug // in FTS3. The bug is such that the call to get the last inserted // row is incorrect. if (table == TABLE_SMS) { // Update the words table with a corresponding row. The words table // allows us to search for words quickly, without scanning the whole // table; ContentValues cv = new ContentValues(); cv.put(Telephony.MmsSms.WordsTable.ID, rowID); cv.put(Telephony.MmsSms.WordsTable.INDEXED_TEXT, values.getAsString("body")); cv.put(Telephony.MmsSms.WordsTable.SOURCE_ROW_ID, rowID); cv.put(Telephony.MmsSms.WordsTable.TABLE_ID, 1); db.insert(TABLE_WORDS, Telephony.MmsSms.WordsTable.INDEXED_TEXT, cv); } if (rowID > 0) { Uri uri = Uri.parse("content://" + table + "/" + rowID); if (Log.isLoggable(TAG, Log.VERBOSE)) { Log.d(TAG, "insert " + uri + " succeeded"); } notifyChange(uri); return uri; } else { Log.e(TAG, "insert: failed!"); } return null; }