Home | History | Annotate | Download | only in action
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.messaging.datamodel.action;
     18 
     19 import android.content.Context;
     20 import android.os.Bundle;
     21 import android.os.Parcel;
     22 import android.os.Parcelable;
     23 
     24 import com.android.messaging.Factory;
     25 import com.android.messaging.datamodel.BugleDatabaseOperations;
     26 import com.android.messaging.datamodel.BugleNotifications;
     27 import com.android.messaging.datamodel.DataModel;
     28 import com.android.messaging.datamodel.DataModelException;
     29 import com.android.messaging.datamodel.DatabaseWrapper;
     30 import com.android.messaging.datamodel.MessagingContentProvider;
     31 import com.android.messaging.datamodel.SyncManager;
     32 import com.android.messaging.datamodel.data.MessageData;
     33 import com.android.messaging.datamodel.data.ParticipantData;
     34 import com.android.messaging.mmslib.pdu.PduHeaders;
     35 import com.android.messaging.sms.DatabaseMessages;
     36 import com.android.messaging.sms.MmsUtils;
     37 import com.android.messaging.util.LogUtil;
     38 
     39 import java.util.List;
     40 
     41 /**
     42  * Action used to "receive" an incoming message
     43  */
     44 public class ReceiveMmsMessageAction extends Action implements Parcelable {
     45     private static final String TAG = LogUtil.BUGLE_DATAMODEL_TAG;
     46 
     47     private static final String KEY_SUB_ID = "sub_id";
     48     private static final String KEY_PUSH_DATA = "push_data";
     49     private static final String KEY_TRANSACTION_ID = "transaction_id";
     50     private static final String KEY_CONTENT_LOCATION = "content_location";
     51 
     52     /**
     53      * Create a message received from a particular number in a particular conversation
     54      */
     55     public ReceiveMmsMessageAction(final int subId, final byte[] pushData) {
     56         actionParameters.putInt(KEY_SUB_ID, subId);
     57         actionParameters.putByteArray(KEY_PUSH_DATA, pushData);
     58     }
     59 
     60     @Override
     61     protected Object executeAction() {
     62         final Context context = Factory.get().getApplicationContext();
     63         final int subId = actionParameters.getInt(KEY_SUB_ID, ParticipantData.DEFAULT_SELF_SUB_ID);
     64         final byte[] pushData = actionParameters.getByteArray(KEY_PUSH_DATA);
     65         final DatabaseWrapper db = DataModel.get().getDatabase();
     66 
     67         // Write received message to telephony DB
     68         MessageData message = null;
     69         final ParticipantData self = BugleDatabaseOperations.getOrCreateSelf(db, subId);
     70 
     71         final long received = System.currentTimeMillis();
     72         // Inform sync that message has been added at local received timestamp
     73         final SyncManager syncManager = DataModel.get().getSyncManager();
     74         syncManager.onNewMessageInserted(received);
     75 
     76         // TODO: Should use local time to set received time in MMS message
     77         final DatabaseMessages.MmsMessage mms = MmsUtils.processReceivedPdu(
     78                 context, pushData, self.getSubId(), self.getNormalizedDestination());
     79 
     80         if (mms != null) {
     81             final List<String> recipients = MmsUtils.getRecipientsByThread(mms.mThreadId);
     82             String from = MmsUtils.getMmsSender(recipients, mms.getUri());
     83             if (from == null) {
     84                 LogUtil.w(TAG, "Received an MMS without sender address; using unknown sender.");
     85                 from = ParticipantData.getUnknownSenderDestination();
     86             }
     87             final ParticipantData rawSender = ParticipantData.getFromRawPhoneBySimLocale(
     88                     from, subId);
     89             final boolean blocked = BugleDatabaseOperations.isBlockedDestination(
     90                     db, rawSender.getNormalizedDestination());
     91             final boolean autoDownload = (!blocked && MmsUtils.allowMmsAutoRetrieve(subId));
     92             final String conversationId =
     93                     BugleDatabaseOperations.getOrCreateConversationFromThreadId(db, mms.mThreadId,
     94                             blocked, subId);
     95 
     96             final boolean messageInFocusedConversation =
     97                     DataModel.get().isFocusedConversation(conversationId);
     98             final boolean messageInObservableConversation =
     99                     DataModel.get().isNewMessageObservable(conversationId);
    100 
    101             // TODO: Also write these values to the telephony provider
    102             mms.mRead = messageInFocusedConversation;
    103             mms.mSeen = messageInObservableConversation || blocked;
    104 
    105             // Write received placeholder message to our DB
    106             db.beginTransaction();
    107             try {
    108                 final String participantId =
    109                         BugleDatabaseOperations.getOrCreateParticipantInTransaction(db, rawSender);
    110                 final String selfId =
    111                         BugleDatabaseOperations.getOrCreateParticipantInTransaction(db, self);
    112 
    113                 message = MmsUtils.createMmsMessage(mms, conversationId, participantId, selfId,
    114                         (autoDownload ? MessageData.BUGLE_STATUS_INCOMING_RETRYING_AUTO_DOWNLOAD :
    115                             MessageData.BUGLE_STATUS_INCOMING_YET_TO_MANUAL_DOWNLOAD));
    116                 // Write the message
    117                 BugleDatabaseOperations.insertNewMessageInTransaction(db, message);
    118 
    119                 if (!autoDownload) {
    120                     BugleDatabaseOperations.updateConversationMetadataInTransaction(db,
    121                             conversationId, message.getMessageId(), message.getReceivedTimeStamp(),
    122                             blocked, true /* shouldAutoSwitchSelfId */);
    123                     final ParticipantData sender = ParticipantData .getFromId(
    124                             db, participantId);
    125                     BugleActionToasts.onMessageReceived(conversationId, sender, message);
    126                 }
    127                 // else update the conversation once we have downloaded final message (or failed)
    128                 db.setTransactionSuccessful();
    129             } finally {
    130                 db.endTransaction();
    131             }
    132 
    133             // Update conversation if not immediately initiating a download
    134             if (!autoDownload) {
    135                 MessagingContentProvider.notifyMessagesChanged(message.getConversationId());
    136                 MessagingContentProvider.notifyPartsChanged();
    137 
    138                 // Show a notification to let the user know a new message has arrived
    139                 BugleNotifications.update(false/*silent*/, conversationId,
    140                         BugleNotifications.UPDATE_ALL);
    141 
    142                 // Send the NotifyRespInd with DEFERRED status since no auto download
    143                 actionParameters.putString(KEY_TRANSACTION_ID, mms.mTransactionId);
    144                 actionParameters.putString(KEY_CONTENT_LOCATION, mms.mContentLocation);
    145                 requestBackgroundWork();
    146             }
    147 
    148             LogUtil.i(TAG, "ReceiveMmsMessageAction: Received MMS message " + message.getMessageId()
    149                     + " in conversation " + message.getConversationId()
    150                     + ", uri = " + message.getSmsMessageUri());
    151         } else {
    152             LogUtil.e(TAG, "ReceiveMmsMessageAction: Skipping processing of incoming PDU");
    153         }
    154 
    155         ProcessPendingMessagesAction.scheduleProcessPendingMessagesAction(false, this);
    156 
    157         return message;
    158     }
    159 
    160     @Override
    161     protected Bundle doBackgroundWork() throws DataModelException {
    162         final Context context = Factory.get().getApplicationContext();
    163         final int subId = actionParameters.getInt(KEY_SUB_ID, ParticipantData.DEFAULT_SELF_SUB_ID);
    164         final String transactionId = actionParameters.getString(KEY_TRANSACTION_ID);
    165         final String contentLocation = actionParameters.getString(KEY_CONTENT_LOCATION);
    166         MmsUtils.sendNotifyResponseForMmsDownload(
    167                 context,
    168                 subId,
    169                 MmsUtils.stringToBytes(transactionId, "UTF-8"),
    170                 contentLocation,
    171                 PduHeaders.STATUS_DEFERRED);
    172         // We don't need to return anything.
    173         return null;
    174     }
    175 
    176     private ReceiveMmsMessageAction(final Parcel in) {
    177         super(in);
    178     }
    179 
    180     public static final Parcelable.Creator<ReceiveMmsMessageAction> CREATOR
    181             = new Parcelable.Creator<ReceiveMmsMessageAction>() {
    182         @Override
    183         public ReceiveMmsMessageAction createFromParcel(final Parcel in) {
    184             return new ReceiveMmsMessageAction(in);
    185         }
    186 
    187         @Override
    188         public ReceiveMmsMessageAction[] newArray(final int size) {
    189             return new ReceiveMmsMessageAction[size];
    190         }
    191     };
    192 
    193     @Override
    194     public void writeToParcel(final Parcel parcel, final int flags) {
    195         writeActionToParcel(parcel, flags);
    196     }
    197 }
    198