Android彩信发送有下面几个类:
一个一个类看 :
1 . ComposeMessageActivity.java 详情页面
2 . WoringMessage.java 处理一些发送短信-或-彩信方法
3. MmsMessageSender.java 彩信入本地数据库
4. TransactionService.java 开启服务进行发送或下载操作实现功能
5. SendTransaction.java 主要功能他是一个线程,在线程里面访问他的父类Transaction里面的SendPdu()方法
6. Transaction.java 主要功能通过他的子类传递值,去调用HttpUtils里面的网络发送下载方法
7. HttpUtils.java 主要进行网络访问httpConnection.java
ComposeMessageActivity.java
主要作用是send()方法 ,建议先看 , 普通短信发送过程 <普通短信发送过程>
WoringMessage.java
send()方法里面主要看
new Thread(new Runnable() { } //这里面调用了
sendMmsWorker() 方法
public void send(final String recipientsInUI) {
long origThreadId = mConversation.getThreadId();
LogTag.debugD("send origThreadId: " + origThreadId);
removeSubjectIfEmpty(true /* notify */);
// Get ready to write to disk.
prepareForSave(true /* notify */);
// Make sure the mConversation has Recipients
checkConversationHasRecipients(recipientsInUI);
// We need the recipient list for both SMS and MMS.
final Conversation conv = mConversation;
String msgTxt = mText.toString();
if (requiresMms() || addressContainsEmailToMms(conv, msgTxt)) {
// uaProfUrl setting in mms_config.xml must be present to send an MMS.
// However, SMS service will still work in the absence of a uaProfUrl address.
if (MmsConfig.getUaProfUrl() == null) {
String err = "WorkingMessage.send MMS sending failure. mms_config.xml is " +
"missing uaProfUrl setting. uaProfUrl is required for MMS service, " +
"but can be absent for SMS.";
RuntimeException ex = new NullPointerException(err);
Log.e(TAG, err, ex);
// now, let's just crash.
throw ex;
}
// Make local copies of the bits we need for sending a message,
// because we will be doing it off of the main thread, which will
// immediately continue on to resetting some of this state.
final Uri mmsUri = mMessageUri;
final PduPersister persister = PduPersister.getPduPersister(mActivity);
final SlideshowModel slideshow = mSlideshow;
final CharSequence subject = mSubject;
final boolean textOnly = mAttachmentType == TEXT;
LogTag.debugD("Send mmsUri: " + mmsUri);
// Do the dirty work of sending the message off of the main UI thread.
new Thread(new Runnable() { //发送信息调用
@Override
public void run() {
final SendReq sendReq = makeSendReq(conv, subject);
// Make sure the text in slide 0 is no longer holding onto a reference to
// the text in the message text box.
slideshow.prepareForSend();
sendMmsWorker(conv, mmsUri, persister, slideshow, sendReq, textOnly);
updateSendStats(conv);
}
}, "WorkingMessage.send MMS").start();
} else {
// Same rules apply as above.
// Add user's signature first if this feature is enabled.
String text = mText.toString();
LogTag.debugD("mText="+text);
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mActivity);
if (sp.getBoolean("pref_key_enable_signature", false)) {
String signature = (sp.getString("pref_key_edit_signature", "")).trim();
if (signature.length() > 0) {
String sigBlock = "\n" + signature;
if (!text.endsWith(sigBlock)) {
// Signature should be written behind the text in a
// newline while the signature has changed.
text += sigBlock;
}
}
}
final String msgText = text;
new Thread(new Runnable() {
@Override
public void run() {
preSendSmsWorker(conv, msgText, recipientsInUI);
updateSendStats(conv);
}
}, "WorkingMessage.send SMS").start();
}
// update the Recipient cache with the new to address, if it's different
RecipientIdCache.updateNumbers(conv.getThreadId(), conv.getRecipients());
// Mark the message as discarded because it is "off the market" after being sent.
mDiscarded = true;
}
-------------------------sendMmsWorker方法
private void sendMmsWorker(Conversation conv, Uri mmsUri, PduPersister persister,
SlideshowModel slideshow, SendReq sendReq, boolean textOnly) {
long threadId = 0;
Cursor cursor = null;
boolean newMessage = false;
boolean forwardMessage = conv.getHasMmsForward();
boolean sameRecipient = false;
ContactList contactList = conv.getRecipients();
// int phoneCount = MessageUtils.getPhoneCount();
if (contactList != null) {
String[] numbers = contactList.getNumbers();
String[] forward = conv.getForwardRecipientNumber();
if (numbers != null && forward != null
&& (numbers.length == forward.length)) {
List<String> currentNumberList = Arrays.asList(numbers);
List<String> forwardNumberList = Arrays.asList(forward);
Collections.sort(currentNumberList);
Collections.sort(forwardNumberList);
if (currentNumberList.equals(forwardNumberList)) {
sameRecipient = true;
}
}
}
try {
// Put a placeholder message in the database first
DraftCache.getInstance().setSavingDraft(true);
mStatusListener.onPreMessageSent();
// Make sure we are still using the correct thread ID for our
// recipient set.
threadId = conv.ensureThreadId();
if (forwardMessage && sameRecipient) {
MessageUtils.sSameRecipientList.add(threadId);
}
if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
LogTag.debug("sendMmsWorker: update draft MMS message " + mmsUri +
" threadId: " + threadId);
}
// One last check to verify the address of the recipient.
String[] dests = conv.getRecipients().getNumbers(true /* scrub for MMS address */);
if (dests.length == 1) {
// verify the single address matches what's in the database. If we get a different
// address back, jam the new value back into the SendReq.
String newAddress =
Conversation.verifySingleRecipient(mActivity, conv.getThreadId(), dests[0]);
if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
LogTag.debug("sendMmsWorker: newAddress " + newAddress +
" dests[0]: " + dests[0]);
}
if (!newAddress.equals(dests[0])) {
dests[0] = newAddress;
EncodedStringValue[] encodedNumbers = EncodedStringValue.encodeStrings(dests);
if (encodedNumbers != null) {
if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
LogTag.debug("sendMmsWorker: REPLACING number!!!");
}
sendReq.setTo(encodedNumbers);
}
}
MessageUtils.markAsNotificationThreadIfNeed(mActivity, threadId, newAddress);
}
newMessage = mmsUri == null;
if (newMessage) {
// Write something in the database so the new message will appear as sending
ContentValues values = new ContentValues();
values.put(Mms.MESSAGE_BOX, Mms.MESSAGE_BOX_OUTBOX);
values.put(Mms.THREAD_ID, threadId);
values.put(Mms.MESSAGE_TYPE, PduHeaders.MESSAGE_TYPE_SEND_REQ);
if (textOnly) {
values.put(Mms.TEXT_ONLY, 1);
}
if (MessageUtils.isMsimIccCardActive()) {
values.put(Mms.SUBSCRIPTION_ID, mCurrentConvSubId);
Log.i(LogTag.ljsTest, "多卡··发送彩信 = " + mCurrentConvSubId);
} else {
values.put(Mms.SUBSCRIPTION_ID,
SubscriptionManager.getDefaultDataSubscriptionId());
Log.i(LogTag.ljsTest, "单卡··发送彩信 = " + mCurrentConvSubId);
}
mmsUri = SqliteWrapper.insert(mActivity, mContentResolver, Mms.Outbox.CONTENT_URI,
values);
}
mStatusListener.onMessageSent();
// If user tries to send the message, it's a signal the inputted text is
// what they wanted.
UserHappinessSignals.userAcceptedImeText(mActivity);
// First make sure we don't have too many outstanding unsent message.
cursor = SqliteWrapper.query(mActivity, mContentResolver,
Mms.Outbox.CONTENT_URI, MMS_OUTBOX_PROJECTION, null, null, null);
if (cursor != null) {
long maxMessageSize = MmsConfig.getMaxSizeScaleForPendingMmsAllowed() *
MmsConfig.getMaxMessageSize();
long totalPendingSize = 0;
while (cursor.moveToNext()) {
totalPendingSize += cursor.getLong(MMS_MESSAGE_SIZE_INDEX);
}
if (totalPendingSize >= maxMessageSize) {
unDiscard(); // it wasn't successfully sent. Allow it to be saved as a draft.
mStatusListener.onMaxPendingMessagesReached();
markMmsMessageWithError(mmsUri);
return;
}
}
} finally {
if (cursor != null) {
cursor.close();
}
}
try {
if (newMessage) {
// Create a new MMS message if one hasn't been made yet.
mmsUri = createDraftMmsMessage(persister, sendReq, slideshow, mmsUri,
mActivity, null);
} else {
// Otherwise, sync the MMS message in progress to disk.
updateDraftMmsMessage(mmsUri, persister, slideshow, sendReq, null);
}
// Be paranoid and clean any draft SMS up.
deleteDraftSmsMessage(threadId);
} finally {
DraftCache.getInstance().setSavingDraft(false);
}
// Resize all the resizeable attachments (e.g. pictures) to fit
// in the remaining space in the slideshow.
int error = 0;
try {
slideshow.finalResize(mmsUri);
} catch (ExceedMessageSizeException e1) {
error = MESSAGE_SIZE_EXCEEDED;
} catch (MmsException e1) {
error = UNKNOWN_ERROR;
}
if (error != 0) {
markMmsMessageWithError(mmsUri);
mStatusListener.onAttachmentError(error);
return;
}
ContentValues values = new ContentValues(1);
if (MessageUtils.isMsimIccCardActive()) {
values.put(Mms.SUBSCRIPTION_ID, mCurrentConvSubId);
Log.i(LogTag.ljsTest, "多卡··发送彩信完 存数据 = " + mCurrentConvSubId);
} else {
values.put(Mms.SUBSCRIPTION_ID, SubscriptionManager.getDefaultDataSubscriptionId());
Log.i(LogTag.ljsTest, "单卡··发送彩信完 存数据 = " + mCurrentConvSubId);
}
SqliteWrapper.update(mActivity, mContentResolver, mmsUri, values, null, null);
MessageSender sender = new MmsMessageSender(mActivity, mmsUri,
slideshow.getCurrentMessageSize(), mCurrentConvSubId);
try {
if (!sender.sendMessage(threadId)) {
// The message was sent through SMS protocol, we should
// delete the copy which was previously saved in MMS drafts.
SqliteWrapper.delete(mActivity, mContentResolver, mmsUri, null, null);
}
// Make sure this thread isn't over the limits in message count
Recycler.getMmsRecycler().deleteOldMessagesByThreadId(mActivity, threadId);
} catch (Exception e) {
Log.e(TAG, "Failed to send message: " + mmsUri + ", threadId=" + threadId, e);
}
if (forwardMessage && sameRecipient) {
MessageUtils.sSameRecipientList.remove(threadId);
}
MmsWidgetProvider.notifyDatasetChanged(mActivity);
MessageUtils.updateThreadAttachTypeByThreadId(mActivity, threadId);
}
---------------------------sendMmsWorker----------------------------
sendMmsWorker方法主要调用 MmsMessageSender里面的sendMessage方法进行数据库插入
在主要操作sender
MessageSender sender = new MmsMessageSender(mActivity, mmsUri,
slideshow.getCurrentMessageSize(), mCurrentConvSubId);
try {
if (!sender.sendMessage(threadId)) {
// The message was sent through SMS protocol, we should
// delete the copy which was previously saved in MMS drafts.
SqliteWrapper.delete(mActivity, mContentResolver, mmsUri, null, null);
}
// Make sure this thread isn't over the limits in message count
Recycler.getMmsRecycler().deleteOldMessagesByThreadId(mActivity, threadId);
} catch (Exception e) {
Log.e(TAG, "Failed to send message: " + mmsUri + ", threadId=" + threadId, e);
}
if (forwardMessage && sameRecipient) {
MessageUtils.sSameRecipientList.remove(threadId);
}
MmsMessageSender.java 主要也sendMessage()方法为主
public boolean sendMessage(long token) throws MmsException {
// Load the MMS from the message uri
if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
LogTag.debug("sendMessage uri: " + mMessageUri);
}
PduPersister p = PduPersister.getPduPersister(mContext);
GenericPdu pdu = p.load(mMessageUri);
if (pdu.getMessageType() != PduHeaders.MESSAGE_TYPE_SEND_REQ) {
throw new MmsException("Invalid message: " + pdu.getMessageType());
}
SendReq sendReq = (SendReq) pdu;
// Update headers.
updatePreferencesHeaders(sendReq);
// MessageClass.
sendReq.setMessageClass(DEFAULT_MESSAGE_CLASS.getBytes());
// Update the 'date' field of the message before sending it.
sendReq.setDate(System.currentTimeMillis() / 1000L);
sendReq.setMessageSize(mMessageSize);
p.updateHeaders(mMessageUri, sendReq);
long messageId = ContentUris.parseId(mMessageUri);
// Move the message into MMS Outbox.
if (!mMessageUri.toString().startsWith(Mms.Draft.CONTENT_URI.toString())) {
// If the message is already in the outbox (most likely because we created a "primed"
// message in the outbox when the user hit send), then we have to manually put an
// entry in the pending_msgs table which is where TransacationService looks for
// messages to send. Normally, the entry in pending_msgs is created by the trigger:
// insert_mms_pending_on_update, when a message is moved from drafts to the outbox.
ContentValues values = new ContentValues(7);
values.put(PendingMessages.PROTO_TYPE, MmsSms.MMS_PROTO);
values.put(PendingMessages.MSG_ID, messageId);
values.put(PendingMessages.MSG_TYPE, pdu.getMessageType());
values.put(PendingMessages.ERROR_TYPE, 0);
values.put(PendingMessages.ERROR_CODE, 0);
values.put(PendingMessages.RETRY_INDEX, 0);
values.put(PendingMessages.DUE_TIME, 0);
SqliteWrapper.insert(mContext, mContext.getContentResolver(),
PendingMessages.CONTENT_URI, values);
} else {
p.move(mMessageUri, Mms.Outbox.CONTENT_URI);
}
// Start MMS transaction service
SendingProgressTokenManager.put(messageId, token);
Intent intent = new Intent(mContext, TransactionService.class);
intent.putExtra(Mms.SUBSCRIPTION_ID, mSubId);
mContext.startService(intent);
return true;
}
----SqliteWrapper.insert()插入数据库
SqliteWrapper.insert(mContext, mContext.getContentResolver(),
PendingMessages.CONTENT_URI, values);
插入成功后开启服务 TransactionService
Intent intent = new Intent(mContext, TransactionService.class);
intent.putExtra(Mms.SUBSCRIPTION_ID, mSubId);
mContext.startService(intent);
TransactionService .java
这个类主要是进行图片上传和下载
主要看Handerl里面
/**
* Handle incoming transaction requests.
* The incoming requests are initiated by the MMSC Server or by the
* MMS Client itself.
*/
@Override
public void handleMessage(Message msg) {
LogTag.debugD("Handling incoming message: " + msg + " = " + decodeMessage(msg));
Transaction transaction = null;
switch (msg.what) {
case EVENT_NEW_INTENT:
onNewIntent((Intent)msg.obj, msg.arg1);
break;
case EVENT_QUIT:
getLooper().quit();
return;
case EVENT_TRANSACTION_REQUEST: //通知彩信接收 liwangjiang
int serviceId = msg.arg1;
try {
TransactionBundle args = (TransactionBundle) msg.obj;
TransactionSettings transactionSettings;
LogTag.debugD("EVENT_TRANSACTION_REQUEST MmscUrl=" +
args.getMmscUrl() + " proxy port: " + args.getProxyAddress());
// Set the connection settings for this transaction.
// If these have not been set in args, load the default settings.
String mmsc = args.getMmscUrl();
if (mmsc != null) {
transactionSettings = new TransactionSettings(
mmsc, args.getProxyAddress(), args.getProxyPort());
} else {
transactionSettings = new TransactionSettings(
TransactionService.this, null,
args.getSubId());
}
int transactionType = args.getTransactionType();
LogTag.debugD("handle EVENT_TRANSACTION_REQUEST: transactionType=" +
transactionType + " " + decodeTransactionType(transactionType));
// Create appropriate transaction
switch (transactionType) {
case Transaction.NOTIFICATION_TRANSACTION:
String uri = args.getUri();
//用户通知 liwangjiang
if (uri!=null){
long threadId = MessagingNotification.getThreadId(
getApplicationContext(), Uri.parse(uri));
MessagingNotification.blockingUpdateNewMessageIndicator(getApplicationContext(),
threadId,
false);
MessagingNotification.updateDownloadFailedNotification(getApplicationContext());
MessageUtils.updateThreadAttachTypeByThreadId(getApplicationContext(), threadId);
}
if (uri != null) {
//开始解压消息 自动解压彩信
transaction = new NotificationTransaction(
TransactionService.this, serviceId,
transactionSettings, uri
);
} else {
// Now it's only used for test purpose.
byte[] pushData = args.getPushData();
PduParser parser = new PduParser(pushData,
PduParserUtil.shouldParseContentDisposition());
GenericPdu ind = parser.parse();
int type = PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND;
if ((ind != null) && (ind.getMessageType() == type)) {
transaction = new NotificationTransaction(
TransactionService.this, serviceId,
transactionSettings, (NotificationInd) ind);
} else {
Log.e(TAG, "Invalid PUSH data.");
transaction = null;
return;
}
}
break;
case Transaction.RETRIEVE_TRANSACTION:
//手动下载短信
transaction = new RetrieveTransaction(
TransactionService.this, serviceId,
transactionSettings, args.getUri());
break;
case Transaction.SEND_TRANSACTION:
transaction = new SendTransaction(
TransactionService.this, serviceId,
transactionSettings, args.getUri());
break;
case Transaction.READREC_TRANSACTION:
transaction = new ReadRecTransaction(
TransactionService.this, serviceId,
transactionSettings, args.getUri());
break;
default:
Log.w(TAG, "Invalid transaction type: " + serviceId);
transaction = null;
return;
}
//copy the subId from TransactionBundle to transaction obj.
transaction.setSubId(args.getSubId());
if (!processTransaction(transaction)) {
transaction = null;
return;
}
LogTag.debugD("Started processing of incoming message: " + msg);
} catch (Exception ex) {
Log.w(TAG, "Exception occurred while handling message: " + msg, ex);
if (transaction != null) {
try {
transaction.detach(TransactionService.this);
if (mProcessing.contains(transaction)) {
synchronized (mProcessing) {
mProcessing.remove(transaction);
}
}
} catch (Throwable t) {
Log.e(TAG, "Unexpected Throwable.", t);
} finally {
// Set transaction to null to allow stopping the
// transaction service.
transaction = null;
}
}
} finally {
if (transaction == null) {
LogTag.debugD("Transaction was null. Stopping self: " + serviceId);
endMmsConnectivity();
stopSelfIfIdle(serviceId);
}
}
return;
case EVENT_HANDLE_NEXT_PENDING_TRANSACTION:
processPendingTransaction(transaction, (TransactionSettings) msg.obj);
return;
case EVENT_MMS_CONNECTIVITY_TIMEOUT:
removeMessages(EVENT_MMS_CONNECTIVITY_TIMEOUT);
mMmsConnecvivityRetryCount++;
if (mMmsConnecvivityRetryCount > MMS_CONNECTIVITY_RETRY_TIMES) {
Log.d(TAG, "MMS_CONNECTIVITY_TIMEOUT");
mMmsConnecvivityRetryCount = 0;
return;
}
if (!mPending.isEmpty()) {
try {
beginMmsConnectivity(SubscriptionManager.getDefaultDataSubscriptionId());
} catch (IOException e) {
Log.w(TAG, "Attempt to use of MMS connectivity failed");
return;
}
}
return;
case EVENT_MMS_PDP_ACTIVATION_TIMEOUT:
onPDPTimeout((int)msg.obj);
return;
default:
Log.w(TAG, "what=" + msg.what);
return;
}
}
handler msg.what 会传入一个 5 就是 EVENT_NEW_INTENT 调用了 onNewIntent()方法
public void onNewIntent(Intent intent, int serviceId) {
if (!MmsConfig.isSmsEnabled(getApplicationContext())) {
LogTag.debugD("TransactionService: is not the default sms app");
stopSelf(serviceId);
return;
}
mConnMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
if (mConnMgr == null || !MmsConfig.isSmsEnabled(getApplicationContext())) {
endMmsConnectivity();
stopSelfIfIdle(serviceId);
return;
}
boolean noNetwork = false;
LogTag.debugD("onNewIntent: serviceId: " + serviceId + ": " + intent.getExtras() +
" intent=" + intent);
Bundle extras = intent.getExtras();
String action = intent.getAction();
DownloadManager downloadManager = DownloadManager.getInstance();
if ((ACTION_ONALARM.equals(action) || ACTION_ENABLE_AUTO_RETRIEVE.equals(action) ||
(extras == null)) || ((extras != null) && !extras.containsKey("uri")
&& !extras.containsKey(CANCEL_URI))) {
//We hit here when either the Retrymanager triggered us or there is
//send operation in which case uri is not set. For rest of the
//cases(MT MMS) we hit "else" case.
// Scan database to find all pending operations.
Cursor cursor = PduPersister.getPduPersister(this).getPendingMessages(
System.currentTimeMillis());
LogTag.debugD("Cursor= " + DatabaseUtils.dumpCursorToString(cursor));
if (cursor != null) {
try {
int count = cursor.getCount();
LogTag.debugD("onNewIntent: cursor.count=" + count + " action=" + action);
//判断是否有未发送的如果没有就 停止服务
if (count == 0) {
LogTag.debugD("onNewIntent: no pending messages. Stopping service.");
RetryScheduler.setRetryAlarm(this);
stopSelfIfIdle(serviceId);
return;uricolumnIndexOfMsgId = cursor.getColumnIndexOrThrow(PendingMessages.MSG_ID);
int columnIndexOfMsgType = cursor.getColumnIndexOrThrow(
PendingMessages.MSG_TYPE);
int columnIndexOfRetryIndex = cursor.getColumnIndexOrThrow(
PendingMessages.RETRY_INDEX);
int inActiveSubCount = 0;
while (cursor.moveToNext()) {
int msgType = cursor.getInt(columnIndexOfMsgType);
int transactionType = getTransactionType(msgType);
if (transactionType==Transaction.RETRIEVE_TRANSACTION){
//如果是下载就跳出循环 transactionType=1就表示自动去再次请求下载 liwangjiang
continue;
}
LogTag.debugD("onNewIntent: msgType=" + msgType + " transactionType=" +
transactionType);
Uri uri = ContentUris.withAppendedId(
Mms.CONTENT_URI,
cursor.getLong(columnIndexOfMsgId));
boolean inRetry = cursor.getInt(columnIndexOfRetryIndex) > 0;
if (noNetwork) {
// Because there is a MMS queue list including
// unsent and undownload MMS in database while data
// network unenabled. Anyway we should give user the
// information about the last MMS in the queue list.
// While there is no data network, we will give
// a prompt to user about the last MMS failed in
// database, so we need to fetch the information of
// last pending MMS in the queue list, just make the
// cursor move to the end of the queue list, and
// give the corresponding prompt to user.
cursor.moveToLast();
//
transactionType = getTransactionType(cursor
.getInt(columnIndexOfMsgType));
onNetworkUnavailable(serviceId, transactionType, uri, inRetry);
return;
}
switch (transactionType) {
case -1:
break;
case Transaction.RETRIEVE_TRANSACTION:
// If it's a transiently failed transaction,
// we should retry it in spite of current
// downloading mode. If the user just turned on the auto-retrieve
// option, we also retry those messages that don't have any errors.
int failureType = cursor.getInt(
cursor.getColumnIndexOrThrow(
PendingMessages.ERROR_TYPE));
boolean autoDownload = downloadManager.isAuto();
LogTag.debugD("onNewIntent: failureType=" + failureType +
" action=" + action + " isTransientFailure:" +
isTransientFailure(failureType) + " autoDownload=" +
autoDownload);
if (!autoDownload && !inRetry) {
// If autodownload is turned off and not in retry peroid,
// don't process the transaction.
LogTag.debugD("onNewIntent: skipping - autodownload off");
break;
}
// If retry always is enabled, need mark state to downloading.
if (getResources().getBoolean(R.bool.config_retry_always)) {
downloadManager.markState(
uri, DownloadManager.STATE_DOWNLOADING);
}
// Logic is twisty. If there's no failure or the failure
// is a non-permanent failure, we want to process the transaction.
// Otherwise, break out and skip processing this transaction.
if (!(failureType == MmsSms.NO_ERROR ||
isTransientFailure(failureType))) {
LogTag.debugD("onNewIntent: skipping - permanent error");
break;
}
LogTag.debugD( "onNewIntent: falling through and processing");
// fall-through
default:
int subId = getSubIdFromDb(uri);
Log.d(TAG, "destination Sub Id = " + subId);
if (subId < 0) {
Log.d(TAG, "Subscriptions are not yet ready.");
int defSmsSubId = getDefaultSmsSubscriptionId();
// We dont have enough info about subId. We dont know if the
// subId as persent in DB actually would match the subId of
// defaultSmsSubId. We can not also ignore this transaction
// since no retry would be scheduled if we return from here. The
// only option is to do best effort try on current default sms
// subId, if it failed then a retry would be scheduled and while
// processing that retry attempt we would be able to get correct
// subId from subscription manager.
Log.d(TAG, "Override with default Sms subId = " + defSmsSubId);
subId = defSmsSubId;
}
if ((!isMmsAllowed())
&& !getResources().getBoolean(R.bool.config_retry_always)) {
Log.d(TAG, "mobileData off or no mms apn or APM, Abort");
if (transactionType == Transaction.RETRIEVE_TRANSACTION) {
downloadManager.markState(uri,
DownloadManager.STATE_TRANSIENT_FAILURE);
}
onNetworkUnavailable(serviceId, transactionType, uri, inRetry);
break;
}
if (!SubscriptionManager.from(getApplicationContext())
.isActiveSubId(subId)) {
LogTag.debugD("SubId is not active:" + subId);
inActiveSubCount ++;
if (inActiveSubCount == count) {
LogTag.debugD("No active SubId found, stop self: " + count);
stopSelfIfIdle(serviceId);
}
break;
}
TransactionBundle args = new TransactionBundle(transactionType,
uri.toString(), subId);
// FIXME: We use the same startId for all MMs.
LogTag.debugD("onNewIntent: launchTransaction uri=" + uri);
// FIXME: We use the same serviceId for all MMs.
launchTransaction(serviceId, args, false);
break;
}
}
} finally {
cursor.close();
}
} else {
LogTag.debugD("onNewIntent: no pending messages. Stopping service.");
RetryScheduler.setRetryAlarm(this);
stopSelfIfIdle(serviceId);
}
} else if ((extras != null) && extras.containsKey(CANCEL_URI)) {
String uriStr = intent.getStringExtra(CANCEL_URI);
Uri mCancelUri = Uri.parse(uriStr);
for (Transaction transaction : mProcessing) {
transaction.cancelTransaction(mCancelUri);
}
for (Transaction transaction : mPending) {
transaction.cancelTransaction(mCancelUri);
}
} else {
LogTag.debugD("onNewIntent: launch transaction...");
String uriStr = intent.getStringExtra("uri");
Uri uri = Uri.parse(uriStr);
int subId = getSubIdFromDb(uri);
Log.d(TAG, "destination Sub Id = " + subId);
if (subId < 0) {
int defSmsSubId = getDefaultSmsSubscriptionId();
Log.d(TAG, "Override with default Sms subId = " + defSmsSubId);
subId = defSmsSubId;
}
if ((!isMmsAllowed()) && !getResources().getBoolean(R.bool.config_retry_always)) {
Log.d(TAG, "Either mobile data is off or apn not present, Abort");
downloadManager.markState(uri, DownloadManager.STATE_TRANSIENT_FAILURE);
boolean isRetry = getRetryIndex(uri.getLastPathSegment()) > 0;
int type = intent.getIntExtra(TransactionBundle.TRANSACTION_TYPE,
Transaction.NOTIFICATION_TRANSACTION);
onNetworkUnavailable(serviceId, type, uri, isRetry);
return;
}
if (!SubscriptionManager.from(getApplicationContext()).isActiveSubId(subId)) {
LogTag.debugD("SubId is not active:" + subId);
stopSelfIfIdle(serviceId);
return;
}
Bundle bundle = intent.getExtras();
bundle.putInt(ConstantsWrapper.Phone.SUBSCRIPTION_KEY, subId);
// For launching NotificationTransaction and test purpose.
TransactionBundle args = new TransactionBundle(bundle);
launchTransaction(serviceId, args, noNetwork);
}
}
onNewIntent主要查询数据库对彩信进行一些操作,在底层,还没有研究
onNewIntent发送一个信息到Handelr里面进行操作
private void launchTransaction(int serviceId, TransactionBundle txnBundle, boolean noNetwork) {
if (noNetwork) {
Log.w(TAG, "launchTransaction: no network error!");
onNetworkUnavailable(serviceId, txnBundle.getTransactionType(),
Uri.parse(txnBundle.getUri()), false);
return;
}
//设置手动现在数据
Message msg = mServiceHandler.obtainMessage(EVENT_TRANSACTION_REQUEST);//接收开始发送给NotificationTransation去接收短信
// Message msg = mServiceHandler.obtainMessage(Transaction.RETRIEVE_TRANSACTION);//接收开始发送给NotificationTransation去接收短信
msg.arg1 = serviceId;
msg.obj = txnBundle;
LogTag.debugD("launchTransaction: sending message " + msg);
mServiceHandler.sendMessage(msg);
}
在Handler里面启动 SendTransaction.java线程
SendTransaction.java主要操作进行调用父类的Transaction ,我就全部复制了这个类很简单
/*
* Copyright (C) 2007-2008 Esmertec AG.
* Copyright (C) 2007-2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.mms.transaction;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.database.sqlite.SqliteWrapper;
import android.net.Uri;
import android.provider.Telephony.Mms;
import android.provider.Telephony.Mms.Sent;
import android.text.TextUtils;
import android.telephony.SubscriptionManager;
import android.util.Log;
import com.android.mms.LogTag;
import com.android.mms.MmsApp;
import com.android.mms.ui.MessageUtils;
import com.android.mms.util.RateController;
import com.android.mms.util.SendingProgressTokenManager;
import com.google.android.mms.pdu.EncodedStringValue;
import com.google.android.mms.pdu.PduComposer;
import com.google.android.mms.pdu.PduHeaders;
import com.google.android.mms.pdu.PduParser;
import com.google.android.mms.pdu.PduPersister;
import com.google.android.mms.pdu.SendConf;
import com.google.android.mms.pdu.SendReq;
import java.util.Arrays;
/**
* The SendTransaction is responsible for sending multimedia messages
* (M-Send.req) to the MMSC server. It:
*
* <ul>
* <li>Loads the multimedia message from storage (Outbox).
* <li>Packs M-Send.req and sends it.
* <li>Retrieves confirmation data from the server (M-Send.conf).
* <li>Parses confirmation message and handles it.
* <li>Moves sent multimedia message from Outbox to Sent.
* <li>Notifies the TransactionService about successful completion.
* </ul>
*/
public class SendTransaction extends Transaction implements Runnable {
private static final String TAG = LogTag.TAG;
private Thread mThread;
public final Uri mSendReqURI;
public SendTransaction(Context context,
int transId, TransactionSettings connectionSettings, String uri) {
super(context, transId, connectionSettings);
mSendReqURI = Uri.parse(uri);
mId = uri;
// Attach the transaction to the instance of RetryScheduler.
attach(RetryScheduler.getInstance(context));
}
/*
* (non-Javadoc)
* @see com.android.mms.Transaction#process()
*/
@Override
public void process() {
mThread = new Thread(this, "SendTransaction");
mThread.start();
}
public void run() {
try {
RateController rateCtlr = RateController.getInstance();
if (rateCtlr.isLimitSurpassed() && !rateCtlr.isAllowedByUser()) {
Log.e(TAG, "Sending rate limit surpassed.");
return;
}
// Load M-Send.req from outbox
PduPersister persister = PduPersister.getPduPersister(mContext);
SendReq sendReq = (SendReq) persister.load(mSendReqURI);
// Update the 'date' field of the PDU right before sending it.
long date = System.currentTimeMillis() / 1000L;
sendReq.setDate(date);
// Persist the new date value into database.
ContentValues values = new ContentValues(1);
values.put(Mms.DATE, date);
SqliteWrapper.update(mContext, mContext.getContentResolver(),
mSendReqURI, values, null, null);
// fix bug 2100169: insert the 'from' address per spec
String lineNumber = MessageUtils.getLocalNumber(mSubId);
Log.d(TAG, "lineNumber " + lineNumber);
if (!TextUtils.isEmpty(lineNumber)) {
sendReq.setFrom(new EncodedStringValue(lineNumber));
}
// Pack M-Send.req, send it, retrieve confirmation data, and parse it
long tokenKey = ContentUris.parseId(mSendReqURI);
//sendReq 流在这个方法里面 liwangjiang
PduComposer pdu = new PduComposer(mContext, sendReq);
Log.v("jiangwanglisend","发送中。。。。。。。。");
byte[] response = sendPdu(SendingProgressTokenManager.get(tokenKey), pdu.make(),mSendReqURI);
Log.v("jiangwanglisend","已发送。。。。。。。。");
SendingProgressTokenManager.remove(tokenKey);
String respStr = new String(response);
LogTag.debugD("[SendTransaction] run: send mms msg (" + mId + "), resp=" + respStr);
SendConf conf = (SendConf) new PduParser(response,
PduParserUtil.shouldParseContentDisposition()).parse();
if (conf == null) {
Log.e(TAG, "No M-Send.conf received.");
}
// Check whether the responding Transaction-ID is consistent
// with the sent one.
byte[] reqId = sendReq.getTransactionId();
byte[] confId = conf.getTransactionId();
if (!Arrays.equals(reqId, confId)) {
Log.e(TAG, "Inconsistent Transaction-ID: req="
+ new String(reqId) + ", conf=" + new String(confId));
return;
}
// From now on, we won't save the whole M-Send.conf into
// our database. Instead, we just save some interesting fields
// into the related M-Send.req.
values = new ContentValues(2);
int respStatus = conf.getResponseStatus();
values.put(Mms.RESPONSE_STATUS, respStatus);
if (respStatus != PduHeaders.RESPONSE_STATUS_OK) {
SqliteWrapper.update(mContext, mContext.getContentResolver(),
mSendReqURI, values, null, null);
Log.e(TAG, "Server returned an error code: " + respStatus);
return;
}
String messageId = PduPersister.toIsoString(conf.getMessageId());
values.put(Mms.MESSAGE_ID, messageId);
SqliteWrapper.update(mContext, mContext.getContentResolver(),
mSendReqURI, values, null, null);
// Move M-Send.req from Outbox into Sent.
Uri uri = persister.move(mSendReqURI, Sent.CONTENT_URI);
mTransactionState.setState(TransactionState.SUCCESS);
mTransactionState.setContentUri(uri);
} catch (Throwable t) {
Log.e(TAG, Log.getStackTraceString(t));
} finally {
LogTag.debugD("[SendTransaction]remove cache:" + mSendReqURI);
MmsApp.getApplication().getPduLoaderManager().removePdu(mSendReqURI);
if (mTransactionState.getState() != TransactionState.SUCCESS) {
mTransactionState.setState(TransactionState.FAILED);
mTransactionState.setContentUri(mSendReqURI);
Log.e(TAG, "Delivery failed.");
}
notifyObservers();
}
}
@Override
public void abort() {
Log.d(TAG, "markFailed = " + this);
mTransactionState.setState(TransactionState.FAILED);
mTransactionState.setContentUri(mSendReqURI);
mFailReason = FAIL_REASON_CAN_NOT_SETUP_DATA_CALL;
notifyObservers();
}
@Override
public int getType() {
return SEND_TRANSACTION;
}
}