FileDocCategorySizeDatePackage
SmsProvider.javaAPI DocAndroid 1.5 API25522Wed May 06 22:42:48 BST 2009com.android.providers.telephony

SmsProvider

public class SmsProvider extends android.content.ContentProvider

Fields Summary
private static final android.net.Uri
NOTIFICATION_URI
private static final android.net.Uri
SIM_URI
static final String
TABLE_SMS
private static final String
TABLE_RAW
private static final String
TABLE_SR_PENDING
private static final Integer
ONE
private static final String[]
SIM_COLUMNS
These are the columns that are available when reading SMS messages from the SIM. Columns whose names begin with "is_" have either "true" or "false" as their values.
private android.database.sqlite.SQLiteOpenHelper
mOpenHelper
private static final String
TAG
private static final String
VND_ANDROID_SMS
private static final String
VND_ANDROID_SMSCHAT
private static final String
VND_ANDROID_DIR_SMS
private static final HashMap
sConversationProjectionMap
private static final String[]
sIDProjection
private static final int
SMS_ALL
private static final int
SMS_ALL_ID
private static final int
SMS_INBOX
private static final int
SMS_INBOX_ID
private static final int
SMS_SENT
private static final int
SMS_SENT_ID
private static final int
SMS_DRAFT
private static final int
SMS_DRAFT_ID
private static final int
SMS_OUTBOX
private static final int
SMS_OUTBOX_ID
private static final int
SMS_CONVERSATIONS
private static final int
SMS_CONVERSATIONS_ID
private static final int
SMS_RAW_MESSAGE
private static final int
SMS_ATTACHMENT
private static final int
SMS_ATTACHMENT_ID
private static final int
SMS_NEW_THREAD_ID
private static final int
SMS_QUERY_THREAD_ID
private static final int
SMS_STATUS_ID
private static final int
SMS_STATUS_PENDING
private static final int
SMS_ALL_SIM
private static final int
SMS_SIM
private static final int
SMS_FAILED
private static final int
SMS_FAILED_ID
private static final int
SMS_QUEUED
private static final int
SMS_UNDELIVERED
private static final android.content.UriMatcher
sURLMatcher
Constructors Summary
Methods Summary
private voidconstructQueryForBox(android.database.sqlite.SQLiteQueryBuilder qb, int type)

        qb.setTables(TABLE_SMS);

        if (type != Sms.MESSAGE_TYPE_ALL) {
            qb.appendWhere("type=" + type);
        }
    
private voidconstructQueryForUndelivered(android.database.sqlite.SQLiteQueryBuilder qb)

        qb.setTables(TABLE_SMS);

        qb.appendWhere("(type=" + Sms.MESSAGE_TYPE_OUTBOX +
                       " OR type=" + Sms.MESSAGE_TYPE_FAILED +
                       " OR type=" + Sms.MESSAGE_TYPE_QUEUED + ")");
    
private java.util.ArrayListconvertSimToSms(android.telephony.gsm.SmsMessage message)

        ArrayList result = new ArrayList();

        // N.B.: These calls must appear in the same order as the
        // columns appear in SIM_COLUMNS.
        result.add(message.getServiceCenterAddress());
        result.add(message.getDisplayOriginatingAddress());
        result.add(message.getMessageClass().toString());
        result.add(message.getDisplayMessageBody());
        result.add(message.getTimestampMillis());
        result.add(Sms.STATUS_NONE);
        result.add(message.getIndexOnSim());
        result.add(message.isStatusReportMessage());
        result.add("sms");
        result.add(TextBasedSmsColumns.MESSAGE_TYPE_ALL);
        return result;
    
public intdelete(android.net.Uri url, java.lang.String where, java.lang.String[] whereArgs)

        int count;
        int match = sURLMatcher.match(url);
        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
        switch (match) {
            case SMS_ALL:
                count = db.delete(TABLE_SMS, where, whereArgs);
                if (count != 0) {
                    // Don't update threads unless something changed.
                    MmsSmsDatabaseHelper.updateAllThreads(db, where, whereArgs);
                }
                break;
             
            case SMS_ALL_ID:
                try {
                    int message_id = Integer.parseInt(url.getPathSegments().get(0));
                    count = MmsSmsDatabaseHelper.deleteOneSms(db, message_id);
                } catch (Exception e) {
                    throw new IllegalArgumentException(
                        "Bad message id: " + url.getPathSegments().get(0));
                }
                break;

            case SMS_CONVERSATIONS_ID:
                int threadID;

                try {
                    threadID = Integer.parseInt(url.getPathSegments().get(1));
                } catch (Exception ex) {
                    throw new IllegalArgumentException(
                            "Bad conversation thread id: "
                            + url.getPathSegments().get(1));
                }

                // delete the messages from the sms table
                where = DatabaseUtils.concatenateWhere("thread_id=" + threadID, where);
                count = db.delete(TABLE_SMS, where, whereArgs);
                MmsSmsDatabaseHelper.updateThread(db, threadID);
                break;

            case SMS_RAW_MESSAGE:
                count = db.delete("raw", where, whereArgs);
                break;

            case SMS_STATUS_PENDING:
                count = db.delete("sr_pending", where, whereArgs);
                break;

            case SMS_SIM:
                String messageIndexString = url.getPathSegments().get(1);

                return deleteMessageFromSim(messageIndexString);

            default:
                throw new IllegalArgumentException("Unknown URL");
        }

        if (count > 0) {
            notifyChange(url);
        }
        return count;
    
private intdeleteMessageFromSim(java.lang.String messageIndexString)
Delete the message at index from SIM. Return true iff successful.

        SmsManager smsManager = SmsManager.getDefault();

        try {
            return smsManager.deleteMessageFromSim(
                    Integer.parseInt(messageIndexString))
                    ? 1 : 0;
        } catch (NumberFormatException exception) {
            throw new IllegalArgumentException(
                    "Bad SMS SIM ID: " + messageIndexString);
        } finally {
            ContentResolver cr = getContext().getContentResolver();

            cr.notifyChange(SIM_URI, null);
        }
    
private android.database.CursorgetAllMessagesFromSim()
Return a Cursor listing all the messages stored on the SIM.

        SmsManager smsManager = SmsManager.getDefault();
        ArrayList<SmsMessage> messages = smsManager.getAllMessagesFromSim();
        ArrayList<ArrayList> rows = new ArrayList<ArrayList>();

        for (int count = messages.size(), i = 0; i < count; i++) {
            SmsMessage message = messages.get(i);
            if (message != null) {
                rows.add(convertSimToSms(message));
            }
        }
        return withSimNotificationUri(new ArrayListCursor(SIM_COLUMNS, rows));
    
private android.database.CursorgetSingleMessageFromSim(java.lang.String messageIndexString)
Return a Cursor containing just one message from the SIM.

        try {
            int messageIndex = Integer.parseInt(messageIndexString);
            SmsManager smsManager = SmsManager.getDefault();
            ArrayList<SmsMessage> messages = smsManager.getAllMessagesFromSim();
            ArrayList<ArrayList> singleRow = new ArrayList<ArrayList>();

            SmsMessage message = messages.get(messageIndex);
            if (message == null) {
                throw new IllegalArgumentException(
                        "Message not retrieved. ID: " + messageIndexString);
            }
            singleRow.add(convertSimToSms(message));
            return withSimNotificationUri(
                    new ArrayListCursor(SIM_COLUMNS, singleRow));
        } catch (NumberFormatException exception) {
            throw new IllegalArgumentException(
                    "Bad SMS SIM ID: " + messageIndexString);
        }
    
public java.lang.StringgetType(android.net.Uri url)

        switch (url.getPathSegments().size()) {
        case 0:
            return VND_ANDROID_DIR_SMS;
            case 1:
                try {
                    Integer.parseInt(url.getPathSegments().get(0));
                    return VND_ANDROID_SMS;
                } catch (NumberFormatException ex) {
                    return VND_ANDROID_DIR_SMS;
                }
            case 2:
                // TODO: What about "threadID"?
                if (url.getPathSegments().get(0).equals("conversations")) {
                    return VND_ANDROID_SMSCHAT;
                } else {
                    return VND_ANDROID_SMS;
                }
        }
        return null;
    
public android.net.Uriinsert(android.net.Uri url, android.content.ContentValues initialValues)

        ContentValues values;
        long rowID;
        int type = Sms.MESSAGE_TYPE_ALL;

        int match = sURLMatcher.match(url);
        if (Config.LOGD) {
            Log.d(TAG, "insert url=" + url + ", match=" + match);
        }

        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;
        }

        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)) && (address != null)) {
                values.put(Sms.THREAD_ID, Threads.getOrCreateThreadId(
                                   getContext(), address));
            }

            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 = getContext().getContentResolver().query(
                            Uri.withAppendedPath(
                                    Contacts.Phones.CONTENT_FILTER_URL, address),
                            new String[] { Contacts.Phones.PERSON_ID },
                            null, null, null);
                    if (cursor != null) {
                        if (cursor.getCount() > 0) {
                            cursor.moveToFirst();
                            Long id = Long.valueOf(cursor.getLong(0));
                                values.put(Sms.PERSON, id);
                        }
                        cursor.deactivate();
                    }
                }
            } else {
                // Mark all non-inbox messages read.
                values.put(Sms.READ, ONE);
            }
        } else {
            if (initialValues == null) {
                values = new ContentValues(1);
            } else {
                values = initialValues;
            }
        }

        SQLiteDatabase db = mOpenHelper.getWritableDatabase();
        rowID = db.insert(table, "body", values);
        if (rowID > 0) {
            Uri uri = Uri.parse("content://" + table + "/" + rowID);
            notifyChange(uri);
            return uri;
        } else {
            Log.e(TAG,
                  "SmsProvider.insert: failed! " + values.toString());
        }

        return null;
    
private voidnotifyChange(android.net.Uri uri)

        ContentResolver cr = getContext().getContentResolver();
        cr.notifyChange(uri, null);
        cr.notifyChange(MmsSms.CONTENT_URI, null);
        cr.notifyChange(Uri.parse("content://mms-sms/conversations/"), null);
    
public booleanonCreate()


    
       
        mOpenHelper = MmsSmsDatabaseHelper.getInstance(getContext());
        return true;
    
public android.database.Cursorquery(android.net.Uri url, java.lang.String[] projectionIn, java.lang.String selection, java.lang.String[] selectionArgs, java.lang.String sort)

        SQLiteQueryBuilder qb = new SQLiteQueryBuilder();

        // Generate the body of the query.
        int match = sURLMatcher.match(url);
        switch (match) {
            case SMS_ALL:
                constructQueryForBox(qb, Sms.MESSAGE_TYPE_ALL);
                break;

            case SMS_UNDELIVERED:
                constructQueryForUndelivered(qb);
                break;
                
            case SMS_FAILED:
                constructQueryForBox(qb, Sms.MESSAGE_TYPE_FAILED);
                break;

            case SMS_QUEUED:
                constructQueryForBox(qb, Sms.MESSAGE_TYPE_QUEUED);
                break;
                
            case SMS_INBOX:
                constructQueryForBox(qb, Sms.MESSAGE_TYPE_INBOX);
                break;

            case SMS_SENT:
                constructQueryForBox(qb, Sms.MESSAGE_TYPE_SENT);
                break;

            case SMS_DRAFT:
                constructQueryForBox(qb, Sms.MESSAGE_TYPE_DRAFT);
                break;

            case SMS_OUTBOX:
                constructQueryForBox(qb, Sms.MESSAGE_TYPE_OUTBOX);
                break;

            case SMS_ALL_ID:
                qb.setTables(TABLE_SMS);
                qb.appendWhere("(_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:
                qb.setTables(TABLE_SMS);
                qb.appendWhere("(_id = " + url.getPathSegments().get(1) + ")");
                break;

            case SMS_CONVERSATIONS_ID:
                int threadID;

                try {
                    threadID = Integer.parseInt(url.getPathSegments().get(1));
                    if (Config.LOGD) {
                        Log.d(TAG, "query conversations: threadID=" + threadID);
                    }
                }
                catch (Exception ex) {
                    Log.e(TAG,
                          "Bad conversation thread id: "
                          + url.getPathSegments().get(1));
                    return null;
                }

                qb.setTables(TABLE_SMS);
                qb.appendWhere("thread_id = " + threadID);
                break;

            case SMS_CONVERSATIONS:
                qb.setTables("sms, (SELECT thread_id AS group_thread_id, MAX(date) AS group_date, COUNT(*) AS msg_count FROM sms GROUP BY thread_id) AS groups");
                qb.appendWhere("sms.thread_id = groups.group_thread_id AND sms.date = groups.group_date");
                qb.setProjectionMap(sConversationProjectionMap);
                break;

            case SMS_RAW_MESSAGE:
                qb.setTables("raw");
                break;

            case SMS_STATUS_PENDING:
                qb.setTables("sr_pending");
                break;

            case SMS_ATTACHMENT:
                qb.setTables("attachments");
                break;

            case SMS_ATTACHMENT_ID:
                qb.setTables("attachments");
                qb.appendWhere(
                        "(sms_id = " + url.getPathSegments().get(1) + ")");
                break;

            case SMS_QUERY_THREAD_ID:
                qb.setTables("canonical_addresses");
                if (projectionIn == null) {
                    projectionIn = sIDProjection;
                }
                break;

            case SMS_STATUS_ID:
                qb.setTables(TABLE_SMS);
                qb.appendWhere("(_id = " + url.getPathSegments().get(1) + ")");
                break;

            case SMS_ALL_SIM:
                return getAllMessagesFromSim();

            case SMS_SIM:
                String messageIndexString = url.getPathSegments().get(1);

                return getSingleMessageFromSim(messageIndexString);

            default:
                Log.e(TAG, "Invalid request: " + url);
                return null;
        }

        String orderBy = null;

        if (!TextUtils.isEmpty(sort)) {
            orderBy = sort;
        } else if (qb.getTables().equals(TABLE_SMS)) {
            orderBy = Sms.DEFAULT_SORT_ORDER;
        }

        SQLiteDatabase db = mOpenHelper.getReadableDatabase();
        Cursor ret = qb.query(db, projectionIn, selection, selectionArgs,
                              null, null, orderBy);

        // TODO: Since the URLs are a mess, always use content://sms
        ret.setNotificationUri(getContext().getContentResolver(),
                NOTIFICATION_URI);
        return ret;
    
public intupdate(android.net.Uri url, android.content.ContentValues values, java.lang.String where, java.lang.String[] whereArgs)

        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");
        }

        where = DatabaseUtils.concatenateWhere(where, extraWhere);
        count = db.update(table, values, where, whereArgs);

        if (count > 0) {
            notifyChange(url);
        }
        return count;
    
private android.database.CursorwithSimNotificationUri(android.database.Cursor cursor)

        cursor.setNotificationUri(getContext().getContentResolver(),
                                  SIM_URI);
        return cursor;