Initial checkin of AOSP Messaging app.
b/23110861 Change-Id: I11db999bd10656801e618f78ab2b2ef74136fff1
This commit is contained in:
922
src/com/android/messaging/datamodel/data/MessageData.java
Normal file
922
src/com/android/messaging/datamodel/data/MessageData.java
Normal file
@@ -0,0 +1,922 @@
|
||||
/*
|
||||
* Copyright (C) 2015 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.messaging.datamodel.data;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteStatement;
|
||||
import android.net.Uri;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.android.messaging.datamodel.DatabaseHelper;
|
||||
import com.android.messaging.datamodel.DatabaseHelper.MessageColumns;
|
||||
import com.android.messaging.datamodel.DatabaseWrapper;
|
||||
import com.android.messaging.sms.MmsUtils;
|
||||
import com.android.messaging.util.Assert;
|
||||
import com.android.messaging.util.BugleGservices;
|
||||
import com.android.messaging.util.BugleGservicesKeys;
|
||||
import com.android.messaging.util.Dates;
|
||||
import com.android.messaging.util.DebugUtils;
|
||||
import com.android.messaging.util.OsUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class MessageData implements Parcelable {
|
||||
private static final String[] sProjection = {
|
||||
MessageColumns._ID,
|
||||
MessageColumns.CONVERSATION_ID,
|
||||
MessageColumns.SENDER_PARTICIPANT_ID,
|
||||
MessageColumns.SELF_PARTICIPANT_ID,
|
||||
MessageColumns.SENT_TIMESTAMP,
|
||||
MessageColumns.RECEIVED_TIMESTAMP,
|
||||
MessageColumns.SEEN,
|
||||
MessageColumns.READ,
|
||||
MessageColumns.PROTOCOL,
|
||||
MessageColumns.STATUS,
|
||||
MessageColumns.SMS_MESSAGE_URI,
|
||||
MessageColumns.SMS_PRIORITY,
|
||||
MessageColumns.SMS_MESSAGE_SIZE,
|
||||
MessageColumns.MMS_SUBJECT,
|
||||
MessageColumns.MMS_TRANSACTION_ID,
|
||||
MessageColumns.MMS_CONTENT_LOCATION,
|
||||
MessageColumns.MMS_EXPIRY,
|
||||
MessageColumns.RAW_TELEPHONY_STATUS,
|
||||
MessageColumns.RETRY_START_TIMESTAMP,
|
||||
};
|
||||
|
||||
private static final int INDEX_ID = 0;
|
||||
private static final int INDEX_CONVERSATION_ID = 1;
|
||||
private static final int INDEX_PARTICIPANT_ID = 2;
|
||||
private static final int INDEX_SELF_ID = 3;
|
||||
private static final int INDEX_SENT_TIMESTAMP = 4;
|
||||
private static final int INDEX_RECEIVED_TIMESTAMP = 5;
|
||||
private static final int INDEX_SEEN = 6;
|
||||
private static final int INDEX_READ = 7;
|
||||
private static final int INDEX_PROTOCOL = 8;
|
||||
private static final int INDEX_BUGLE_STATUS = 9;
|
||||
private static final int INDEX_SMS_MESSAGE_URI = 10;
|
||||
private static final int INDEX_SMS_PRIORITY = 11;
|
||||
private static final int INDEX_SMS_MESSAGE_SIZE = 12;
|
||||
private static final int INDEX_MMS_SUBJECT = 13;
|
||||
private static final int INDEX_MMS_TRANSACTION_ID = 14;
|
||||
private static final int INDEX_MMS_CONTENT_LOCATION = 15;
|
||||
private static final int INDEX_MMS_EXPIRY = 16;
|
||||
private static final int INDEX_RAW_TELEPHONY_STATUS = 17;
|
||||
private static final int INDEX_RETRY_START_TIMESTAMP = 18;
|
||||
|
||||
// SQL statement to insert a "complete" message row (columns based on the projection above).
|
||||
private static final String INSERT_MESSAGE_SQL =
|
||||
"INSERT INTO " + DatabaseHelper.MESSAGES_TABLE + " ( "
|
||||
+ TextUtils.join(", ", Arrays.copyOfRange(sProjection, 1,
|
||||
INDEX_RETRY_START_TIMESTAMP + 1))
|
||||
+ ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
|
||||
private String mMessageId;
|
||||
private String mConversationId;
|
||||
private String mParticipantId;
|
||||
private String mSelfId;
|
||||
private long mSentTimestamp;
|
||||
private long mReceivedTimestamp;
|
||||
private boolean mSeen;
|
||||
private boolean mRead;
|
||||
private int mProtocol;
|
||||
private Uri mSmsMessageUri;
|
||||
private int mSmsPriority;
|
||||
private long mSmsMessageSize;
|
||||
private String mMmsSubject;
|
||||
private String mMmsTransactionId;
|
||||
private String mMmsContentLocation;
|
||||
private long mMmsExpiry;
|
||||
private int mRawStatus;
|
||||
private int mStatus;
|
||||
private final ArrayList<MessagePartData> mParts;
|
||||
private long mRetryStartTimestamp;
|
||||
|
||||
// PROTOCOL Values
|
||||
public static final int PROTOCOL_UNKNOWN = -1; // Unknown type
|
||||
public static final int PROTOCOL_SMS = 0; // SMS message
|
||||
public static final int PROTOCOL_MMS = 1; // MMS message
|
||||
public static final int PROTOCOL_MMS_PUSH_NOTIFICATION = 2; // MMS WAP push notification
|
||||
|
||||
// Bugle STATUS Values
|
||||
public static final int BUGLE_STATUS_UNKNOWN = 0;
|
||||
|
||||
// Outgoing
|
||||
public static final int BUGLE_STATUS_OUTGOING_COMPLETE = 1;
|
||||
public static final int BUGLE_STATUS_OUTGOING_DELIVERED = 2;
|
||||
// Transitions to either YET_TO_SEND or SEND_AFTER_PROCESSING depending attachments.
|
||||
public static final int BUGLE_STATUS_OUTGOING_DRAFT = 3;
|
||||
public static final int BUGLE_STATUS_OUTGOING_YET_TO_SEND = 4;
|
||||
public static final int BUGLE_STATUS_OUTGOING_SENDING = 5;
|
||||
public static final int BUGLE_STATUS_OUTGOING_RESENDING = 6;
|
||||
public static final int BUGLE_STATUS_OUTGOING_AWAITING_RETRY = 7;
|
||||
public static final int BUGLE_STATUS_OUTGOING_FAILED = 8;
|
||||
public static final int BUGLE_STATUS_OUTGOING_FAILED_EMERGENCY_NUMBER = 9;
|
||||
|
||||
// Incoming
|
||||
public static final int BUGLE_STATUS_INCOMING_COMPLETE = 100;
|
||||
public static final int BUGLE_STATUS_INCOMING_YET_TO_MANUAL_DOWNLOAD = 101;
|
||||
public static final int BUGLE_STATUS_INCOMING_RETRYING_MANUAL_DOWNLOAD = 102;
|
||||
public static final int BUGLE_STATUS_INCOMING_MANUAL_DOWNLOADING = 103;
|
||||
public static final int BUGLE_STATUS_INCOMING_RETRYING_AUTO_DOWNLOAD = 104;
|
||||
public static final int BUGLE_STATUS_INCOMING_AUTO_DOWNLOADING = 105;
|
||||
public static final int BUGLE_STATUS_INCOMING_DOWNLOAD_FAILED = 106;
|
||||
public static final int BUGLE_STATUS_INCOMING_EXPIRED_OR_NOT_AVAILABLE = 107;
|
||||
|
||||
public static final String getStatusDescription(int status) {
|
||||
switch (status) {
|
||||
case BUGLE_STATUS_UNKNOWN:
|
||||
return "UNKNOWN";
|
||||
case BUGLE_STATUS_OUTGOING_COMPLETE:
|
||||
return "OUTGOING_COMPLETE";
|
||||
case BUGLE_STATUS_OUTGOING_DELIVERED:
|
||||
return "OUTGOING_DELIVERED";
|
||||
case BUGLE_STATUS_OUTGOING_DRAFT:
|
||||
return "OUTGOING_DRAFT";
|
||||
case BUGLE_STATUS_OUTGOING_YET_TO_SEND:
|
||||
return "OUTGOING_YET_TO_SEND";
|
||||
case BUGLE_STATUS_OUTGOING_SENDING:
|
||||
return "OUTGOING_SENDING";
|
||||
case BUGLE_STATUS_OUTGOING_RESENDING:
|
||||
return "OUTGOING_RESENDING";
|
||||
case BUGLE_STATUS_OUTGOING_AWAITING_RETRY:
|
||||
return "OUTGOING_AWAITING_RETRY";
|
||||
case BUGLE_STATUS_OUTGOING_FAILED:
|
||||
return "OUTGOING_FAILED";
|
||||
case BUGLE_STATUS_OUTGOING_FAILED_EMERGENCY_NUMBER:
|
||||
return "OUTGOING_FAILED_EMERGENCY_NUMBER";
|
||||
case BUGLE_STATUS_INCOMING_COMPLETE:
|
||||
return "INCOMING_COMPLETE";
|
||||
case BUGLE_STATUS_INCOMING_YET_TO_MANUAL_DOWNLOAD:
|
||||
return "INCOMING_YET_TO_MANUAL_DOWNLOAD";
|
||||
case BUGLE_STATUS_INCOMING_RETRYING_MANUAL_DOWNLOAD:
|
||||
return "INCOMING_RETRYING_MANUAL_DOWNLOAD";
|
||||
case BUGLE_STATUS_INCOMING_MANUAL_DOWNLOADING:
|
||||
return "INCOMING_MANUAL_DOWNLOADING";
|
||||
case BUGLE_STATUS_INCOMING_RETRYING_AUTO_DOWNLOAD:
|
||||
return "INCOMING_RETRYING_AUTO_DOWNLOAD";
|
||||
case BUGLE_STATUS_INCOMING_AUTO_DOWNLOADING:
|
||||
return "INCOMING_AUTO_DOWNLOADING";
|
||||
case BUGLE_STATUS_INCOMING_DOWNLOAD_FAILED:
|
||||
return "INCOMING_DOWNLOAD_FAILED";
|
||||
case BUGLE_STATUS_INCOMING_EXPIRED_OR_NOT_AVAILABLE:
|
||||
return "INCOMING_EXPIRED_OR_NOT_AVAILABLE";
|
||||
default:
|
||||
return String.valueOf(status) + " (check MessageData)";
|
||||
}
|
||||
}
|
||||
|
||||
// All incoming messages expect to have status >= BUGLE_STATUS_FIRST_INCOMING
|
||||
public static final int BUGLE_STATUS_FIRST_INCOMING = BUGLE_STATUS_INCOMING_COMPLETE;
|
||||
|
||||
// Detailed MMS failures. Most of the values are defined in PduHeaders. However, a few are
|
||||
// defined here instead. These are never returned in the MMS HTTP response, but are used
|
||||
// internally. The values here must not conflict with any of the existing PduHeader values.
|
||||
public static final int RAW_TELEPHONY_STATUS_UNDEFINED = MmsUtils.PDU_HEADER_VALUE_UNDEFINED;
|
||||
public static final int RAW_TELEPHONY_STATUS_MESSAGE_TOO_BIG = 10000;
|
||||
|
||||
// Unknown result code for MMS sending/downloading. This is used as the default value
|
||||
// for result code returned from platform MMS API.
|
||||
public static final int UNKNOWN_RESULT_CODE = 0;
|
||||
|
||||
/**
|
||||
* Create an "empty" message
|
||||
*/
|
||||
public MessageData() {
|
||||
mParts = new ArrayList<MessagePartData>();
|
||||
}
|
||||
|
||||
public static String[] getProjection() {
|
||||
return sProjection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a draft message for a particular conversation based on supplied content
|
||||
*/
|
||||
public static MessageData createDraftMessage(final String conversationId,
|
||||
final String selfId, final MessageData content) {
|
||||
final MessageData message = new MessageData();
|
||||
message.mStatus = BUGLE_STATUS_OUTGOING_DRAFT;
|
||||
message.mProtocol = PROTOCOL_UNKNOWN;
|
||||
message.mConversationId = conversationId;
|
||||
message.mParticipantId = selfId;
|
||||
message.mReceivedTimestamp = System.currentTimeMillis();
|
||||
if (content == null) {
|
||||
message.mParts.add(MessagePartData.createTextMessagePart(""));
|
||||
} else {
|
||||
if (!TextUtils.isEmpty(content.mParticipantId)) {
|
||||
message.mParticipantId = content.mParticipantId;
|
||||
}
|
||||
if (!TextUtils.isEmpty(content.mMmsSubject)) {
|
||||
message.mMmsSubject = content.mMmsSubject;
|
||||
}
|
||||
for (final MessagePartData part : content.getParts()) {
|
||||
message.mParts.add(part);
|
||||
}
|
||||
}
|
||||
message.mSelfId = selfId;
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a draft sms message for a particular conversation
|
||||
*/
|
||||
public static MessageData createDraftSmsMessage(final String conversationId,
|
||||
final String selfId, final String messageText) {
|
||||
final MessageData message = new MessageData();
|
||||
message.mStatus = BUGLE_STATUS_OUTGOING_DRAFT;
|
||||
message.mProtocol = PROTOCOL_SMS;
|
||||
message.mConversationId = conversationId;
|
||||
message.mParticipantId = selfId;
|
||||
message.mSelfId = selfId;
|
||||
message.mParts.add(MessagePartData.createTextMessagePart(messageText));
|
||||
message.mReceivedTimestamp = System.currentTimeMillis();
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a draft mms message for a particular conversation
|
||||
*/
|
||||
public static MessageData createDraftMmsMessage(final String conversationId,
|
||||
final String selfId, final String messageText, final String subjectText) {
|
||||
final MessageData message = new MessageData();
|
||||
message.mStatus = BUGLE_STATUS_OUTGOING_DRAFT;
|
||||
message.mProtocol = PROTOCOL_MMS;
|
||||
message.mConversationId = conversationId;
|
||||
message.mParticipantId = selfId;
|
||||
message.mSelfId = selfId;
|
||||
message.mMmsSubject = subjectText;
|
||||
message.mReceivedTimestamp = System.currentTimeMillis();
|
||||
if (!TextUtils.isEmpty(messageText)) {
|
||||
message.mParts.add(MessagePartData.createTextMessagePart(messageText));
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a message received from a particular number in a particular conversation
|
||||
*/
|
||||
public static MessageData createReceivedSmsMessage(final Uri uri, final String conversationId,
|
||||
final String participantId, final String selfId, final String messageText,
|
||||
final String subject, final long sent, final long recieved,
|
||||
final boolean seen, final boolean read) {
|
||||
final MessageData message = new MessageData();
|
||||
message.mSmsMessageUri = uri;
|
||||
message.mConversationId = conversationId;
|
||||
message.mParticipantId = participantId;
|
||||
message.mSelfId = selfId;
|
||||
message.mProtocol = PROTOCOL_SMS;
|
||||
message.mStatus = BUGLE_STATUS_INCOMING_COMPLETE;
|
||||
message.mMmsSubject = subject;
|
||||
message.mReceivedTimestamp = recieved;
|
||||
message.mSentTimestamp = sent;
|
||||
message.mParts.add(MessagePartData.createTextMessagePart(messageText));
|
||||
message.mSeen = seen;
|
||||
message.mRead = read;
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a message not yet associated with a particular conversation
|
||||
*/
|
||||
public static MessageData createSharedMessage(final String messageText) {
|
||||
final MessageData message = new MessageData();
|
||||
message.mStatus = BUGLE_STATUS_OUTGOING_DRAFT;
|
||||
if (!TextUtils.isEmpty(messageText)) {
|
||||
message.mParts.add(MessagePartData.createTextMessagePart(messageText));
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a message from Sms table fields
|
||||
*/
|
||||
public static MessageData createSmsMessage(final String messageUri, final String participantId,
|
||||
final String selfId, final String conversationId, final int bugleStatus,
|
||||
final boolean seen, final boolean read, final long sent,
|
||||
final long recieved, final String messageText) {
|
||||
final MessageData message = new MessageData();
|
||||
message.mParticipantId = participantId;
|
||||
message.mSelfId = selfId;
|
||||
message.mConversationId = conversationId;
|
||||
message.mSentTimestamp = sent;
|
||||
message.mReceivedTimestamp = recieved;
|
||||
message.mSeen = seen;
|
||||
message.mRead = read;
|
||||
message.mProtocol = PROTOCOL_SMS;
|
||||
message.mStatus = bugleStatus;
|
||||
message.mSmsMessageUri = Uri.parse(messageUri);
|
||||
message.mParts.add(MessagePartData.createTextMessagePart(messageText));
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a message from Mms table fields
|
||||
*/
|
||||
public static MessageData createMmsMessage(final String messageUri, final String participantId,
|
||||
final String selfId, final String conversationId, final boolean isNotification,
|
||||
final int bugleStatus, final String contentLocation, final String transactionId,
|
||||
final int smsPriority, final String subject, final boolean seen, final boolean read,
|
||||
final long size, final int rawStatus, final long expiry, final long sent,
|
||||
final long received) {
|
||||
final MessageData message = new MessageData();
|
||||
message.mParticipantId = participantId;
|
||||
message.mSelfId = selfId;
|
||||
message.mConversationId = conversationId;
|
||||
message.mSentTimestamp = sent;
|
||||
message.mReceivedTimestamp = received;
|
||||
message.mMmsContentLocation = contentLocation;
|
||||
message.mMmsTransactionId = transactionId;
|
||||
message.mSeen = seen;
|
||||
message.mRead = read;
|
||||
message.mStatus = bugleStatus;
|
||||
message.mProtocol = (isNotification ? PROTOCOL_MMS_PUSH_NOTIFICATION : PROTOCOL_MMS);
|
||||
message.mSmsMessageUri = Uri.parse(messageUri);
|
||||
message.mSmsPriority = smsPriority;
|
||||
message.mSmsMessageSize = size;
|
||||
message.mMmsSubject = subject;
|
||||
message.mMmsExpiry = expiry;
|
||||
message.mRawStatus = rawStatus;
|
||||
if (bugleStatus == BUGLE_STATUS_INCOMING_RETRYING_AUTO_DOWNLOAD ||
|
||||
bugleStatus == BUGLE_STATUS_OUTGOING_RESENDING) {
|
||||
// Set the retry start timestamp if this message is already in process of retrying
|
||||
// Either as autodownload is starting or sending already in progress (MMS update)
|
||||
message.mRetryStartTimestamp = received;
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
public void addPart(final MessagePartData part) {
|
||||
if (part instanceof PendingAttachmentData) {
|
||||
// Pending attachments may only be added to shared message data that's not associated
|
||||
// with any particular conversation, in order to store shared images.
|
||||
Assert.isTrue(mConversationId == null);
|
||||
}
|
||||
mParts.add(part);
|
||||
}
|
||||
|
||||
public Iterable<MessagePartData> getParts() {
|
||||
return mParts;
|
||||
}
|
||||
|
||||
public void bind(final Cursor cursor) {
|
||||
mMessageId = cursor.getString(INDEX_ID);
|
||||
mConversationId = cursor.getString(INDEX_CONVERSATION_ID);
|
||||
mParticipantId = cursor.getString(INDEX_PARTICIPANT_ID);
|
||||
mSelfId = cursor.getString(INDEX_SELF_ID);
|
||||
mSentTimestamp = cursor.getLong(INDEX_SENT_TIMESTAMP);
|
||||
mReceivedTimestamp = cursor.getLong(INDEX_RECEIVED_TIMESTAMP);
|
||||
mSeen = (cursor.getInt(INDEX_SEEN) != 0);
|
||||
mRead = (cursor.getInt(INDEX_READ) != 0);
|
||||
mProtocol = cursor.getInt(INDEX_PROTOCOL);
|
||||
mStatus = cursor.getInt(INDEX_BUGLE_STATUS);
|
||||
final String smsMessageUri = cursor.getString(INDEX_SMS_MESSAGE_URI);
|
||||
mSmsMessageUri = (smsMessageUri == null) ? null : Uri.parse(smsMessageUri);
|
||||
mSmsPriority = cursor.getInt(INDEX_SMS_PRIORITY);
|
||||
mSmsMessageSize = cursor.getLong(INDEX_SMS_MESSAGE_SIZE);
|
||||
mMmsExpiry = cursor.getLong(INDEX_MMS_EXPIRY);
|
||||
mRawStatus = cursor.getInt(INDEX_RAW_TELEPHONY_STATUS);
|
||||
mMmsSubject = cursor.getString(INDEX_MMS_SUBJECT);
|
||||
mMmsTransactionId = cursor.getString(INDEX_MMS_TRANSACTION_ID);
|
||||
mMmsContentLocation = cursor.getString(INDEX_MMS_CONTENT_LOCATION);
|
||||
mRetryStartTimestamp = cursor.getLong(INDEX_RETRY_START_TIMESTAMP);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind to the draft message data for a conversation. The conversation's self id is used as
|
||||
* the draft's self id.
|
||||
*/
|
||||
public void bindDraft(final Cursor cursor, final String conversationSelfId) {
|
||||
bind(cursor);
|
||||
mSelfId = conversationSelfId;
|
||||
}
|
||||
|
||||
protected static String getParticipantId(final Cursor cursor) {
|
||||
return cursor.getString(INDEX_PARTICIPANT_ID);
|
||||
}
|
||||
|
||||
public void populate(final ContentValues values) {
|
||||
values.put(MessageColumns.CONVERSATION_ID, mConversationId);
|
||||
values.put(MessageColumns.SENDER_PARTICIPANT_ID, mParticipantId);
|
||||
values.put(MessageColumns.SELF_PARTICIPANT_ID, mSelfId);
|
||||
values.put(MessageColumns.SENT_TIMESTAMP, mSentTimestamp);
|
||||
values.put(MessageColumns.RECEIVED_TIMESTAMP, mReceivedTimestamp);
|
||||
values.put(MessageColumns.SEEN, mSeen ? 1 : 0);
|
||||
values.put(MessageColumns.READ, mRead ? 1 : 0);
|
||||
values.put(MessageColumns.PROTOCOL, mProtocol);
|
||||
values.put(MessageColumns.STATUS, mStatus);
|
||||
final String smsMessageUri = ((mSmsMessageUri == null) ? null : mSmsMessageUri.toString());
|
||||
values.put(MessageColumns.SMS_MESSAGE_URI, smsMessageUri);
|
||||
values.put(MessageColumns.SMS_PRIORITY, mSmsPriority);
|
||||
values.put(MessageColumns.SMS_MESSAGE_SIZE, mSmsMessageSize);
|
||||
values.put(MessageColumns.MMS_EXPIRY, mMmsExpiry);
|
||||
values.put(MessageColumns.MMS_SUBJECT, mMmsSubject);
|
||||
values.put(MessageColumns.MMS_TRANSACTION_ID, mMmsTransactionId);
|
||||
values.put(MessageColumns.MMS_CONTENT_LOCATION, mMmsContentLocation);
|
||||
values.put(MessageColumns.RAW_TELEPHONY_STATUS, mRawStatus);
|
||||
values.put(MessageColumns.RETRY_START_TIMESTAMP, mRetryStartTimestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Note this is not thread safe so callers need to make sure they own the wrapper + statements
|
||||
* while they call this and use the returned value.
|
||||
*/
|
||||
public SQLiteStatement getInsertStatement(final DatabaseWrapper db) {
|
||||
final SQLiteStatement insert = db.getStatementInTransaction(
|
||||
DatabaseWrapper.INDEX_INSERT_MESSAGE, INSERT_MESSAGE_SQL);
|
||||
insert.clearBindings();
|
||||
insert.bindString(INDEX_CONVERSATION_ID, mConversationId);
|
||||
insert.bindString(INDEX_PARTICIPANT_ID, mParticipantId);
|
||||
insert.bindString(INDEX_SELF_ID, mSelfId);
|
||||
insert.bindLong(INDEX_SENT_TIMESTAMP, mSentTimestamp);
|
||||
insert.bindLong(INDEX_RECEIVED_TIMESTAMP, mReceivedTimestamp);
|
||||
insert.bindLong(INDEX_SEEN, mSeen ? 1 : 0);
|
||||
insert.bindLong(INDEX_READ, mRead ? 1 : 0);
|
||||
insert.bindLong(INDEX_PROTOCOL, mProtocol);
|
||||
insert.bindLong(INDEX_BUGLE_STATUS, mStatus);
|
||||
if (mSmsMessageUri != null) {
|
||||
insert.bindString(INDEX_SMS_MESSAGE_URI, mSmsMessageUri.toString());
|
||||
}
|
||||
insert.bindLong(INDEX_SMS_PRIORITY, mSmsPriority);
|
||||
insert.bindLong(INDEX_SMS_MESSAGE_SIZE, mSmsMessageSize);
|
||||
insert.bindLong(INDEX_MMS_EXPIRY, mMmsExpiry);
|
||||
if (mMmsSubject != null) {
|
||||
insert.bindString(INDEX_MMS_SUBJECT, mMmsSubject);
|
||||
}
|
||||
if (mMmsTransactionId != null) {
|
||||
insert.bindString(INDEX_MMS_TRANSACTION_ID, mMmsTransactionId);
|
||||
}
|
||||
if (mMmsContentLocation != null) {
|
||||
insert.bindString(INDEX_MMS_CONTENT_LOCATION, mMmsContentLocation);
|
||||
}
|
||||
insert.bindLong(INDEX_RAW_TELEPHONY_STATUS, mRawStatus);
|
||||
insert.bindLong(INDEX_RETRY_START_TIMESTAMP, mRetryStartTimestamp);
|
||||
return insert;
|
||||
}
|
||||
|
||||
public final String getMessageId() {
|
||||
return mMessageId;
|
||||
}
|
||||
|
||||
public final String getConversationId() {
|
||||
return mConversationId;
|
||||
}
|
||||
|
||||
public final String getParticipantId() {
|
||||
return mParticipantId;
|
||||
}
|
||||
|
||||
public final String getSelfId() {
|
||||
return mSelfId;
|
||||
}
|
||||
|
||||
public final long getSentTimeStamp() {
|
||||
return mSentTimestamp;
|
||||
}
|
||||
|
||||
public final long getReceivedTimeStamp() {
|
||||
return mReceivedTimestamp;
|
||||
}
|
||||
|
||||
public final String getFormattedReceivedTimeStamp() {
|
||||
return Dates.getMessageTimeString(mReceivedTimestamp).toString();
|
||||
}
|
||||
|
||||
public final int getProtocol() {
|
||||
return mProtocol;
|
||||
}
|
||||
|
||||
public final int getStatus() {
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
public final Uri getSmsMessageUri() {
|
||||
return mSmsMessageUri;
|
||||
}
|
||||
|
||||
public final int getSmsPriority() {
|
||||
return mSmsPriority;
|
||||
}
|
||||
|
||||
public final long getSmsMessageSize() {
|
||||
return mSmsMessageSize;
|
||||
}
|
||||
|
||||
public final String getMmsSubject() {
|
||||
return mMmsSubject;
|
||||
}
|
||||
|
||||
public final void setMmsSubject(final String subject) {
|
||||
mMmsSubject = subject;
|
||||
}
|
||||
|
||||
public final String getMmsContentLocation() {
|
||||
return mMmsContentLocation;
|
||||
}
|
||||
|
||||
public final String getMmsTransactionId() {
|
||||
return mMmsTransactionId;
|
||||
}
|
||||
|
||||
public final boolean getMessageSeen() {
|
||||
return mSeen;
|
||||
}
|
||||
|
||||
/**
|
||||
* For incoming MMS messages this returns the retrieve-status value
|
||||
* For sent MMS messages this returns the response-status value
|
||||
* See PduHeaders.java for possible values
|
||||
* Otherwise (SMS etc) this is RAW_TELEPHONY_STATUS_UNDEFINED
|
||||
*/
|
||||
public final int getRawTelephonyStatus() {
|
||||
return mRawStatus;
|
||||
}
|
||||
|
||||
public final void setMessageSeen(final boolean hasSeen) {
|
||||
mSeen = hasSeen;
|
||||
}
|
||||
|
||||
public final boolean getInResendWindow(final long now) {
|
||||
final long maxAgeToResend = BugleGservices.get().getLong(
|
||||
BugleGservicesKeys.MESSAGE_RESEND_TIMEOUT_MS,
|
||||
BugleGservicesKeys.MESSAGE_RESEND_TIMEOUT_MS_DEFAULT);
|
||||
final long age = now - mRetryStartTimestamp;
|
||||
return age < maxAgeToResend;
|
||||
}
|
||||
|
||||
public final boolean getInDownloadWindow(final long now) {
|
||||
final long maxAgeToRedownload = BugleGservices.get().getLong(
|
||||
BugleGservicesKeys.MESSAGE_DOWNLOAD_TIMEOUT_MS,
|
||||
BugleGservicesKeys.MESSAGE_DOWNLOAD_TIMEOUT_MS_DEFAULT);
|
||||
final long age = now - mRetryStartTimestamp;
|
||||
return age < maxAgeToRedownload;
|
||||
}
|
||||
|
||||
static boolean getShowDownloadMessage(final int status) {
|
||||
if (OsUtil.isSecondaryUser()) {
|
||||
// Secondary users can't download mms's. Mms's are downloaded by bugle running as the
|
||||
// primary user.
|
||||
return false;
|
||||
}
|
||||
// Should show option for manual download iff status is manual download or failed
|
||||
return (status == BUGLE_STATUS_INCOMING_DOWNLOAD_FAILED ||
|
||||
status == BUGLE_STATUS_INCOMING_YET_TO_MANUAL_DOWNLOAD ||
|
||||
// If debug is enabled, allow to download an expired or unavailable message.
|
||||
(DebugUtils.isDebugEnabled()
|
||||
&& status == BUGLE_STATUS_INCOMING_EXPIRED_OR_NOT_AVAILABLE));
|
||||
}
|
||||
|
||||
public boolean canDownloadMessage() {
|
||||
if (OsUtil.isSecondaryUser()) {
|
||||
// Secondary users can't download mms's. Mms's are downloaded by bugle running as the
|
||||
// primary user.
|
||||
return false;
|
||||
}
|
||||
// Can download iff status is retrying auto/manual downloading
|
||||
return (mStatus == BUGLE_STATUS_INCOMING_RETRYING_MANUAL_DOWNLOAD ||
|
||||
mStatus == BUGLE_STATUS_INCOMING_RETRYING_AUTO_DOWNLOAD);
|
||||
}
|
||||
|
||||
public boolean canRedownloadMessage() {
|
||||
if (OsUtil.isSecondaryUser()) {
|
||||
// Secondary users can't download mms's. Mms's are downloaded by bugle running as the
|
||||
// primary user.
|
||||
return false;
|
||||
}
|
||||
// Can redownload iff status is manual download not started or download failed
|
||||
return (mStatus == BUGLE_STATUS_INCOMING_DOWNLOAD_FAILED ||
|
||||
mStatus == BUGLE_STATUS_INCOMING_YET_TO_MANUAL_DOWNLOAD ||
|
||||
// If debug is enabled, allow to download an expired or unavailable message.
|
||||
(DebugUtils.isDebugEnabled()
|
||||
&& mStatus == BUGLE_STATUS_INCOMING_EXPIRED_OR_NOT_AVAILABLE));
|
||||
}
|
||||
|
||||
static boolean getShowResendMessage(final int status) {
|
||||
// Should show option to resend iff status is failed
|
||||
return (status == BUGLE_STATUS_OUTGOING_FAILED);
|
||||
}
|
||||
|
||||
static boolean getOneClickResendMessage(final int status, final int rawStatus) {
|
||||
// Should show option to resend iff status is failed
|
||||
return (status == BUGLE_STATUS_OUTGOING_FAILED
|
||||
&& rawStatus == RAW_TELEPHONY_STATUS_UNDEFINED);
|
||||
}
|
||||
|
||||
public boolean canResendMessage() {
|
||||
// Manual retry allowed only from failed
|
||||
return (mStatus == BUGLE_STATUS_OUTGOING_FAILED);
|
||||
}
|
||||
|
||||
public boolean canSendMessage() {
|
||||
// Sending messages must be in yet_to_send or awaiting_retry state
|
||||
return (mStatus == BUGLE_STATUS_OUTGOING_YET_TO_SEND ||
|
||||
mStatus == BUGLE_STATUS_OUTGOING_AWAITING_RETRY);
|
||||
}
|
||||
|
||||
public final boolean getYetToSend() {
|
||||
return (mStatus == BUGLE_STATUS_OUTGOING_YET_TO_SEND);
|
||||
}
|
||||
|
||||
public final boolean getIsMms() {
|
||||
return mProtocol == MessageData.PROTOCOL_MMS
|
||||
|| mProtocol == MessageData.PROTOCOL_MMS_PUSH_NOTIFICATION;
|
||||
}
|
||||
|
||||
public static final boolean getIsMmsNotification(final int protocol) {
|
||||
return (protocol == MessageData.PROTOCOL_MMS_PUSH_NOTIFICATION);
|
||||
}
|
||||
|
||||
public final boolean getIsMmsNotification() {
|
||||
return getIsMmsNotification(mProtocol);
|
||||
}
|
||||
|
||||
public static final boolean getIsSms(final int protocol) {
|
||||
return protocol == (MessageData.PROTOCOL_SMS);
|
||||
}
|
||||
|
||||
public final boolean getIsSms() {
|
||||
return getIsSms(mProtocol);
|
||||
}
|
||||
|
||||
public static boolean getIsIncoming(final int status) {
|
||||
return (status >= MessageData.BUGLE_STATUS_FIRST_INCOMING);
|
||||
}
|
||||
|
||||
public boolean getIsIncoming() {
|
||||
return getIsIncoming(mStatus);
|
||||
}
|
||||
|
||||
public long getRetryStartTimestamp() {
|
||||
return mRetryStartTimestamp;
|
||||
}
|
||||
|
||||
public final String getMessageText() {
|
||||
final String separator = System.getProperty("line.separator");
|
||||
final StringBuilder text = new StringBuilder();
|
||||
for (final MessagePartData part : mParts) {
|
||||
if (!part.isAttachment() && !TextUtils.isEmpty(part.getText())) {
|
||||
if (text.length() > 0) {
|
||||
text.append(separator);
|
||||
}
|
||||
text.append(part.getText());
|
||||
}
|
||||
}
|
||||
return text.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes all captions from attachments and adds them as a prefix to the first text part or
|
||||
* appends a text part
|
||||
*/
|
||||
public final void consolidateText() {
|
||||
final String separator = System.getProperty("line.separator");
|
||||
final StringBuilder captionText = new StringBuilder();
|
||||
MessagePartData firstTextPart = null;
|
||||
int firstTextPartIndex = -1;
|
||||
for (int i = 0; i < mParts.size(); i++) {
|
||||
final MessagePartData part = mParts.get(i);
|
||||
if (firstTextPart == null && !part.isAttachment()) {
|
||||
firstTextPart = part;
|
||||
firstTextPartIndex = i;
|
||||
}
|
||||
if (part.isAttachment() && !TextUtils.isEmpty(part.getText())) {
|
||||
if (captionText.length() > 0) {
|
||||
captionText.append(separator);
|
||||
}
|
||||
captionText.append(part.getText());
|
||||
}
|
||||
}
|
||||
|
||||
if (captionText.length() == 0) {
|
||||
// Nothing to consolidate
|
||||
return;
|
||||
}
|
||||
|
||||
if (firstTextPart == null) {
|
||||
addPart(MessagePartData.createTextMessagePart(captionText.toString()));
|
||||
} else {
|
||||
final String partText = firstTextPart.getText();
|
||||
if (partText.length() > 0) {
|
||||
captionText.append(separator);
|
||||
captionText.append(partText);
|
||||
}
|
||||
mParts.set(firstTextPartIndex,
|
||||
MessagePartData.createTextMessagePart(captionText.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
public final MessagePartData getFirstAttachment() {
|
||||
for (final MessagePartData part : mParts) {
|
||||
if (part.isAttachment()) {
|
||||
return part;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the messageId for this message.
|
||||
* Can be used to reset the messageId prior to persisting (which will assign a new messageId)
|
||||
* or can be called on a message that does not yet have a valid messageId to set it.
|
||||
*/
|
||||
public void updateMessageId(final String messageId) {
|
||||
Assert.isTrue(TextUtils.isEmpty(messageId) || TextUtils.isEmpty(mMessageId));
|
||||
mMessageId = messageId;
|
||||
|
||||
// TODO : This should probably also call updateMessageId on the message parts. We
|
||||
// may also want to make messages effectively immutable once they have a valid message id.
|
||||
}
|
||||
|
||||
public final void updateSendingMessage(final String conversationId, final Uri messageUri,
|
||||
final long timestamp) {
|
||||
mConversationId = conversationId;
|
||||
mSmsMessageUri = messageUri;
|
||||
mRead = true;
|
||||
mSeen = true;
|
||||
mReceivedTimestamp = timestamp;
|
||||
mSentTimestamp = timestamp;
|
||||
mStatus = BUGLE_STATUS_OUTGOING_YET_TO_SEND;
|
||||
mRetryStartTimestamp = timestamp;
|
||||
}
|
||||
|
||||
public final void markMessageManualResend(final long timestamp) {
|
||||
// Manual send updates timestamp and transitions back to initial sending status.
|
||||
mReceivedTimestamp = timestamp;
|
||||
mSentTimestamp = timestamp;
|
||||
mStatus = BUGLE_STATUS_OUTGOING_SENDING;
|
||||
}
|
||||
|
||||
public final void markMessageSending(final long timestamp) {
|
||||
// Initial send
|
||||
mStatus = BUGLE_STATUS_OUTGOING_SENDING;
|
||||
mSentTimestamp = timestamp;
|
||||
}
|
||||
|
||||
public final void markMessageResending(final long timestamp) {
|
||||
// Auto resend of message
|
||||
mStatus = BUGLE_STATUS_OUTGOING_RESENDING;
|
||||
mSentTimestamp = timestamp;
|
||||
}
|
||||
|
||||
public final void markMessageSent(final long timestamp) {
|
||||
mSentTimestamp = timestamp;
|
||||
mStatus = BUGLE_STATUS_OUTGOING_COMPLETE;
|
||||
}
|
||||
|
||||
public final void markMessageFailed(final long timestamp) {
|
||||
mSentTimestamp = timestamp;
|
||||
mStatus = BUGLE_STATUS_OUTGOING_FAILED;
|
||||
}
|
||||
|
||||
public final void markMessageFailedEmergencyNumber(final long timestamp) {
|
||||
mSentTimestamp = timestamp;
|
||||
mStatus = BUGLE_STATUS_OUTGOING_FAILED_EMERGENCY_NUMBER;
|
||||
}
|
||||
|
||||
public final void markMessageNotSent(final long timestamp) {
|
||||
mSentTimestamp = timestamp;
|
||||
mStatus = BUGLE_STATUS_OUTGOING_AWAITING_RETRY;
|
||||
}
|
||||
|
||||
public final void updateSizesForImageParts() {
|
||||
for (final MessagePartData part : getParts()) {
|
||||
part.decodeAndSaveSizeIfImage(false /* saveToStorage */);
|
||||
}
|
||||
}
|
||||
|
||||
public final void setRetryStartTimestamp(final long timestamp) {
|
||||
mRetryStartTimestamp = timestamp;
|
||||
}
|
||||
|
||||
public final void setRawTelephonyStatus(final int rawStatus) {
|
||||
mRawStatus = rawStatus;
|
||||
}
|
||||
|
||||
public boolean hasContent() {
|
||||
return !TextUtils.isEmpty(mMmsSubject) ||
|
||||
getFirstAttachment() != null ||
|
||||
!TextUtils.isEmpty(getMessageText());
|
||||
}
|
||||
|
||||
public final void bindSelfId(final String selfId) {
|
||||
mSelfId = selfId;
|
||||
}
|
||||
|
||||
public final void bindParticipantId(final String participantId) {
|
||||
mParticipantId = participantId;
|
||||
}
|
||||
|
||||
protected MessageData(final Parcel in) {
|
||||
mMessageId = in.readString();
|
||||
mConversationId = in.readString();
|
||||
mParticipantId = in.readString();
|
||||
mSelfId = in.readString();
|
||||
mSentTimestamp = in.readLong();
|
||||
mReceivedTimestamp = in.readLong();
|
||||
mSeen = (in.readInt() != 0);
|
||||
mRead = (in.readInt() != 0);
|
||||
mProtocol = in.readInt();
|
||||
mStatus = in.readInt();
|
||||
final String smsMessageUri = in.readString();
|
||||
mSmsMessageUri = (smsMessageUri == null ? null : Uri.parse(smsMessageUri));
|
||||
mSmsPriority = in.readInt();
|
||||
mSmsMessageSize = in.readLong();
|
||||
mMmsExpiry = in.readLong();
|
||||
mMmsSubject = in.readString();
|
||||
mMmsTransactionId = in.readString();
|
||||
mMmsContentLocation = in.readString();
|
||||
mRawStatus = in.readInt();
|
||||
mRetryStartTimestamp = in.readLong();
|
||||
|
||||
// Read parts
|
||||
mParts = new ArrayList<MessagePartData>();
|
||||
final int partCount = in.readInt();
|
||||
for (int i = 0; i < partCount; i++) {
|
||||
mParts.add((MessagePartData) in.readParcelable(MessagePartData.class.getClassLoader()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(final Parcel dest, final int flags) {
|
||||
dest.writeString(mMessageId);
|
||||
dest.writeString(mConversationId);
|
||||
dest.writeString(mParticipantId);
|
||||
dest.writeString(mSelfId);
|
||||
dest.writeLong(mSentTimestamp);
|
||||
dest.writeLong(mReceivedTimestamp);
|
||||
dest.writeInt(mRead ? 1 : 0);
|
||||
dest.writeInt(mSeen ? 1 : 0);
|
||||
dest.writeInt(mProtocol);
|
||||
dest.writeInt(mStatus);
|
||||
final String smsMessageUri = (mSmsMessageUri == null) ? null : mSmsMessageUri.toString();
|
||||
dest.writeString(smsMessageUri);
|
||||
dest.writeInt(mSmsPriority);
|
||||
dest.writeLong(mSmsMessageSize);
|
||||
dest.writeLong(mMmsExpiry);
|
||||
dest.writeString(mMmsSubject);
|
||||
dest.writeString(mMmsTransactionId);
|
||||
dest.writeString(mMmsContentLocation);
|
||||
dest.writeInt(mRawStatus);
|
||||
dest.writeLong(mRetryStartTimestamp);
|
||||
|
||||
// Write parts
|
||||
dest.writeInt(mParts.size());
|
||||
for (final MessagePartData messagePartData : mParts) {
|
||||
dest.writeParcelable(messagePartData, flags);
|
||||
}
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<MessageData> CREATOR
|
||||
= new Parcelable.Creator<MessageData>() {
|
||||
@Override
|
||||
public MessageData createFromParcel(final Parcel in) {
|
||||
return new MessageData(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MessageData[] newArray(final int size) {
|
||||
return new MessageData[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toString(mMessageId, mParts);
|
||||
}
|
||||
|
||||
public static String toString(String messageId, List<MessagePartData> parts) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (messageId != null) {
|
||||
sb.append(messageId);
|
||||
sb.append(": ");
|
||||
}
|
||||
for (MessagePartData part : parts) {
|
||||
sb.append(part.toString());
|
||||
sb.append(" ");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user