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.ContentValues;
     20 import android.content.Context;
     21 import android.net.Uri;
     22 import android.os.Parcel;
     23 import android.os.Parcelable;
     24 import android.provider.Telephony.Sms;
     25 import android.text.TextUtils;
     26 
     27 import com.android.messaging.Factory;
     28 import com.android.messaging.datamodel.BugleDatabaseOperations;
     29 import com.android.messaging.datamodel.BugleNotifications;
     30 import com.android.messaging.datamodel.DataModel;
     31 import com.android.messaging.datamodel.DatabaseWrapper;
     32 import com.android.messaging.datamodel.MessagingContentProvider;
     33 import com.android.messaging.datamodel.SyncManager;
     34 import com.android.messaging.datamodel.data.MessageData;
     35 import com.android.messaging.datamodel.data.ParticipantData;
     36 import com.android.messaging.sms.MmsSmsUtils;
     37 import com.android.messaging.util.LogUtil;
     38 import com.android.messaging.util.OsUtil;
     39 
     40 /**
     41  * Action used to "receive" an incoming message
     42  */
     43 public class ReceiveSmsMessageAction extends Action implements Parcelable {
     44     private static final String TAG = LogUtil.BUGLE_DATAMODEL_TAG;
     45 
     46     private static final String KEY_MESSAGE_VALUES = "message_values";
     47 
     48     /**
     49      * Create a message received from a particular number in a particular conversation
     50      */
     51     public ReceiveSmsMessageAction(final ContentValues messageValues) {
     52         actionParameters.putParcelable(KEY_MESSAGE_VALUES, messageValues);
     53     }
     54 
     55     @Override
     56     protected Object executeAction() {
     57         final Context context = Factory.get().getApplicationContext();
     58         final ContentValues messageValues = actionParameters.getParcelable(KEY_MESSAGE_VALUES);
     59         final DatabaseWrapper db = DataModel.get().getDatabase();
     60 
     61         // Get the SIM subscription ID
     62         Integer subId = messageValues.getAsInteger(Sms.SUBSCRIPTION_ID);
     63         if (subId == null) {
     64             subId = ParticipantData.DEFAULT_SELF_SUB_ID;
     65         }
     66         // Make sure we have a sender address
     67         String address = messageValues.getAsString(Sms.ADDRESS);
     68         if (TextUtils.isEmpty(address)) {
     69             LogUtil.w(TAG, "Received an SMS without an address; using unknown sender.");
     70             address = ParticipantData.getUnknownSenderDestination();
     71             messageValues.put(Sms.ADDRESS, address);
     72         }
     73         final ParticipantData rawSender = ParticipantData.getFromRawPhoneBySimLocale(
     74                 address, subId);
     75 
     76         // TODO: Should use local timestamp for this?
     77         final long received = messageValues.getAsLong(Sms.DATE);
     78         // Inform sync that message has been added at local received timestamp
     79         final SyncManager syncManager = DataModel.get().getSyncManager();
     80         syncManager.onNewMessageInserted(received);
     81 
     82         // Make sure we've got a thread id
     83         final long threadId = MmsSmsUtils.Threads.getOrCreateThreadId(context, address);
     84         messageValues.put(Sms.THREAD_ID, threadId);
     85         final boolean blocked = BugleDatabaseOperations.isBlockedDestination(
     86                 db, rawSender.getNormalizedDestination());
     87         final String conversationId = BugleDatabaseOperations.
     88                 getOrCreateConversationFromRecipient(db, threadId, blocked, rawSender);
     89 
     90         final boolean messageInFocusedConversation =
     91                 DataModel.get().isFocusedConversation(conversationId);
     92         final boolean messageInObservableConversation =
     93                 DataModel.get().isNewMessageObservable(conversationId);
     94 
     95         MessageData message = null;
     96         // Only the primary user gets to insert the message into the telephony db and into bugle's
     97         // db. The secondary user goes through this path, but skips doing the actual insert. It
     98         // goes through this path because it needs to compute messageInFocusedConversation in order
     99         // to calculate whether to skip the notification and play a soft sound if the user is
    100         // already in the conversation.
    101         if (!OsUtil.isSecondaryUser()) {
    102             final boolean read = messageValues.getAsBoolean(Sms.Inbox.READ)
    103                     || messageInFocusedConversation;
    104             // If you have read it you have seen it
    105             final boolean seen = read || messageInObservableConversation || blocked;
    106             messageValues.put(Sms.Inbox.READ, read ? Integer.valueOf(1) : Integer.valueOf(0));
    107 
    108             // incoming messages are marked as seen in the telephony db
    109             messageValues.put(Sms.Inbox.SEEN, 1);
    110 
    111             // Insert into telephony
    112             final Uri messageUri = context.getContentResolver().insert(Sms.Inbox.CONTENT_URI,
    113                     messageValues);
    114 
    115             if (messageUri != null) {
    116                 if (LogUtil.isLoggable(TAG, LogUtil.DEBUG)) {
    117                     LogUtil.d(TAG, "ReceiveSmsMessageAction: Inserted SMS message into telephony, "
    118                             + "uri = " + messageUri);
    119                 }
    120             } else {
    121                 LogUtil.e(TAG, "ReceiveSmsMessageAction: Failed to insert SMS into telephony!");
    122             }
    123 
    124             final String text = messageValues.getAsString(Sms.BODY);
    125             final String subject = messageValues.getAsString(Sms.SUBJECT);
    126             final long sent = messageValues.getAsLong(Sms.DATE_SENT);
    127             final ParticipantData self = ParticipantData.getSelfParticipant(subId);
    128             final Integer pathPresent = messageValues.getAsInteger(Sms.REPLY_PATH_PRESENT);
    129             final String smsServiceCenter = messageValues.getAsString(Sms.SERVICE_CENTER);
    130             String conversationServiceCenter = null;
    131             // Only set service center if message REPLY_PATH_PRESENT = 1
    132             if (pathPresent != null && pathPresent == 1 && !TextUtils.isEmpty(smsServiceCenter)) {
    133                 conversationServiceCenter = smsServiceCenter;
    134             }
    135             db.beginTransaction();
    136             try {
    137                 final String participantId =
    138                         BugleDatabaseOperations.getOrCreateParticipantInTransaction(db, rawSender);
    139                 final String selfId =
    140                         BugleDatabaseOperations.getOrCreateParticipantInTransaction(db, self);
    141 
    142                 message = MessageData.createReceivedSmsMessage(messageUri, conversationId,
    143                         participantId, selfId, text, subject, sent, received, seen, read);
    144 
    145                 BugleDatabaseOperations.insertNewMessageInTransaction(db, message);
    146 
    147                 BugleDatabaseOperations.updateConversationMetadataInTransaction(db, conversationId,
    148                         message.getMessageId(), message.getReceivedTimeStamp(), blocked,
    149                         conversationServiceCenter, true /* shouldAutoSwitchSelfId */);
    150 
    151                 final ParticipantData sender = ParticipantData.getFromId(db, participantId);
    152                 BugleActionToasts.onMessageReceived(conversationId, sender, message);
    153                 db.setTransactionSuccessful();
    154             } finally {
    155                 db.endTransaction();
    156             }
    157             LogUtil.i(TAG, "ReceiveSmsMessageAction: Received SMS message " + message.getMessageId()
    158                     + " in conversation " + message.getConversationId()
    159                     + ", uri = " + messageUri);
    160 
    161             ProcessPendingMessagesAction.scheduleProcessPendingMessagesAction(false, this);
    162         } else {
    163             if (LogUtil.isLoggable(TAG, LogUtil.DEBUG)) {
    164                 LogUtil.d(TAG, "ReceiveSmsMessageAction: Not inserting received SMS message for "
    165                         + "secondary user.");
    166             }
    167         }
    168         // Show a notification to let the user know a new message has arrived
    169         BugleNotifications.update(false/*silent*/, conversationId, BugleNotifications.UPDATE_ALL);
    170 
    171         MessagingContentProvider.notifyMessagesChanged(conversationId);
    172         MessagingContentProvider.notifyPartsChanged();
    173 
    174         return message;
    175     }
    176 
    177     private ReceiveSmsMessageAction(final Parcel in) {
    178         super(in);
    179     }
    180 
    181     public static final Parcelable.Creator<ReceiveSmsMessageAction> CREATOR
    182             = new Parcelable.Creator<ReceiveSmsMessageAction>() {
    183         @Override
    184         public ReceiveSmsMessageAction createFromParcel(final Parcel in) {
    185             return new ReceiveSmsMessageAction(in);
    186         }
    187 
    188         @Override
    189         public ReceiveSmsMessageAction[] newArray(final int size) {
    190             return new ReceiveSmsMessageAction[size];
    191         }
    192     };
    193 
    194     @Override
    195     public void writeToParcel(final Parcel parcel, final int flags) {
    196         writeActionToParcel(parcel, flags);
    197     }
    198 }
    199