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.Context;
21import android.content.Intent;
22import android.content.SharedPreferences;
23import android.database.Cursor;
24import android.database.sqlite.SQLiteException;
25import android.database.sqlite.SqliteWrapper;
26import android.net.Uri;
27import android.preference.PreferenceManager;
28import android.provider.Telephony.Sms;
29import android.provider.Telephony.Sms.Inbox;
30import android.util.Log;
31
32import com.android.mms.LogTag;
33import com.android.mms.ui.MessagingPreferenceActivity;
34import com.google.android.mms.MmsException;
35
36public class SmsMessageSender implements MessageSender {
37    protected final Context mContext;
38    protected final int mNumberOfDests;
39    private final String[] mDests;
40    protected final String mMessageText;
41    protected final String mServiceCenter;
42    protected final long mThreadId;
43    protected long mTimestamp;
44    private static final String TAG = LogTag.TAG;
45
46    // Default preference values
47    private static final boolean DEFAULT_DELIVERY_REPORT_MODE  = false;
48
49    private static final String[] SERVICE_CENTER_PROJECTION = new String[] {
50        Sms.Conversations.REPLY_PATH_PRESENT,
51        Sms.Conversations.SERVICE_CENTER,
52    };
53
54    private static final int COLUMN_REPLY_PATH_PRESENT = 0;
55    private static final int COLUMN_SERVICE_CENTER     = 1;
56
57    public SmsMessageSender(Context context, String[] dests, String msgText, long threadId) {
58        mContext = context;
59        mMessageText = msgText;
60        if (dests != null) {
61            mNumberOfDests = dests.length;
62            mDests = new String[mNumberOfDests];
63            System.arraycopy(dests, 0, mDests, 0, mNumberOfDests);
64        } else {
65            mNumberOfDests = 0;
66            mDests = null;
67        }
68        mTimestamp = System.currentTimeMillis();
69        mThreadId = threadId;
70        mServiceCenter = getOutgoingServiceCenter(mThreadId);
71    }
72
73    public boolean sendMessage(long token) throws MmsException {
74        // In order to send the message one by one, instead of sending now, the message will split,
75        // and be put into the queue along with each destinations
76        return queueMessage(token);
77    }
78
79    private boolean queueMessage(long token) throws MmsException {
80        if ((mMessageText == null) || (mNumberOfDests == 0)) {
81            // Don't try to send an empty message.
82            throw new MmsException("Null message body or dest.");
83        }
84
85        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
86        boolean requestDeliveryReport = prefs.getBoolean(
87                MessagingPreferenceActivity.SMS_DELIVERY_REPORT_MODE,
88                DEFAULT_DELIVERY_REPORT_MODE);
89
90        for (int i = 0; i < mNumberOfDests; i++) {
91            try {
92                if (LogTag.DEBUG_SEND) {
93                    Log.v(TAG, "queueMessage mDests[i]: " + mDests[i] + " mThreadId: " + mThreadId);
94                }
95                Sms.addMessageToUri(mContext.getContentResolver(),
96                        Uri.parse("content://sms/queued"), mDests[i],
97                        mMessageText, null, mTimestamp,
98                        true /* read */,
99                        requestDeliveryReport,
100                        mThreadId);
101            } catch (SQLiteException e) {
102                if (LogTag.DEBUG_SEND) {
103                    Log.e(TAG, "queueMessage SQLiteException", e);
104                }
105                SqliteWrapper.checkSQLiteException(mContext, e);
106            }
107        }
108        // Notify the SmsReceiverService to send the message out
109        mContext.sendBroadcast(new Intent(SmsReceiverService.ACTION_SEND_MESSAGE,
110                null,
111                mContext,
112                SmsReceiver.class));
113        return false;
114    }
115
116    /**
117     * Get the service center to use for a reply.
118     *
119     * The rule from TS 23.040 D.6 is that we send reply messages to
120     * the service center of the message to which we're replying, but
121     * only if we haven't already replied to that message and only if
122     * <code>TP-Reply-Path</code> was set in that message.
123     *
124     * Therefore, return the service center from the most recent
125     * message in the conversation, but only if it is a message from
126     * the other party, and only if <code>TP-Reply-Path</code> is set.
127     * Otherwise, return null.
128     */
129    private String getOutgoingServiceCenter(long threadId) {
130        Cursor cursor = null;
131
132        try {
133            cursor = SqliteWrapper.query(mContext, mContext.getContentResolver(),
134                            Inbox.CONTENT_URI, SERVICE_CENTER_PROJECTION,
135                            "thread_id = " + threadId, null, "date DESC");
136
137            if ((cursor == null) || !cursor.moveToFirst()) {
138                return null;
139            }
140
141            boolean replyPathPresent = (1 == cursor.getInt(COLUMN_REPLY_PATH_PRESENT));
142            return replyPathPresent ? cursor.getString(COLUMN_SERVICE_CENTER) : null;
143        } finally {
144            if (cursor != null) {
145                cursor.close();
146            }
147        }
148    }
149
150    private void log(String msg) {
151        Log.d(LogTag.TAG, "[SmsMsgSender] " + msg);
152    }
153}
154