summaryrefslogtreecommitdiffstats
path: root/src/com/android/messaging/datamodel/action/SendMessageAction.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/messaging/datamodel/action/SendMessageAction.java')
-rw-r--r--src/com/android/messaging/datamodel/action/SendMessageAction.java447
1 files changed, 0 insertions, 447 deletions
diff --git a/src/com/android/messaging/datamodel/action/SendMessageAction.java b/src/com/android/messaging/datamodel/action/SendMessageAction.java
deleted file mode 100644
index d7ebe8f..0000000
--- a/src/com/android/messaging/datamodel/action/SendMessageAction.java
+++ /dev/null
@@ -1,447 +0,0 @@
-/*
- * 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.action;
-
-import android.content.ContentValues;
-import android.content.Context;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.provider.Telephony.Mms;
-import android.provider.Telephony.Sms;
-
-import com.android.messaging.Factory;
-import com.android.messaging.datamodel.BugleDatabaseOperations;
-import com.android.messaging.datamodel.DataModel;
-import com.android.messaging.datamodel.DatabaseHelper.MessageColumns;
-import com.android.messaging.datamodel.DatabaseWrapper;
-import com.android.messaging.datamodel.MessagingContentProvider;
-import com.android.messaging.datamodel.SyncManager;
-import com.android.messaging.datamodel.data.MessageData;
-import com.android.messaging.datamodel.data.ParticipantData;
-import com.android.messaging.sms.MmsUtils;
-import com.android.messaging.util.Assert;
-import com.android.messaging.util.LogUtil;
-
-import java.util.ArrayList;
-
-/**
- * Action used to send an outgoing message. It writes MMS messages to the telephony db
- * ({@link InsertNewMessageAction}) writes SMS messages to the telephony db). It also
- * initiates the actual sending. It will all be used for re-sending a failed message.
- * NOTE: This action must queue a ProcessPendingMessagesAction when it is done (success or failure).
- * <p>
- * This class is public (not package-private) because the SMS/MMS (e.g. MmsUtils) classes need to
- * access the EXTRA_* fields for setting up the 'sent' pending intent.
- */
-public class SendMessageAction extends Action implements Parcelable {
- private static final String TAG = LogUtil.BUGLE_DATAMODEL_TAG;
-
- /**
- * Queue sending of existing message (can only be called during execute of action)
- */
- static boolean queueForSendInBackground(final String messageId,
- final Action processingAction) {
- final SendMessageAction action = new SendMessageAction();
- return action.queueAction(messageId, processingAction);
- }
-
- public static final boolean DEFAULT_DELIVERY_REPORT_MODE = false;
- public static final int MAX_SMS_RETRY = 3;
-
- // Core parameters needed for all types of message
- private static final String KEY_MESSAGE_ID = "message_id";
- private static final String KEY_MESSAGE = "message";
- private static final String KEY_MESSAGE_URI = "message_uri";
- private static final String KEY_SUB_PHONE_NUMBER = "sub_phone_number";
-
- // For sms messages a few extra values are included in the bundle
- private static final String KEY_RECIPIENT = "recipient";
- private static final String KEY_RECIPIENTS = "recipients";
- private static final String KEY_SMS_SERVICE_CENTER = "sms_service_center";
-
- // Values we attach to the pending intent that's fired when the message is sent.
- // Only applicable when sending via the platform APIs on L+.
- public static final String KEY_SUB_ID = "sub_id";
- public static final String EXTRA_MESSAGE_ID = "message_id";
- public static final String EXTRA_UPDATED_MESSAGE_URI = "updated_message_uri";
- public static final String EXTRA_CONTENT_URI = "content_uri";
- public static final String EXTRA_RESPONSE_IMPORTANT = "response_important";
-
- /**
- * Constructor used for retrying sending in the background (only message id available)
- */
- private SendMessageAction() {
- super();
- }
-
- /**
- * Read message from database and queue actual sending
- */
- private boolean queueAction(final String messageId, final Action processingAction) {
- actionParameters.putString(KEY_MESSAGE_ID, messageId);
-
- final long timestamp = System.currentTimeMillis();
- final DatabaseWrapper db = DataModel.get().getDatabase();
-
- final MessageData message = BugleDatabaseOperations.readMessage(db, messageId);
- // Check message can be resent
- if (message != null && message.canSendMessage()) {
- final boolean isSms = (message.getProtocol() == MessageData.PROTOCOL_SMS);
-
- final ParticipantData self = BugleDatabaseOperations.getExistingParticipant(
- db, message.getSelfId());
- final Uri messageUri = message.getSmsMessageUri();
- final String conversationId = message.getConversationId();
-
- // Update message status
- if (message.getYetToSend()) {
- // Initial sending of message
- message.markMessageSending(timestamp);
- } else {
- // Automatic resend of message
- message.markMessageResending(timestamp);
- }
- if (!updateMessageAndStatus(isSms, message, null /* messageUri */, false /*notify*/)) {
- // If message is missing in the telephony database we don't need to send it
- return false;
- }
-
- final ArrayList<String> recipients =
- BugleDatabaseOperations.getRecipientsForConversation(db, conversationId);
-
- // Update action state with parameters needed for background sending
- actionParameters.putParcelable(KEY_MESSAGE_URI, messageUri);
- actionParameters.putParcelable(KEY_MESSAGE, message);
- actionParameters.putStringArrayList(KEY_RECIPIENTS, recipients);
- actionParameters.putInt(KEY_SUB_ID, self.getSubId());
- actionParameters.putString(KEY_SUB_PHONE_NUMBER, self.getNormalizedDestination());
-
- if (isSms) {
- final String smsc = BugleDatabaseOperations.getSmsServiceCenterForConversation(
- db, conversationId);
- actionParameters.putString(KEY_SMS_SERVICE_CENTER, smsc);
-
- if (recipients.size() == 1) {
- final String recipient = recipients.get(0);
-
- actionParameters.putString(KEY_RECIPIENT, recipient);
- // Queue actual sending for SMS
- processingAction.requestBackgroundWork(this);
-
- if (LogUtil.isLoggable(TAG, LogUtil.DEBUG)) {
- LogUtil.d(TAG, "SendMessageAction: Queued SMS message " + messageId
- + " for sending");
- }
- return true;
- } else {
- LogUtil.wtf(TAG, "Trying to resend a broadcast SMS - not allowed");
- }
- } else {
- // Queue actual sending for MMS
- processingAction.requestBackgroundWork(this);
-
- if (LogUtil.isLoggable(TAG, LogUtil.DEBUG)) {
- LogUtil.d(TAG, "SendMessageAction: Queued MMS message " + messageId
- + " for sending");
- }
- return true;
- }
- }
-
- return false;
- }
-
-
- /**
- * Never called
- */
- @Override
- protected Object executeAction() {
- Assert.fail("SendMessageAction must be queued rather than started");
- return null;
- }
-
- /**
- * Send message on background worker thread
- */
- @Override
- protected Bundle doBackgroundWork() {
- final MessageData message = actionParameters.getParcelable(KEY_MESSAGE);
- final String messageId = actionParameters.getString(KEY_MESSAGE_ID);
- Uri messageUri = actionParameters.getParcelable(KEY_MESSAGE_URI);
- Uri updatedMessageUri = null;
- final boolean isSms = message.getProtocol() == MessageData.PROTOCOL_SMS;
- final int subId = actionParameters.getInt(KEY_SUB_ID, ParticipantData.DEFAULT_SELF_SUB_ID);
- final String subPhoneNumber = actionParameters.getString(KEY_SUB_PHONE_NUMBER);
-
- LogUtil.i(TAG, "SendMessageAction: Sending " + (isSms ? "SMS" : "MMS") + " message "
- + messageId + " in conversation " + message.getConversationId());
-
- int status;
- int rawStatus = MessageData.RAW_TELEPHONY_STATUS_UNDEFINED;
- int resultCode = MessageData.UNKNOWN_RESULT_CODE;
- if (isSms) {
- Assert.notNull(messageUri);
- final String recipient = actionParameters.getString(KEY_RECIPIENT);
- final String messageText = message.getMessageText();
- final String smsServiceCenter = actionParameters.getString(KEY_SMS_SERVICE_CENTER);
- final boolean deliveryReportRequired = MmsUtils.isDeliveryReportRequired(subId);
-
- status = MmsUtils.sendSmsMessage(recipient, messageText, messageUri, subId,
- smsServiceCenter, deliveryReportRequired);
- } else {
- final Context context = Factory.get().getApplicationContext();
- final ArrayList<String> recipients =
- actionParameters.getStringArrayList(KEY_RECIPIENTS);
- if (messageUri == null) {
- final long timestamp = message.getReceivedTimeStamp();
-
- // Inform sync that message has been added at local received timestamp
- final SyncManager syncManager = DataModel.get().getSyncManager();
- syncManager.onNewMessageInserted(timestamp);
-
- // For MMS messages first need to write to telephony (resizing images if needed)
- updatedMessageUri = MmsUtils.insertSendingMmsMessage(context, recipients,
- message, subId, subPhoneNumber, timestamp);
- if (updatedMessageUri != null) {
- messageUri = updatedMessageUri;
- // To prevent Sync seeing inconsistent state must write to DB on this thread
- updateMessageUri(messageId, updatedMessageUri);
-
- if (LogUtil.isLoggable(TAG, LogUtil.VERBOSE)) {
- LogUtil.v(TAG, "SendMessageAction: Updated message " + messageId
- + " with new uri " + messageUri);
- }
- }
- }
- if (messageUri != null) {
- // Actually send the MMS
- final Bundle extras = new Bundle();
- extras.putString(EXTRA_MESSAGE_ID, messageId);
- extras.putParcelable(EXTRA_UPDATED_MESSAGE_URI, updatedMessageUri);
- final MmsUtils.StatusPlusUri result = MmsUtils.sendMmsMessage(context, subId,
- messageUri, extras);
- if (result == MmsUtils.STATUS_PENDING) {
- // Async send, so no status yet
- LogUtil.d(TAG, "SendMessageAction: Sending MMS message " + messageId
- + " asynchronously; waiting for callback to finish processing");
- return null;
- }
- status = result.status;
- rawStatus = result.rawStatus;
- resultCode = result.resultCode;
- } else {
- status = MmsUtils.MMS_REQUEST_MANUAL_RETRY;
- }
- }
-
- // When we fast-fail before calling the MMS lib APIs (e.g. airplane mode,
- // sending message is deleted).
- ProcessSentMessageAction.processMessageSentFastFailed(messageId, messageUri,
- updatedMessageUri, subId, isSms, status, rawStatus, resultCode);
- return null;
- }
-
- private void updateMessageUri(final String messageId, final Uri updatedMessageUri) {
- final DatabaseWrapper db = DataModel.get().getDatabase();
- db.beginTransaction();
- try {
- final ContentValues values = new ContentValues();
- values.put(MessageColumns.SMS_MESSAGE_URI, updatedMessageUri.toString());
- BugleDatabaseOperations.updateMessageRow(db, messageId, values);
- db.setTransactionSuccessful();
- } finally {
- db.endTransaction();
- }
- }
-
- @Override
- protected Object processBackgroundResponse(final Bundle response) {
- // Nothing to do here, post-send tasks handled by ProcessSentMessageAction
- return null;
- }
-
- /**
- * Update message status to reflect success or failure
- */
- @Override
- protected Object processBackgroundFailure() {
- final String messageId = actionParameters.getString(KEY_MESSAGE_ID);
- final MessageData message = actionParameters.getParcelable(KEY_MESSAGE);
- final boolean isSms = message.getProtocol() == MessageData.PROTOCOL_SMS;
- final int subId = actionParameters.getInt(KEY_SUB_ID, ParticipantData.DEFAULT_SELF_SUB_ID);
- final int resultCode = actionParameters.getInt(ProcessSentMessageAction.KEY_RESULT_CODE);
- final int httpStatusCode =
- actionParameters.getInt(ProcessSentMessageAction.KEY_HTTP_STATUS_CODE);
-
- ProcessSentMessageAction.processResult(messageId, null /* updatedMessageUri */,
- MmsUtils.MMS_REQUEST_MANUAL_RETRY, MessageData.RAW_TELEPHONY_STATUS_UNDEFINED,
- isSms, this, subId, resultCode, httpStatusCode);
-
- // Whether we succeeded or failed we will check and maybe schedule some more work
- ProcessPendingMessagesAction.scheduleProcessPendingMessagesAction(true, this);
-
- return null;
- }
-
- /**
- * Update the message status (and message itself if necessary)
- * @param isSms whether this is an SMS or MMS
- * @param message message to update
- * @param updatedMessageUri message uri for newly-inserted messages; null otherwise
- * @param clearSeen whether the message 'seen' status should be reset if error occurs
- */
- public static boolean updateMessageAndStatus(final boolean isSms, final MessageData message,
- final Uri updatedMessageUri, final boolean clearSeen) {
- final Context context = Factory.get().getApplicationContext();
- final DatabaseWrapper db = DataModel.get().getDatabase();
-
- // TODO: We're optimistically setting the type/box of outgoing messages to
- // 'SENT' even before they actually are. We should technically be using QUEUED or OUTBOX
- // instead, but if we do that, it's possible that the Messaging app will try to send them
- // as part of its clean-up logic that runs when it starts (http://b/18155366).
- //
- // We also use the wrong status when inserting queued SMS messages in
- // InsertNewMessageAction.insertBroadcastSmsMessage and insertSendingSmsMessage (should be
- // QUEUED or OUTBOX), and in MmsUtils.insertSendReq (should be OUTBOX).
-
- boolean updatedTelephony = true;
- int messageBox;
- int type;
- switch(message.getStatus()) {
- case MessageData.BUGLE_STATUS_OUTGOING_COMPLETE:
- case MessageData.BUGLE_STATUS_OUTGOING_DELIVERED:
- type = Sms.MESSAGE_TYPE_SENT;
- messageBox = Mms.MESSAGE_BOX_SENT;
- break;
- case MessageData.BUGLE_STATUS_OUTGOING_YET_TO_SEND:
- case MessageData.BUGLE_STATUS_OUTGOING_AWAITING_RETRY:
- type = Sms.MESSAGE_TYPE_SENT;
- messageBox = Mms.MESSAGE_BOX_SENT;
- break;
- case MessageData.BUGLE_STATUS_OUTGOING_SENDING:
- case MessageData.BUGLE_STATUS_OUTGOING_RESENDING:
- type = Sms.MESSAGE_TYPE_SENT;
- messageBox = Mms.MESSAGE_BOX_SENT;
- break;
- case MessageData.BUGLE_STATUS_OUTGOING_FAILED:
- case MessageData.BUGLE_STATUS_OUTGOING_FAILED_EMERGENCY_NUMBER:
- type = Sms.MESSAGE_TYPE_FAILED;
- messageBox = Mms.MESSAGE_BOX_FAILED;
- break;
- default:
- type = Sms.MESSAGE_TYPE_ALL;
- messageBox = Mms.MESSAGE_BOX_ALL;
- break;
- }
- // First in the telephony DB
- if (isSms) {
- // Ignore update message Uri
- if (type != Sms.MESSAGE_TYPE_ALL) {
- if (!MmsUtils.updateSmsMessageSendingStatus(context, message.getSmsMessageUri(),
- type, message.getReceivedTimeStamp())) {
- message.markMessageFailed(message.getSentTimeStamp());
- updatedTelephony = false;
- }
- }
- } else if (message.getSmsMessageUri() != null) {
- if (messageBox != Mms.MESSAGE_BOX_ALL) {
- if (!MmsUtils.updateMmsMessageSendingStatus(context, message.getSmsMessageUri(),
- messageBox, message.getReceivedTimeStamp())) {
- message.markMessageFailed(message.getSentTimeStamp());
- updatedTelephony = false;
- }
- }
- }
- if (updatedTelephony) {
- if (LogUtil.isLoggable(TAG, LogUtil.VERBOSE)) {
- LogUtil.v(TAG, "SendMessageAction: Updated " + (isSms ? "SMS" : "MMS")
- + " message " + message.getMessageId()
- + " in telephony (" + message.getSmsMessageUri() + ")");
- }
- } else {
- LogUtil.w(TAG, "SendMessageAction: Failed to update " + (isSms ? "SMS" : "MMS")
- + " message " + message.getMessageId()
- + " in telephony (" + message.getSmsMessageUri() + "); marking message failed");
- }
-
- // Update the local DB
- db.beginTransaction();
- try {
- if (updatedMessageUri != null) {
- // Update all message and part fields
- BugleDatabaseOperations.updateMessageInTransaction(db, message);
- BugleDatabaseOperations.refreshConversationMetadataInTransaction(
- db, message.getConversationId(), false/* shouldAutoSwitchSelfId */,
- false/*archived*/);
- } else {
- final ContentValues values = new ContentValues();
- values.put(MessageColumns.STATUS, message.getStatus());
-
- if (clearSeen) {
- // When a message fails to send, the message needs to
- // be unseen to be selected as an error notification.
- values.put(MessageColumns.SEEN, 0);
- }
- values.put(MessageColumns.RECEIVED_TIMESTAMP, message.getReceivedTimeStamp());
- values.put(MessageColumns.RAW_TELEPHONY_STATUS, message.getRawTelephonyStatus());
-
- BugleDatabaseOperations.updateMessageRowIfExists(db, message.getMessageId(),
- values);
- }
- db.setTransactionSuccessful();
- if (LogUtil.isLoggable(TAG, LogUtil.VERBOSE)) {
- LogUtil.v(TAG, "SendMessageAction: Updated " + (isSms ? "SMS" : "MMS")
- + " message " + message.getMessageId() + " in local db. Timestamp = "
- + message.getReceivedTimeStamp());
- }
- } finally {
- db.endTransaction();
- }
-
- MessagingContentProvider.notifyMessagesChanged(message.getConversationId());
- if (updatedMessageUri != null) {
- MessagingContentProvider.notifyPartsChanged();
- }
-
- return updatedTelephony;
- }
-
- private SendMessageAction(final Parcel in) {
- super(in);
- }
-
- public static final Parcelable.Creator<SendMessageAction> CREATOR
- = new Parcelable.Creator<SendMessageAction>() {
- @Override
- public SendMessageAction createFromParcel(final Parcel in) {
- return new SendMessageAction(in);
- }
-
- @Override
- public SendMessageAction[] newArray(final int size) {
- return new SendMessageAction[size];
- }
- };
-
- @Override
- public void writeToParcel(final Parcel parcel, final int flags) {
- writeActionToParcel(parcel, flags);
- }
-}