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