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