1/*
2 * Copyright (C) 2008 Esmertec AG.
3 * Copyright (C) 2008 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 *      http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18package com.android.mms.transaction;
19
20import android.content.ContentUris;
21import android.content.ContentValues;
22import android.content.Context;
23import android.content.Intent;
24import android.content.SharedPreferences;
25import android.net.Uri;
26import android.preference.PreferenceManager;
27import android.provider.Telephony.Mms;
28import android.provider.Telephony.MmsSms;
29import android.provider.Telephony.MmsSms.PendingMessages;
30import android.util.Log;
31
32import com.android.mms.LogTag;
33import com.android.mms.ui.ComposeMessageActivity;
34import com.android.mms.ui.MessagingPreferenceActivity;
35import com.android.mms.util.SendingProgressTokenManager;
36import com.google.android.mms.InvalidHeaderValueException;
37import com.google.android.mms.MmsException;
38import com.google.android.mms.pdu.EncodedStringValue;
39import com.google.android.mms.pdu.GenericPdu;
40import com.google.android.mms.pdu.PduHeaders;
41import com.google.android.mms.pdu.PduPersister;
42import com.google.android.mms.pdu.ReadRecInd;
43import com.google.android.mms.pdu.SendReq;
44import com.google.android.mms.util.SqliteWrapper;
45
46public class MmsMessageSender implements MessageSender {
47    private static final String TAG = LogTag.TAG;
48
49    private final Context mContext;
50    private final Uri mMessageUri;
51    private final long mMessageSize;
52
53    // Default preference values
54    private static final boolean DEFAULT_DELIVERY_REPORT_MODE  = false;
55    private static final boolean DEFAULT_READ_REPORT_MODE      = false;
56    private static final long    DEFAULT_EXPIRY_TIME     = 7 * 24 * 60 * 60;
57    private static final int     DEFAULT_PRIORITY        = PduHeaders.PRIORITY_NORMAL;
58    private static final String  DEFAULT_MESSAGE_CLASS   = PduHeaders.MESSAGE_CLASS_PERSONAL_STR;
59
60    public MmsMessageSender(Context context, Uri location, long messageSize) {
61        mContext = context;
62        mMessageUri = location;
63        mMessageSize = messageSize;
64
65        if (mMessageUri == null) {
66            throw new IllegalArgumentException("Null message URI.");
67        }
68    }
69
70    public boolean sendMessage(long token) throws MmsException {
71        // Load the MMS from the message uri
72        if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
73            LogTag.debug("sendMessage uri: " + mMessageUri);
74        }
75        PduPersister p = PduPersister.getPduPersister(mContext);
76        GenericPdu pdu = p.load(mMessageUri);
77
78        if (pdu.getMessageType() != PduHeaders.MESSAGE_TYPE_SEND_REQ) {
79            throw new MmsException("Invalid message: " + pdu.getMessageType());
80        }
81
82        SendReq sendReq = (SendReq) pdu;
83
84        // Update headers.
85        updatePreferencesHeaders(sendReq);
86
87        // MessageClass.
88        sendReq.setMessageClass(DEFAULT_MESSAGE_CLASS.getBytes());
89
90        // Update the 'date' field of the message before sending it.
91        sendReq.setDate(System.currentTimeMillis() / 1000L);
92
93        sendReq.setMessageSize(mMessageSize);
94
95        p.updateHeaders(mMessageUri, sendReq);
96
97        long messageId = ContentUris.parseId(mMessageUri);
98
99        // Move the message into MMS Outbox.
100        if (!mMessageUri.toString().startsWith(Mms.Draft.CONTENT_URI.toString())) {
101            // If the message is already in the outbox (most likely because we created a "primed"
102            // message in the outbox when the user hit send), then we have to manually put an
103            // entry in the pending_msgs table which is where TransacationService looks for
104            // messages to send. Normally, the entry in pending_msgs is created by the trigger:
105            // insert_mms_pending_on_update, when a message is moved from drafts to the outbox.
106            ContentValues values = new ContentValues(7);
107
108            values.put(PendingMessages.PROTO_TYPE, MmsSms.MMS_PROTO);
109            values.put(PendingMessages.MSG_ID, messageId);
110            values.put(PendingMessages.MSG_TYPE, pdu.getMessageType());
111            values.put(PendingMessages.ERROR_TYPE, 0);
112            values.put(PendingMessages.ERROR_CODE, 0);
113            values.put(PendingMessages.RETRY_INDEX, 0);
114            values.put(PendingMessages.DUE_TIME, 0);
115
116            SqliteWrapper.insert(mContext, mContext.getContentResolver(),
117                    PendingMessages.CONTENT_URI, values);
118        } else {
119            p.move(mMessageUri, Mms.Outbox.CONTENT_URI);
120        }
121
122        // Start MMS transaction service
123        SendingProgressTokenManager.put(messageId, token);
124        mContext.startService(new Intent(mContext, TransactionService.class));
125
126        return true;
127    }
128
129    // Update the headers which are stored in SharedPreferences.
130    private void updatePreferencesHeaders(SendReq sendReq) throws MmsException {
131        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
132
133        // Expiry.
134        sendReq.setExpiry(prefs.getLong(
135                MessagingPreferenceActivity.EXPIRY_TIME, DEFAULT_EXPIRY_TIME));
136
137        // Priority.
138        sendReq.setPriority(prefs.getInt(MessagingPreferenceActivity.PRIORITY, DEFAULT_PRIORITY));
139
140        // Delivery report.
141        boolean dr = prefs.getBoolean(MessagingPreferenceActivity.MMS_DELIVERY_REPORT_MODE,
142                DEFAULT_DELIVERY_REPORT_MODE);
143        sendReq.setDeliveryReport(dr?PduHeaders.VALUE_YES:PduHeaders.VALUE_NO);
144
145        // Read report.
146        boolean rr = prefs.getBoolean(MessagingPreferenceActivity.READ_REPORT_MODE,
147                DEFAULT_READ_REPORT_MODE);
148        sendReq.setReadReport(rr?PduHeaders.VALUE_YES:PduHeaders.VALUE_NO);
149    }
150
151    public static void sendReadRec(Context context, String to, String messageId, int status) {
152        EncodedStringValue[] sender = new EncodedStringValue[1];
153        sender[0] = new EncodedStringValue(to);
154
155        try {
156            final ReadRecInd readRec = new ReadRecInd(
157                    new EncodedStringValue(PduHeaders.FROM_INSERT_ADDRESS_TOKEN_STR.getBytes()),
158                    messageId.getBytes(),
159                    PduHeaders.CURRENT_MMS_VERSION,
160                    status,
161                    sender);
162
163            readRec.setDate(System.currentTimeMillis() / 1000);
164
165            PduPersister.getPduPersister(context).persist(readRec, Mms.Outbox.CONTENT_URI, true,
166                    MessagingPreferenceActivity.getIsGroupMmsEnabled(context), null);
167            context.startService(new Intent(context, TransactionService.class));
168        } catch (InvalidHeaderValueException e) {
169            Log.e(TAG, "Invalide header value", e);
170        } catch (MmsException e) {
171            Log.e(TAG, "Persist message failed", e);
172        }
173    }
174}
175