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