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