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 18 package com.android.mms.transaction; 19 20 import android.content.Context; 21 import android.content.Intent; 22 import android.content.SharedPreferences; 23 import android.database.Cursor; 24 import android.database.sqlite.SQLiteException; 25 import android.database.sqlite.SqliteWrapper; 26 import android.net.Uri; 27 import android.preference.PreferenceManager; 28 import android.provider.Telephony.Sms; 29 import android.provider.Telephony.Sms.Inbox; 30 import android.util.Log; 31 32 import com.android.mms.LogTag; 33 import com.android.mms.ui.MessagingPreferenceActivity; 34 import com.google.android.mms.MmsException; 35 36 public 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 = "SmsMessageSender"; 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