/** * Move a PDU object from one location to another. * * @param from Specify the PDU object to be moved. * @param to The destination location, should be one of the following: * "content://mms/inbox", "content://mms/sent", * "content://mms/drafts", "content://mms/outbox", * "content://mms/trash". * @return New Uri of the moved PDU. * @throws MmsException Error occurred while moving the message. */ public Uri move(Uri from, Uri to) throws MmsException { // Check whether the 'msgId' has been assigned a valid value. long msgId = ContentUris.parseId(from); if (msgId == -1L) { throw new MmsException("Error! ID of the message: -1."); } // Get corresponding int value of destination box. Integer msgBox = MESSAGE_BOX_MAP.get(to); if (msgBox == null) { throw new MmsException( "Bad destination, must be one of " + "content://mms/inbox, content://mms/sent, " + "content://mms/drafts, content://mms/outbox, " + "content://mms/temp."); } ContentValues values = new ContentValues(1); values.put(Mms.MESSAGE_BOX, msgBox); SqliteWrapper.update(mContext, mContentResolver, from, values, null, null); return ContentUris.withAppendedId(to, msgId); }
private void markMmsFailedToSend(Context context, Uri msgUri) { // https://github.com/qklabs/aosp-messenger/blob/master/src/com/android/mms/data/WorkingMessage.java#L1476-1476 try { PduPersister p = PduPersister.getPduPersister(context); // Move the message into MMS Outbox. A trigger will create an entry in // the "pending_msgs" table. p.move(msgUri, Telephony.Mms.Outbox.CONTENT_URI); // Now update the pending_msgs table with an error for that new item. ContentValues values = new ContentValues(1); values.put(Telephony.MmsSms.PendingMessages.ERROR_TYPE, Telephony.MmsSms.ERR_TYPE_GENERIC_PERMANENT); long msgId = ContentUris.parseId(msgUri); SqliteWrapper.update(context, mContentResolver, Telephony.MmsSms.PendingMessages.CONTENT_URI, values, Telephony.MmsSms.PendingMessages.MSG_ID + "=" + msgId, null); } catch (MmsException e) { // Not much we can do here. If the p.move throws an exception, we'll just // leave the message in the draft box. Log.e(TAG, "Failed to move message to outbox and mark as error: " + msgUri, e); } }
private int getResponseStatus(long msgID) { int respStatus = 0; Cursor cursor = SqliteWrapper.query(mContext, mContentResolver, Mms.Outbox.CONTENT_URI, null, Mms._ID + "=" + msgID, null, null); try { if (cursor.moveToFirst()) { respStatus = cursor.getInt(cursor.getColumnIndexOrThrow(Mms.RESPONSE_STATUS)); } } finally { cursor.close(); } if (respStatus != 0) { Log.e(TAG, "Response status is: " + respStatus); } return respStatus; }
private int getRetrieveStatus(long msgID) { int retrieveStatus = 0; Cursor cursor = SqliteWrapper.query(mContext, mContentResolver, Mms.Inbox.CONTENT_URI, null, Mms._ID + "=" + msgID, null, null); try { if (cursor.moveToFirst()) { retrieveStatus = cursor.getInt(cursor.getColumnIndexOrThrow( Mms.RESPONSE_STATUS)); } } finally { cursor.close(); } if (retrieveStatus != 0) { if (LOCAL_LOGV) Log.v(TAG, "Retrieve status is: " + retrieveStatus); } return retrieveStatus; }
/** * Check for locked messages in all threads or a specified thread. * * @param handler An AsyncQueryHandler that will receive onQueryComplete * upon completion of looking for locked messages * @param threadIds A list of threads to search. null means all threads * @param token The token that will be passed to onQueryComplete */ public static void startQueryHaveLockedMessages(AsyncQueryHandler handler, Collection<Long> threadIds, int token) { handler.cancelOperation(token); Uri uri = MmsSms.CONTENT_LOCKED_URI; String selection = null; if (threadIds != null) { StringBuilder buf = new StringBuilder(); int i = 0; for (long threadId : threadIds) { if (i++ > 0) { buf.append(" OR "); } // We have to build the selection arg into the selection because deep down in // provider, the function buildUnionSubQuery takes selectionArgs, but ignores it. buf.append(Mms.THREAD_ID).append("=").append(Long.toString(threadId)); } selection = buf.toString(); } handler.startQuery(token, threadIds, uri, ALL_THREADS_PROJECTION, selection, null, Conversations.DEFAULT_SORT_ORDER); }
/** * Copies media from an Mms to the DrmProvider * * @param context * @param msgId */ public static boolean saveRingtone(Context context, long msgId) { boolean result = true; PduBody body = null; try { body = SlideshowModel.getPduBody(context, ContentUris.withAppendedId(Mms.CONTENT_URI, msgId)); } catch (MmsException e) { Log.e(TAG, "copyToDrmProvider can't load pdu body: " + msgId); } if (body == null) { return false; } int partNum = body.getPartsNum(); for (int i = 0; i < partNum; i++) { PduPart part = body.getPart(i); String type = new String(part.getContentType()); if (DrmUtils.isDrmType(type)) { // All parts (but there's probably only a single one) have to be successful // for a valid result. result &= copyPart(context, part, Long.toHexString(msgId)); } } return result; }
/** * Copies media from an Mms to the "download" directory on the SD card. If any of the parts * are audio types, drm'd or not, they're copied to the "Ringtones" directory. * * @param context * @param msgId */ public static boolean copyMedia(Context context, long msgId) { boolean result = true; PduBody body = null; try { body = SlideshowModel.getPduBody(context, ContentUris.withAppendedId(Mms.CONTENT_URI, msgId)); } catch (MmsException e) { Log.e(TAG, "copyMedia can't load pdu body: " + msgId); } if (body == null) { return false; } int partNum = body.getPartsNum(); for (int i = 0; i < partNum; i++) { PduPart part = body.getPart(i); // all parts have to be successful for a valid result. result &= copyPart(context, part, Long.toHexString(msgId)); } return result; }
/** * Returns true if all drm'd parts are forwardable. * * @param context * @param msgId * @return true if all drm'd parts are forwardable. */ public static boolean isForwardable(Context context, long msgId) { PduBody body = null; try { body = SlideshowModel.getPduBody(context, ContentUris.withAppendedId(Mms.CONTENT_URI, msgId)); } catch (MmsException e) { Log.e(TAG, "getDrmMimeType can't load pdu body: " + msgId); } if (body == null) { return false; } int partNum = body.getPartsNum(); for (int i = 0; i < partNum; i++) { PduPart part = body.getPart(i); String type = new String(part.getContentType()); if (DrmUtils.isDrmType(type) && !DrmUtils.haveRightsForAction(part.getDataUri(), DrmStore.Action.TRANSFER)) { return false; } } return true; }
public static void lockMessage(Context context, MessageItem msgItem, boolean locked) { Uri uri; if ("sms".equals(msgItem.mType)) { uri = Sms.CONTENT_URI; } else { uri = Mms.CONTENT_URI; } final Uri lockUri = ContentUris.withAppendedId(uri, msgItem.mMsgId); final ContentValues values = new ContentValues(1); values.put("locked", locked ? 1 : 0); new Thread(() -> { context.getContentResolver().update(lockUri, values, null, null); }, "MainActivity.lockMessage").start(); }
/** * Move a PDU object from one location to another. * * @param from Specify the PDU object to be moved. * @param to The destination location, should be one of the following: * "content://mms/inbox", "content://mms/sent", * "content://mms/drafts", "content://mms/outbox", * "content://mms/trash". * @return New Uri of the moved PDU. * @throws MmsException Error occurred while moving the message. */ public Uri move(Uri from, Uri to) throws MmsException { // Check whether the 'msgId' has been assigned a valid value. long msgId = ContentUris.parseId(from); if (msgId == -1L) { throw new MmsException("Error! ID of the message: -1."); } // Get corresponding int value of destination box. Integer msgBox = MESSAGE_BOX_MAP.get(to); if (msgBox == null) { throw new MmsException( "Bad destination, must be one of " + "content://mms/inbox, content://mms/sent, " + "content://mms/drafts, content://mms/outbox, " + "content://mms/temp."); } ContentValues values = new ContentValues(1); values.put(Mms.MESSAGE_BOX, msgBox); mContentResolver.update(from, values, null, null); return ContentUris.withAppendedId(to, msgId); }
private int getRetrieveStatus(long msgID) { int retrieveStatus = 0; Cursor cursor = SqliteWrapper.query(mContext, mContentResolver, Mms.Inbox.CONTENT_URI, null, Mms._ID + "=" + msgID, null, null); try { if (cursor.moveToFirst()) { retrieveStatus = cursor.getInt(cursor.getColumnIndexOrThrow( Mms.RESPONSE_STATUS)); } } finally { cursor.close(); } if (retrieveStatus != 0) { if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) { Log.v(TAG, "Retrieve status is: " + retrieveStatus); } } return retrieveStatus; }
private static boolean isDuplicateNotification( Context context, NotificationInd nInd) { byte[] rawLocation = nInd.getContentLocation(); if (rawLocation != null) { String location = new String(rawLocation); String selection = Mms.CONTENT_LOCATION + " = ?"; String[] selectionArgs = new String[] { location }; Cursor cursor = SqliteWrapper.query( context, context.getContentResolver(), Mms.CONTENT_URI, new String[] { Mms._ID }, selection, selectionArgs, null); if (cursor != null) { try { if (cursor.getCount() > 0) { // We already received the same notification before. return true; } } finally { cursor.close(); } } } return false; }
private static int getDownloadFailedMessageCount(Context context) { // Look for any messages in the MMS Inbox that are of the type // NOTIFICATION_IND (i.e. not already downloaded) and in the // permanent failure state. If there are none, cancel any // failed download notification. Cursor c = SqliteWrapper.query(context, context.getContentResolver(), Mms.Inbox.CONTENT_URI, null, Mms.MESSAGE_TYPE + "=" + String.valueOf(PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND) + " AND " + Mms.STATUS + "=" + String.valueOf(DownloadManager.STATE_PERMANENT_FAILURE), null, null); if (c == null) { return 0; } int count = c.getCount(); c.close(); return count; }
/** * Get the thread ID of the MMS message with the given URI * @param context The context * @param uri The URI of the SMS message * @return The thread ID, or THREAD_NONE if the URI contains no entries */ public static long getThreadId(Context context, Uri uri) { Cursor cursor = SqliteWrapper.query( context, context.getContentResolver(), uri, MMS_THREAD_ID_PROJECTION, null, null, null); if (cursor == null) { return THREAD_NONE; } try { if (cursor.moveToFirst()) { return cursor.getLong(cursor.getColumnIndex(Mms.THREAD_ID)); } else { return THREAD_NONE; } } finally { cursor.close(); } }
private int getSubIdFromDb(Uri uri) { int subId = 0; Cursor c = getApplicationContext().getContentResolver().query(uri, null, null, null, null); Log.d(TAG, "Cursor= "+DatabaseUtils.dumpCursorToString(c)); if (c != null) { try { if (c.moveToFirst()) { subId = c.getInt(c.getColumnIndex(Mms.SUB_ID)); Log.d(TAG, "subId in db="+subId ); return subId; } } finally { c.close(); } } return subId; }
/** * Create a new WorkingMessage from the specified data URI, which typically * contains an MMS message. */ public static WorkingMessage load(ComposeMessageActivity activity, Uri uri) { // If the message is not already in the draft box, move it there. if (!uri.toString().startsWith(Mms.Draft.CONTENT_URI.toString())) { PduPersister persister = PduPersister.getPduPersister(activity); if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) { LogTag.debug("load: moving %s to drafts", uri); } try { uri = persister.move(uri, Mms.Draft.CONTENT_URI); } catch (MmsException e) { LogTag.error("Can't move %s to drafts", uri); return null; } } WorkingMessage msg = new WorkingMessage(activity); if (msg.loadFromUri(uri)) { msg.mHasMmsDraft = true; return msg; } return null; }
private boolean addressContainsEmailToMms(Conversation conv, String text) { if (MmsConfig.getEmailGateway() != null) { String[] dests = conv.getRecipients().getNumbers(); int length = dests.length; for (int i = 0; i < length; i++) { if (Mms.isEmailAddress(dests[i]) || MessageUtils.isAlias(dests[i])) { String mtext = dests[i] + " " + text; int[] params = SmsMessage.calculateLength(mtext, false); if (params[0] > 1) { updateState(RECIPIENTS_REQUIRE_MMS, true, true); ensureSlideshow(); syncTextToSlideshow(); return true; } } } } return false; }
private void markMmsMessageWithError(Uri mmsUri) { try { PduPersister p = PduPersister.getPduPersister(mActivity); // Move the message into MMS Outbox. A trigger will create an entry // in // the "pending_msgs" table. p.move(mmsUri, Mms.Outbox.CONTENT_URI); // Now update the pending_msgs table with an error for that new // item. ContentValues values = new ContentValues(1); values.put(PendingMessages.ERROR_TYPE, MmsSms.ERR_TYPE_GENERIC_PERMANENT); long msgId = ContentUris.parseId(mmsUri); SqliteWrapper.update(mActivity, mContentResolver, PendingMessages.CONTENT_URI, values, PendingMessages.MSG_ID + "=" + msgId, null); } catch (MmsException e) { // Not much we can do here. If the p.move throws an exception, we'll // just // leave the message in the draft box. Log.e(TAG, "Failed to move message to outbox and mark as error: " + mmsUri, e); } }
private static Uri createDraftMmsMessage(PduPersister persister, SendReq sendReq, SlideshowModel slideshow, Uri preUri) { if (slideshow == null) { return null; } try { PduBody pb = slideshow.toPduBody(); sendReq.setBody(pb); Uri res = persister.persist(sendReq, preUri == null ? Mms.Draft.CONTENT_URI : preUri); slideshow.sync(pb); return res; } catch (MmsException e) { return null; } }
private void lockMessage(MessageItem msgItem, boolean locked) { Uri uri; if ("sms".equals(msgItem.mType)) { uri = Sms.CONTENT_URI; } else { uri = Mms.CONTENT_URI; } final Uri lockUri = ContentUris.withAppendedId(uri, msgItem.mMsgId); final ContentValues values = new ContentValues(1); values.put("locked", locked ? 1 : 0); new Thread(new Runnable() { @Override public void run() { getContentResolver().update(lockUri, values, null, null); } }, "ComposeMessageActivity.lockMessage").start(); }
/** * Returns true if all drm'd parts are forwardable. * * @param msgId * @return true if all drm'd parts are forwardable. */ private boolean isForwardable(long msgId) { PduBody body = null; try { body = SlideshowModel.getPduBody(this, ContentUris.withAppendedId(Mms.CONTENT_URI, msgId)); } catch (MmsException e) { Log.e(TAG, "getDrmMimeType can't load pdu body: " + msgId); } if (body == null) { return false; } int partNum = body.getPartsNum(); for (int i = 0; i < partNum; i++) { PduPart part = body.getPart(i); String type = new String(part.getContentType()); if (DrmUtils.isDrmType(type) && !DrmUtils.haveRightsForAction(part.getDataUri(), DrmStore.Action.TRANSFER)) { return false; } } return true; }
/** * Copies media from an Mms to the "download" directory on the SD card. If * any of the parts are audio types, drm'd or not, they're copied to the * "Ringtones" directory. * * @param msgId */ private boolean copyMedia(long msgId) { boolean result = true; PduBody body = null; try { body = SlideshowModel.getPduBody(this, ContentUris.withAppendedId(Mms.CONTENT_URI, msgId)); } catch (MmsException e) { Log.e(TAG, "copyMedia can't load pdu body: " + msgId); } if (body == null) { return false; } int partNum = body.getPartsNum(); for (int i = 0; i < partNum; i++) { PduPart part = body.getPart(i); // all parts have to be successful for a valid result. result &= copyPart(part, Long.toHexString(msgId)); } return result; }
private long getMessageDate(Uri uri) { if (uri != null) { Cursor cursor = SqliteWrapper.query(this, mContentResolver, uri, new String[] { Mms.DATE }, null, null, null); if (cursor != null) { try { if ((cursor.getCount() == 1) && cursor.moveToFirst()) { return cursor.getLong(0) * 1000L; } } finally { cursor.close(); } } } return NO_DATE_FOR_DIALOG; }
/** * parse the input address to be a valid MMS address. - if the address is an * email address, leave it as is. - if the address can be parsed into a * valid MMS phone number, return the parsed number. - if the address is a * compliant alias address, leave it as is. */ public static String parseMmsAddress(String address) { // if it's a valid Email address, use that. if (Mms.isEmailAddress(address)) { return address; } // if we are able to parse the address to a MMS compliant phone number, // take that. String retVal = parsePhoneNumberForMms(address); if (retVal != null) { return retVal; } // if it's an alias compliant address, use that. if (isAlias(address)) { return address; } // it's not a valid MMS address, return null return null; }
private int getItemViewType(Cursor cursor) { String type = cursor.getString(mColumnsMap.mColumnMsgType); int boxId; if ("sms".equals(type)) { boxId = cursor.getInt(mColumnsMap.mColumnSmsType); // Note that messages from the SIM card all have a boxId of zero. return (boxId == TextBasedSmsColumns.MESSAGE_TYPE_INBOX || boxId == TextBasedSmsColumns.MESSAGE_TYPE_ALL) ? INCOMING_ITEM_TYPE_SMS : OUTGOING_ITEM_TYPE_SMS; } else { boxId = cursor.getInt(mColumnsMap.mColumnMmsMessageBox); // Note that messages from the SIM card all have a boxId of zero: Mms.MESSAGE_BOX_ALL return (boxId == Mms.MESSAGE_BOX_INBOX || boxId == Mms.MESSAGE_BOX_ALL) ? INCOMING_ITEM_TYPE_MMS : OUTGOING_ITEM_TYPE_MMS; } }
private static MmsReportStatus queryStatusByRecipient( Map<String, MmsReportStatus> status, String recipient) { Set<String> recipientSet = status.keySet(); Iterator<String> iterator = recipientSet.iterator(); while (iterator.hasNext()) { String r = iterator.next(); if (Mms.isEmailAddress(recipient)) { if (TextUtils.equals(r, recipient)) { return status.get(r); } } else if (PhoneNumberUtils.compare(r, recipient)) { return status.get(r); } } return null; }
private int getItemViewType(Cursor cursor) { String type = cursor.getString(mColumnsMap.mColumnMsgType); int boxId; if ("sms".equals(type)) { boxId = cursor.getInt(mColumnsMap.mColumnSmsType); // Note that messages from the SIM card all have a boxId of zero. return (boxId == TextBasedSmsColumns.MESSAGE_TYPE_INBOX || boxId == TextBasedSmsColumns.MESSAGE_TYPE_ALL) ? INCOMING_ITEM_TYPE_SMS : OUTGOING_ITEM_TYPE_SMS; } else { boxId = cursor.getInt(mColumnsMap.mColumnMmsMessageBox); // Note that messages from the SIM card all have a boxId of zero: // Mms.MESSAGE_BOX_ALL return (boxId == Mms.MESSAGE_BOX_INBOX || boxId == Mms.MESSAGE_BOX_ALL) ? INCOMING_ITEM_TYPE_MMS : OUTGOING_ITEM_TYPE_MMS; } }
public void markAllPendingTransactionsAsFailed() { synchronized (mProcessing) { while (mPending.size() != 0) { Transaction transaction = mPending.remove(0); transaction.mTransactionState.setState(TransactionState.FAILED); if (transaction instanceof SendTransaction) { Uri uri = ((SendTransaction)transaction).mSendReqURI; transaction.mTransactionState.setContentUri(uri); int respStatus = PduHeaders.RESPONSE_STATUS_ERROR_NETWORK_PROBLEM; ContentValues values = new ContentValues(1); values.put(Mms.RESPONSE_STATUS, respStatus); SqliteWrapper.update(TransactionService.this, TransactionService.this.getContentResolver(), uri, values, null, null); } transaction.notifyObservers(); } } }
/** * Check for locked messages in all threads or a specified thread. * @param handler An AsyncQueryHandler that will receive onQueryComplete * upon completion of looking for locked messages * @param threadIds A list of threads to search. null means all threads * @param token The token that will be passed to onQueryComplete */ public static void startQueryHaveLockedMessages(AsyncQueryHandler handler, Collection<Long> threadIds, int token) { handler.cancelOperation(token); Uri uri = MmsSms.CONTENT_LOCKED_URI; String selection = null; if (threadIds != null) { StringBuilder buf = new StringBuilder(); int i = 0; for (long threadId : threadIds) { if (i++ > 0) { buf.append(" OR "); } // We have to build the selection arg into the selection because deep down in // provider, the function buildUnionSubQuery takes selectionArgs, but ignores it. buf.append(Mms.THREAD_ID).append("=").append(Long.toString(threadId)); } selection = buf.toString(); } handler.startQuery(token, threadIds, uri, ALL_THREADS_PROJECTION, selection, null, Conversations.DEFAULT_SORT_ORDER); }
/** * Returns the caller info in Contact. */ private Contact getContactInfo(Contact c) { if (c.mIsMe) { return getContactInfoForSelf(); } else if (Mms.isEmailAddress(c.mNumber)) { return getContactInfoForEmailAddress(c.mNumber); } else if (isAlphaNumber(c.mNumber)) { // first try to look it up in the email field Contact contact = getContactInfoForEmailAddress(c.mNumber); if (contact.existsInDatabase()) { return contact; } // then look it up in the phone field return getContactInfoForPhoneNumber(c.mNumber); } else { // it's a real phone number, so strip out non-digits and look it up final String strippedNumber = PhoneNumberUtils.stripSeparators(c.mNumber); return getContactInfoForPhoneNumber(strippedNumber); } }
private void markMmsMessageWithError(Uri mmsUri) { try { PduPersister p = PduPersister.getPduPersister(mActivity); // Move the message into MMS Outbox. A trigger will create an entry in // the "pending_msgs" table. p.move(mmsUri, Mms.Outbox.CONTENT_URI); // Now update the pending_msgs table with an error for that new item. ContentValues values = new ContentValues(1); values.put(PendingMessages.ERROR_TYPE, MmsSms.ERR_TYPE_GENERIC_PERMANENT); long msgId = ContentUris.parseId(mmsUri); SqliteWrapper.update(mActivity, mContentResolver, PendingMessages.CONTENT_URI, values, PendingMessages.MSG_ID + "=" + msgId, null); } catch (MmsException e) { // Not much we can do here. If the p.move throws an exception, we'll just // leave the message in the draft box. Log.e(TAG, "Failed to move message to outbox and mark as error: " + mmsUri, e); } }