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