172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project/* 272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * Copyright (C) 2007-2008 Esmertec AG. 372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * Copyright (C) 2007-2008 The Android Open Source Project 472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * 572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * you may not use this file except in compliance with the License. 772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * You may obtain a copy of the License at 872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * 972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 1072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * 1172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software 1272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 1372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * See the License for the specific language governing permissions and 1572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * limitations under the License. 1672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project */ 1772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project 1872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectpackage com.android.mms.transaction; 1972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project 2072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.content.ContentUris; 2172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.content.ContentValues; 2272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.content.Context; 23d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport android.database.sqlite.SqliteWrapper; 2472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.net.Uri; 25f7e8281a223af6228e6399055a6197a1edd9bc3aTom Taylorimport android.provider.Telephony.Mms; 26f7e8281a223af6228e6399055a6197a1edd9bc3aTom Taylorimport android.provider.Telephony.Mms.Sent; 279653d43dfe3713df14ef3567b124c5729543c5f2Tom Taylorimport android.text.TextUtils; 2872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectimport android.util.Log; 2972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project 30d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.android.mms.LogTag; 31d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.android.mms.ui.MessageUtils; 32d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.android.mms.util.RateController; 33d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.android.mms.util.SendingProgressTokenManager; 34d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.google.android.mms.pdu.EncodedStringValue; 35d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.google.android.mms.pdu.PduComposer; 36d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.google.android.mms.pdu.PduHeaders; 37d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.google.android.mms.pdu.PduParser; 38d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.google.android.mms.pdu.PduPersister; 39d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.google.android.mms.pdu.SendConf; 40d64419030e1fec1e751695dab3bd7236e2fb0214Roger Chenimport com.google.android.mms.pdu.SendReq; 4172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project 42178eb8396bd0cc972542798b79218cdf32af4b35Ye Wenimport java.util.Arrays; 43178eb8396bd0cc972542798b79218cdf32af4b35Ye Wen 4472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project/** 4572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * The SendTransaction is responsible for sending multimedia messages 4672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * (M-Send.req) to the MMSC server. It: 4772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * 4872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * <ul> 4972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * <li>Loads the multimedia message from storage (Outbox). 5072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * <li>Packs M-Send.req and sends it. 5172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * <li>Retrieves confirmation data from the server (M-Send.conf). 5272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * <li>Parses confirmation message and handles it. 5372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * <li>Moves sent multimedia message from Outbox to Sent. 5472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * <li>Notifies the TransactionService about successful completion. 5572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * </ul> 5672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project */ 5772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Projectpublic class SendTransaction extends Transaction implements Runnable { 58ab845dee6565a8dfc384186bc8f2e801a2b087e1Ye Wen private static final String TAG = LogTag.TAG; 5972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project 6072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project private Thread mThread; 61c65a9fdb8e1c936a2b8ce9312c125d4046fbae46Tom Taylor public final Uri mSendReqURI; 6272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project 6372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project public SendTransaction(Context context, 64a277f438d33872b9a0f1611fb8a86a918765f04bTom Taylor int transId, TransactionSettings connectionSettings, String uri) { 65a277f438d33872b9a0f1611fb8a86a918765f04bTom Taylor super(context, transId, connectionSettings); 6672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project mSendReqURI = Uri.parse(uri); 6772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project mId = uri; 6872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project 6972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project // Attach the transaction to the instance of RetryScheduler. 7072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project attach(RetryScheduler.getInstance(context)); 7172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project } 7272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project 7372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project /* 7472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * (non-Javadoc) 7572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project * @see com.android.mms.Transaction#process() 7672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project */ 7772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project @Override 7872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project public void process() { 79ddd31c4011b4191035bdfbba05a8edb1785f71afTodor Kalaydjiev mThread = new Thread(this, "SendTransaction"); 8072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project mThread.start(); 8172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project } 8272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project 8372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project public void run() { 8472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project try { 8572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project RateController rateCtlr = RateController.getInstance(); 8672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project if (rateCtlr.isLimitSurpassed() && !rateCtlr.isAllowedByUser()) { 8772b7fda4ff5e94ba1a13c41601ac1cd61c0d6663The Android Open Source Project Log.e(TAG, "Sending rate limit surpassed."); 8872b7fda4ff5e94ba1a13c41601ac1cd61c0d6663The Android Open Source Project return; 8972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project } 9072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project 9172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project // Load M-Send.req from outbox 9272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project PduPersister persister = PduPersister.getPduPersister(mContext); 9372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project SendReq sendReq = (SendReq) persister.load(mSendReqURI); 9472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project 9572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project // Update the 'date' field of the PDU right before sending it. 9672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project long date = System.currentTimeMillis() / 1000L; 9772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project sendReq.setDate(date); 9872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project 9972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project // Persist the new date value into database. 10072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project ContentValues values = new ContentValues(1); 10172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project values.put(Mms.DATE, date); 10272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project SqliteWrapper.update(mContext, mContext.getContentResolver(), 10372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project mSendReqURI, values, null, null); 10472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project 10513dbe96fc54f9b7190fd415d737f9a56dc409d10Wei Huang // fix bug 2100169: insert the 'from' address per spec 106a277f438d33872b9a0f1611fb8a86a918765f04bTom Taylor String lineNumber = MessageUtils.getLocalNumber(); 1079653d43dfe3713df14ef3567b124c5729543c5f2Tom Taylor if (!TextUtils.isEmpty(lineNumber)) { 1089653d43dfe3713df14ef3567b124c5729543c5f2Tom Taylor sendReq.setFrom(new EncodedStringValue(lineNumber)); 1099653d43dfe3713df14ef3567b124c5729543c5f2Tom Taylor } 11013dbe96fc54f9b7190fd415d737f9a56dc409d10Wei Huang 11172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project // Pack M-Send.req, send it, retrieve confirmation data, and parse it 11272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project long tokenKey = ContentUris.parseId(mSendReqURI); 11372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project byte[] response = sendPdu(SendingProgressTokenManager.get(tokenKey), 11472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project new PduComposer(mContext, sendReq).make()); 11572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project SendingProgressTokenManager.remove(tokenKey); 11672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project 1170d798c0853ead129b245ac7e8700f3a4aba92ecbWei Huang if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) { 1180d798c0853ead129b245ac7e8700f3a4aba92ecbWei Huang String respStr = new String(response); 1190d798c0853ead129b245ac7e8700f3a4aba92ecbWei Huang Log.d(TAG, "[SendTransaction] run: send mms msg (" + mId + "), resp=" + respStr); 1200d798c0853ead129b245ac7e8700f3a4aba92ecbWei Huang } 1210d798c0853ead129b245ac7e8700f3a4aba92ecbWei Huang 122178eb8396bd0cc972542798b79218cdf32af4b35Ye Wen SendConf conf = (SendConf) new PduParser( 123178eb8396bd0cc972542798b79218cdf32af4b35Ye Wen response, PduParserUtil.shouldParseContentDisposition()).parse(); 12472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project if (conf == null) { 12572b7fda4ff5e94ba1a13c41601ac1cd61c0d6663The Android Open Source Project Log.e(TAG, "No M-Send.conf received."); 12672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project } 12772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project 12872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project // Check whether the responding Transaction-ID is consistent 12972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project // with the sent one. 13072b7fda4ff5e94ba1a13c41601ac1cd61c0d6663The Android Open Source Project byte[] reqId = sendReq.getTransactionId(); 13172b7fda4ff5e94ba1a13c41601ac1cd61c0d6663The Android Open Source Project byte[] confId = conf.getTransactionId(); 13272b7fda4ff5e94ba1a13c41601ac1cd61c0d6663The Android Open Source Project if (!Arrays.equals(reqId, confId)) { 13372b7fda4ff5e94ba1a13c41601ac1cd61c0d6663The Android Open Source Project Log.e(TAG, "Inconsistent Transaction-ID: req=" 13472b7fda4ff5e94ba1a13c41601ac1cd61c0d6663The Android Open Source Project + new String(reqId) + ", conf=" + new String(confId)); 13572b7fda4ff5e94ba1a13c41601ac1cd61c0d6663The Android Open Source Project return; 13672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project } 13772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project 13872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project // From now on, we won't save the whole M-Send.conf into 13972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project // our database. Instead, we just save some interesting fields 14072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project // into the related M-Send.req. 14172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project values = new ContentValues(2); 14272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project int respStatus = conf.getResponseStatus(); 14372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project values.put(Mms.RESPONSE_STATUS, respStatus); 14472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project 14572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project if (respStatus != PduHeaders.RESPONSE_STATUS_OK) { 14672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project SqliteWrapper.update(mContext, mContext.getContentResolver(), 14772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project mSendReqURI, values, null, null); 14872b7fda4ff5e94ba1a13c41601ac1cd61c0d6663The Android Open Source Project Log.e(TAG, "Server returned an error code: " + respStatus); 14972b7fda4ff5e94ba1a13c41601ac1cd61c0d6663The Android Open Source Project return; 15072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project } 15172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project 15272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project String messageId = PduPersister.toIsoString(conf.getMessageId()); 15372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project values.put(Mms.MESSAGE_ID, messageId); 15472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project SqliteWrapper.update(mContext, mContext.getContentResolver(), 15572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project mSendReqURI, values, null, null); 15672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project 15772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project // Move M-Send.req from Outbox into Sent. 15872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project Uri uri = persister.move(mSendReqURI, Sent.CONTENT_URI); 15972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project 16072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project mTransactionState.setState(TransactionState.SUCCESS); 16172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project mTransactionState.setContentUri(uri); 16272b7fda4ff5e94ba1a13c41601ac1cd61c0d6663The Android Open Source Project } catch (Throwable t) { 16372b7fda4ff5e94ba1a13c41601ac1cd61c0d6663The Android Open Source Project Log.e(TAG, Log.getStackTraceString(t)); 16472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project } finally { 16572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project if (mTransactionState.getState() != TransactionState.SUCCESS) { 16672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project mTransactionState.setState(TransactionState.FAILED); 16772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project mTransactionState.setContentUri(mSendReqURI); 16872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project Log.e(TAG, "Delivery failed."); 16972735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project } 17072735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project notifyObservers(); 17172735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project } 17272735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project } 17372735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project 17472735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project @Override 17572735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project public int getType() { 17672735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project return SEND_TRANSACTION; 17772735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project } 17872735c62aba8fd2a9420a0f9f83d22543e3c164fThe Android Open Source Project} 179