MMS发送流程

1. 点击发送按钮Src/com/android/mms/ui/ComposeMessageActivity.java

public void onClick(View v) {

if ((v == mSendButton) && isPreparedForSending()) {

confirmSendMessageIfNeeded(); //确认是否需要发送短信—-》

}
}

2.src/com/android/mms/ui/ComposeMessageActivity.java

private void confirmSendMessageIfNeeded() {

if (!isRecipientsEditorVisible()) { //编辑联系人不可见时,也就是给已存在会话的联系人发送短信时

sendMessage(true);

return;

}

boolean isMms = mWorkingMessage.requiresMms(); //是否需要以彩信形式发送

if (mRecipientsEditor.hasInvalidRecipient(isMms)) {//是否含有不合法的收件人

if (mRecipientsEditor.hasValidRecipient(isMms)) {//有合法的和不合法的,弹出尝试发送对话框

String title = getResourcesString(R.string.has_invalid_recipient,

mRecipientsEditor.formatInvalidNumbers(isMms));

new AlertDialog.Builder(this)

.setIcon(android.R.drawable.ic_dialog_alert)

.setTitle(title)

.setMessage(R.string.invalid_recipient_message)

.setPositiveButton(R.string.try_to_send,

newSendIgnoreInvalidRecipientListener())

.setNegativeButton(R.string.no, new CancelSendingListener())

.show();

} else {//如果全是不合法的联系人,提示不能发送信息

new AlertDialog.Builder(this)

.setIcon(android.R.drawable.ic_dialog_alert)

.setTitle(R.string.cannot_send_message)

.setMessage(R.string.cannot_send_message_reason)

.setPositiveButton(R.string.yes, new CancelSendingListener())

.show();

}

} else {//判断收件人没有问题,接着发送信息 --》

sendMessage(true);

}
}

3. src/com/android/mms/ui/ComposeMessageActivity.java

private void sendMessage(boolean bCheckEcmMode) {

Log.v(TAG, "sendMessage");

if (bCheckEcmMode) {

// TODO: expose this in telephony layer for SDK build

String inEcm = SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE); //判断电话是否处于紧急拨号模式,得到的inEcm一般为空

Log.v(TAG, "inEcm = " + inEcm);

if (Boolean.parseBoolean(inEcm)) {

try {

startActivityForResult(

new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS,null),

REQUEST_CODE_ECM_EXIT_DIALOG);

return;

} catch (ActivityNotFoundException e) {

// continue to send message

Log.e(TAG, "Cannot find EmergencyCallbackModeExitDialog", e);

}

}

}

if (!mSendingMessage) {

// send can change the recipients. Make sure we remove the listeners firstand then add

// them back once the recipient list has settled.

removeRecipientsListeners(); //取消对收件人的监听

mWorkingMessage.send(); //发送信息—-》

mSentMessage = true;

mSendingMessage = true;

addRecipientsListeners(); //重新添加收件人监听

}

// But bail out if we are supposed to exit after the message is sent.

if (mExitOnSent) {//如果mExitOnSent为true,信息发送完成后退出Activity

finish();

}
}

4. src/com/android/mms/data/WorkingMessage.java

/**

* Send this message over the network. Will call back with onMessageSent() once

* it has been dispatched to the telephonystack. This WorkingMessage object is

* no longer useful after this method hasbeen called.

*/

public void send() {

if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {

LogTag.debug("send");

}

// Get ready to write to disk.

prepareForSave(true /* notify */);//主要做一下同步收件人和WorkingMessage,彩信时在准备其他一些东西

// We need the recipient list for both SMS and MMS.

final Conversation conv = mConversation;

String msgTxt = mText.toString();

Log.v(TAG, "msgText = " + msgTxt);

if (requiresMms()|| addressContainsEmailToMms(conv, msgTxt)) {

// 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; //如果第一次发送,此时mmsUri为null,如果是重发,则是草稿箱的地址 mMessageUri =content://mms/drafts/1

final PduPersister persister = PduPersister.getPduPersister(mContext);

final SlideshowModel slideshow = mSlideshow;

final SendReq sendReq = makeSendReq(conv,mSubject);

// Do the dirty work of sending the message off of the main UI thread.

new Thread(new Runnable() {

public void run() {

// 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);

}

}).start();

}else {

// Same rules apply as above.

final String msgText = mText.toString();//取出短消息

Log.v(TAG, "msgText = " + msgText);

new Thread(new Runnable() {

public void run() {

preSendSmsWorker(conv, msgText);//发送信息--》

}

}).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;

}

5. src/com/android/mms/data/WorkingMessage.java

private void sendMmsWorker(Conversation conv, Uri mmsUri, PduPersisterpersister, SlideshowModel slideshow, SendReq sendReq) {

Log.v(TAG, "sendMmsWorker");

// If user tries to send the message, it's a signal the inputtedtext is what they wanted.

UserHappinessSignals.userAcceptedImeText(mContext);

// First make sure we don't have too many outstanding unsent message.

Cursor cursor = null;

try {

cursor = SqliteWrapper.query(mContext, mContentResolver,

Mms.Outbox.CONTENT_URI,MMS_OUTBOX_PROJECTION, null, null, null);

if (cursor != null) {//如果MMS_OUTBOX里有未发送的彩信,并且总的大小已经超过了彩信的最大限制,则取消此次发送,并存入草稿箱

Log.v(TAG, "query Mms.Outbox.CONTENT_URI is not empty");

long maxMessageSize = MmsConfig.getMaxSizeScaleForPendingMmsAllowed()*

MmsConfig.getMaxMessageSize();

Log.v(TAG, "MmsConfig.getMaxSizeScaleForPendingMmsAllowed() =" + MmsConfig.getMaxSizeScaleForPendingMmsAllowed());

Log.v(TAG, "MmsConfig.getMaxMessageSize()() = " + MmsConfig.getMaxMessageSize());



long totalPendingSize = 0;

while (cursor.moveToNext()) {

totalPendingSize +=cursor.getLong(MMS_MESSAGE_SIZE_INDEX);

Log.v(TAG, "totalPendingSize = " + totalPendingSize);

}

if (totalPendingSize >= maxMessageSize) {

unDiscard(); // itwasn't successfully sent. Allow it to be saved as a draft.

mStatusListener.onMaxPendingMessagesReached();

return;

}

}else{

Log.v(TAG, "query Mms.Outbox.CONTENT_URI is empty");

}

} finally {

if (cursor != null) {

cursor.close();

}

}

mStatusListener.onPreMessageSent();

// Make sure we are still using the correct thread ID for our

// recipient set.

long threadId = conv.ensureThreadId();

if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) {

LogTag.debug("sendMmsWorker: update draft MMS message " + mmsUri);

}

if (mmsUri == null) {//如果是首次发送,先把彩信保存入草稿箱

// Create a new MMS message if one hasn't been made yet.

Log.v(TAG, "mmsUri == null and startcreateDraftMmsMessage");

mmsUri = createDraftMmsMessage(persister,sendReq, slideshow);

} else {

// Otherwise, sync the MMS message in progress to disk.

Log.v(TAG, "mmsUri = " + mmsUri);

Log.v(TAG, "updateDraftMmsMessage");

updateDraftMmsMessage(mmsUri,persister, slideshow, sendReq);

}

// Be paranoid and clean any draft SMS up.

deleteDraftSmsMessage(threadId);

// 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;

}

MessageSender sender = new MmsMessageSender(mContext, mmsUri,

slideshow.getCurrentMessageSize());

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(mContext, mContentResolver, mmsUri, null, null);

}

// Make sure this thread isn't over the limits in message count

Recycler.getMmsRecycler().deleteOldMessagesByThreadId(mContext, threadId);

} catch (Exception e) {

Log.e(TAG, "Failed to send message: " + mmsUri + ",threadId=" + threadId, e);

}

mStatusListener.onMessageSent();

}

6.src/com/android/mms/transaction/MmsMessageSender.java

public boolean sendMessage(long token) throws MmsException {

// Load the MMS from the message uri

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);

// Move the message into MMS Outbox

p.move(mMessageUri, Mms.Outbox.CONTENT_URI);

// Start MMS transaction service

SendingProgressTokenManager.put(ContentUris.parseId(mMessageUri), token);

mContext.startService(new Intent(mContext, TransactionService.class));

return true;

}

7.src/com/android/mms/transaction/TransactionService.java

@Override

public int onStartCommand(Intent intent, int flags, int startId) {

Log.v(TAG, "onStartCommand");

if (intent == null) {

return Service.START_NOT_STICKY;

}

mConnMgr = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);

boolean noNetwork =!isNetworkAvailable();

if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {

Log.v(TAG, "onStart: #" + startId + ": " + intent.getExtras() + " intent=" + intent);

Log.v(TAG, " networkAvailable=" + !noNetwork);

}

Log.v(TAG, "getAction is " + intent.getAction());

if (ACTION_ONALARM.equals(intent.getAction())|| (intent.getExtras() == null)) {

Log.v(TAG, "ACTION_ONALARM.equals(intent.getAction()) ||(intent.getExtras() == null)");

// Scan database to find all pending operations.

Cursor cursor = PduPersister.getPduPersister(this).getPendingMessages(

System.currentTimeMillis());

if (cursor != null) {

try {

int count = cursor.getCount();

if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {

Log.v(TAG, "onStart: cursor.count=" + count);

}

if (count == 0) {

if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {

Log.v(TAG, "onStart: no pending messages. Stoppingservice.");

}

RetryScheduler.setRetryAlarm(this);

stopSelfIfIdle(startId);

return Service.START_NOT_STICKY;

}

int columnIndexOfMsgId =cursor.getColumnIndexOrThrow(PendingMessages.MSG_ID);

int columnIndexOfMsgType =cursor.getColumnIndexOrThrow(

PendingMessages.MSG_TYPE);

if (noNetwork) {

// Make sure we register for connection state changes.

if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {

Log.v(TAG, "onStart: registerForConnectionStateChanges");

}

MmsSystemEventReceiver.registerForConnectionStateChanges(

getApplicationContext());

}

while (cursor.moveToNext()) {

int msgType =cursor.getInt(columnIndexOfMsgType);

int transactionType =getTransactionType(msgType);

Log.v(TAG, "msgType = " + msgType);

Log.v(TAG, "transactionType = " + transactionType);

if (noNetwork) {

onNetworkUnavailable(startId, transactionType);

return Service.START_NOT_STICKY;

}



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.

int failureType =cursor.getInt(

cursor.getColumnIndexOrThrow(

PendingMessages.ERROR_TYPE));

if (!isTransientFailure(failureType)){

break;

}

// fall-through

default:

Uri uri =ContentUris.withAppendedId(

Mms.CONTENT_URI,

cursor.getLong(columnIndexOfMsgId));

TransactionBundle args = new TransactionBundle(

transactionType, uri.toString());

// FIXME: We use the same startId for all MMs.

launchTransaction(startId, args, false);

break;

}

}

} finally {

cursor.close();

}

} else {

if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {

Log.v(TAG, "onStart: no pending messages. Stoppingservice.");

}

RetryScheduler.setRetryAlarm(this);

stopSelfIfIdle(startId);

}

} else {

if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {

Log.v(TAG, "onStart: launch transaction...");

}

// For launching NotificationTransaction and test purpose.

TransactionBundle args = newTransactionBundle(intent.getExtras());

launchTransaction(startId, args,noNetwork);

}

return Service.START_NOT_STICKY;

}

8. src/com/android/mms/transaction/TransactionService.java

private void launchTransaction(int serviceId,TransactionBundle txnBundle, boolean noNetwork) {

Log.v(TAG, "launchTransaction");

if (noNetwork) {

Log.w(TAG, "launchTransaction: no network error!");

onNetworkUnavailable(serviceId,txnBundle.getTransactionType());

return;

}

Message msg = mServiceHandler.obtainMessage(EVENT_TRANSACTION_REQUEST);

msg.arg1 = serviceId;

msg.obj = txnBundle;

if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {

Log.v(TAG, "launchTransaction: sending message " + msg);

}

mServiceHandler.sendMessage(msg);

}

9. src/com/android/mms/transaction/TransactionService.java

private final class ServiceHandler extends Handler {

public ServiceHandler(Looper looper) {

super(looper);

}

/**

* Handle incoming transactionrequests.

* The incoming requests are initiatedby the MMSC Server or by the

* MMS Client itself.

*/

@Override

public void handleMessage(Messagemsg) {

if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {

Log.v(TAG, "Handling incoming message: " + msg);

}

Transaction transaction = null;

switch (msg.what) {

case EVENT_QUIT:

getLooper().quit();

return;

case EVENT_CONTINUE_MMS_CONNECTIVITY:

synchronized (mProcessing) {

if (mProcessing.isEmpty()) {

return;

}

}

if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {

Log.v(TAG, "handle EVENT_CONTINUE_MMS_CONNECTIVITYevent...");

}

try {

int result =beginMmsConnectivity();

if (result != Phone.APN_ALREADY_ACTIVE){

Log.v(TAG, "Extending MMS connectivity returned " + result +

" instead of APN_ALREADY_ACTIVE");

// Just wait for connectivity startup without

// any newrequest of APN switch.

return;

}

} catch (IOException e) {

Log.w(TAG, "Attempt to extend use of MMS connectivityfailed");

return;

}

// Restart timer

sendMessageDelayed(obtainMessage(EVENT_CONTINUE_MMS_CONNECTIVITY),

APN_EXTENSION_WAIT);

return;

case EVENT_DATA_STATE_CHANGED:

/*

* If we are being informedthat connectivity has been established

* to allow MMS traffic,then proceed with processing the pending

* transaction, if any.

*/

if (mConnectivityListener == null) {

return;

}

NetworkInfo info = mConnectivityListener.getNetworkInfo();

if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {

Log.v(TAG, "Handle DATA_STATE_CHANGED event: " + info);

}

// Check availability of the mobile network.

if ((info == null) || (info.getType() !=

ConnectivityManager.TYPE_MOBILE_MMS)) {

if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {

Log.v(TAG, " type isnot TYPE_MOBILE_MMS, bail");

}

return;

}

if (!info.isConnected()) {

if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {

Log.v(TAG, " TYPE_MOBILE_MMS not connected, bail");

}

return;

}

TransactionSettings settings = newTransactionSettings(

TransactionService.this,info.getExtraInfo());

// If this APN doesn't have an MMSC, wait for one that does.

if (TextUtils.isEmpty(settings.getMmscUrl())){

if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {

Log.v(TAG, " empty MMSCurl, bail");

}

return;

}

// Set a timer to keep renewing our "lease" on the MMSconnection

sendMessageDelayed(obtainMessage(EVENT_CONTINUE_MMS_CONNECTIVITY),

APN_EXTENSION_WAIT);

processPendingTransaction(transaction, settings);

return;

case EVENT_TRANSACTION_REQUEST://响应请求

Log.v(TAG, "EVENT_TRANSACTION_REQUEST");

int serviceId = msg.arg1;

try {

TransactionBundle args= (TransactionBundle) msg.obj;

TransactionSettingstransactionSettings;

// Set the connection settings for this transaction.

// If these have not been set in args, load thedefault settings.

String mmsc =args.getMmscUrl();

if (mmsc != null) {

transactionSettings= new TransactionSettings(

mmsc,args.getProxyAddress(), args.getProxyPort());

} else {

transactionSettings= new TransactionSettings(

TransactionService.this, null);

}

int transactionType =args.getTransactionType();

Log.v(TAG, "transactionType = " + transactionType)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值