发送SMS与MMS过程

来源:互联网 发布:上班签到软件 编辑:程序博客网 时间:2024/05/17 08:17

Android4.2

pending_msgs表:  等待下载或发送的信息

proto_type:0代表sms,1代表mms。

msg_id     :代表pdu表或sms表的id

msg_type : 128代表等待发送的信息,130代表失败后等待重发的信息。在发送时这个筛选掉了已发送的信息。

err_type    :0代表没异常。


点击发送按钮触发发送,短信是个ImageButton,彩信是个带图片的TextView

    @Override    public void onClick(View v) {        if ((v == mSendButtonSms || v == mSendButtonMms) && isPreparedForSending()) {            confirmSendMessageIfNeeded();        } else if ((v == mRecipientsPicker)) {            launchMultiplePhonePicker();        }    }
在confirmSendMessageIfNeeded方法中,粗略的判断了联系人号码合法性,有数字就是合法的。合法就调用了sendMessage(true)方法,在sendMessage方法中调用了mWorkingMessage.send(mDebugRecipients),在send方法中对短彩信发送做了区分。

一、短信SMS

调用了preSendSmsWorker(conv, msgText, recipientsInUI);方法,在此方法中调用了sendSmsWorker(msgText, semiSepRecipients, threadId);方法。

    private void sendSmsWorker(String msgText, String semiSepRecipients, long threadId) {        String[] dests = TextUtils.split(semiSepRecipients, ";");        if (LogTag.VERBOSE || Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {            Log.d(LogTag.TRANSACTION, "sendSmsWorker sending message: recipients=" +                    semiSepRecipients + ", threadId=" + threadId);        }        MessageSender sender = new SmsMessageSender(mActivity, dests, msgText, threadId);        try {            sender.sendMessage(threadId);            // Make sure this thread isn't over the limits in message count            Recycler.getSmsRecycler().deleteOldMessagesByThreadId(mActivity, threadId);        } catch (Exception e) {            Log.e(TAG, "Failed to send SMS message, threadId=" + threadId, e);        }        mStatusListener.onMessageSent();        MmsWidgetProvider.notifyDatasetChanged(mActivity);    }

接着调用了SmsMessageSender.java类的sendMessage方法发送信息,SmsMessageSender.java在构造时通过getOutgoingServiceCenter(mThreadId)方法试图从收件箱中获取服务中心号码,留给子类所用。sendMessage方法调用了queueMessage(token)方法,在此方法中把短信存到sms数据库中,每一个联系人存一条,type=0。接着发广播到SmsReceiver.class中,收到广播后启动SmsReceiverService服务。

SmsReceiverService中调用hander处理信息,发短信的Action为ACTION_SEND_MESSAGE,调用了handleSendMessage()方法,接着sendFirstQueuedMessage()被调用,在sendFirstQueuedMessage()方法中取出了Uri.parse("content://sms/queued")的待发送数据,构建了SmsMessageSender的子类SmsSingleRecipientSender并调用其的sendMessage方法发送消息。sendMessage方法主要是使用SmsManager对短信进行长短信拆分并一个个发送。

 smsManager.sendMultipartTextMessage(mDest, mServiceCenter, messages, sentIntents, deliveryIntents);

发送成功或者失败都要走SmsReceiverService的handleSmsSent(intent, error);方法。

framework流程:

在SmsManagger的sendMultipartTextMessage方法中判断messages的size,等于1为短信,大于1为长短信,分别走不同流程。

短信:

          sendTextMessage(destinationAddress, scAddress, parts.get(0),                    sentIntent, deliveryIntent);
在此方法中调用
            ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));            if (iccISms != null) {                iccISms.sendText(destinationAddress, scAddress, text, sentIntent, deliveryIntent);            }
通过远程调用,被调用的类为IccSmsInterfaceManagerProxy.java,实际处理的类为IccSmsInterfaceManager.java。在IccSmsInterfaceManager的senText方法中调用了
 mDispatcher.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent);
其中mDispatcher为类SMSDispatcher的对象。用移动卡发了个短信测试后发现此处SMSDispatcher为子类GsmSMSDispatcher,IccSmsInterfaceManager为子类SimSmsInterfaceManager。

在GsmSMSDispatcher的sendText方法里调用了

sendRawPdu(pdu.encodedScAddress, pdu.encodedMessage, sentIntent, deliveryIntent,                    destAddr);
接着调用了sendSms(tracker)方法,最后调到了
mCm.sendSMS(IccUtils.bytesToHexString(smsc), IccUtils.bytesToHexString(pdu), reply);
mCm是CommandsInterface接口的对象,在GsmSMSDispatcher构造时传进来了PhoneBase对象,PhoneBase对象构造时传进去了CommandsInterface对象。PhoneBase对象里的CommandsInterface接口其实就是Ril.java所实现的接口。也就是说Ril.java里的sendSMS方法最后会被调到,之后就是RIL层的事了。

长短信与短信流程基本差不多。

sms表:

type      : ALL=0;INBOX=1;SENT=2;DRAFT=3;OUTBOX=4;FAILED=5;QUEUED=6; 6表示等待发送。

status  : 32表示启动了发送报告。


二、彩信MMS(ComposeMessageActivity、WorkingMessage、MmsMessageSender、TransactionService)

调用了

 sendMmsWorker(conv, mmsUri, persister, slideshow, sendReq, textOnly);
发送彩信,主要流程为:把一些基本信息存到发件箱内
            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);                }                mmsUri = SqliteWrapper.insert(mActivity, mContentResolver, Mms.Outbox.CONTENT_URI,                        values);            }

接着查询彩信发件箱,所有发件箱内彩信的m_size字段的相加和如果大于4*300*1024,则unDiscard()使得mDiscarded为false,并调用mStatusListener.onMaxPendingMessagesReached()存草稿。

如果待发送的彩信没超出限制,则

mmsUri = createDraftMmsMessage(persister, sendReq, slideshow, mmsUri,                        mActivity, null);
获取uri,如果传进去的uri有id,则不变,否则返回带id的uri,主要通过
 Uri res = persister.persist(sendReq, preUri == null ? Mms.Draft.CONTENT_URI : preUri,                    true, MessagingPreferenceActivity.getIsGroupMmsEnabled(context),                    preOpenedFiles);
得到uri,persist方法把这个带id的uri进行数据更新,如果是不带id的uri,则是插入返回带id的uri。


获取uri后构建发送类,接着发送(sender.sendMessage(threadId))

        MessageSender sender = new MmsMessageSender(mActivity, mmsUri,                slideshow.getCurrentMessageSize());
在sendMessage方法里存了一条数据到pending_msgs数据表内。接着以id为键thread_id为值存到SendingProgressTokenManager中,然后启动TransactionService.class服务。如果发送的彩信是从草稿箱里去的,则通过触发器更新pending_msgs。

TransactionService.class服务中用hander处理消息

            switch (msg.what) {                case EVENT_NEW_INTENT:                    onNewIntent((Intent)msg.obj, msg.arg1);
在onNewIntent方法里

判断了网络状态noNetwork,intent.getAction()得到的值是null,所以走if流程,以时间为条件获取pending_msgs表中所有时间(due_time)小于或等于当前时间并且err_type字段值小于等于10的数据。如果没网络,则给出提示、stopSelf(serviceId)并返回。

                    while (cursor.moveToNext()) {                        int msgType = cursor.getInt(columnIndexOfMsgType);                        int transactionType = getTransactionType(msgType);                        if (noNetwork) {                            onNetworkUnavailable(serviceId, transactionType);                            return;                        }                        switch (transactionType) {
如果网络正常则构建TransactionBundle对象,此对象存储以msg_id与mms构成的uri及msg_type变换后的int值。调用launchTransaction(serviceId, transactionBundle, false);方法。接着又调用了hander的处理,key为EVENT_TRANSACTION_REQUEST。接着根据msg_type不同构建不同类型的Transaction子类对象。
   if (!processTransaction(transaction)) {
开始发送彩信,先排除掉短信正在发送或者已发送的情况后再判断网络,如果网络良好则往下走,否则保存要发送的信息返回
                int connectivityResult = beginMmsConnectivity();                if (connectivityResult == PhoneConstants.APN_REQUEST_STARTED) {                    mPending.add(transaction);                    if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {                        Log.v(TAG, "processTransaction: connResult=APN_REQUEST_STARTED, " +                                "defer transaction pending MMS connectivity");                    }                    return true;                }
如果没返回最后会走到开始发送:
            transaction.attach(TransactionService.this);            transaction.process();
正式开始处理发送,process()方法里启动一个线程,在线的run方法里构建了SendReq对象,调用
            byte[] response = sendPdu(SendingProgressTokenManager.get(tokenKey),                                      new PduComposer(mContext, sendReq).make());
发送信息,每次发送不管成功与否都会更新data字段,根据response更新resp_st字段,如果发送成功了更新m_id(信息中心的?)字段,最后
            // Move M-Send.req from Outbox into Sent.            Uri uri = persister.move(mSendReqURI, Sent.CONTENT_URI);
把信息由发件箱移到 已发送。

发送彩信采用的是http的方式,sendPdu一直到最后调用了

    protected static byte[] httpConnection(Context context, long token,            String url, byte[] pdu, int method, boolean isProxySet,            String proxyHost, int proxyPort) throws IOException {
发送。

对于发送前判断的网络没准备好而保存的数据,在onCreate中注册了广播接收者,当网络恢复时接收广播,最后调用

            renewMmsConnectivity();            mServiceHandler.processPendingTransaction(null, settings);

在processPendingTransaction方法中取出未发送的数据,继续走processTransaction流程。


彩信发送结果:

在SendTransaction中发送完彩信后返回结果数组 byte[] response ,解析返回值后更新mms数据,最后调用notifyObservers()方法,而在此类构建时 

 attach(RetryScheduler.getInstance(context))

把observer类 RetryScheduler注册到此类中,最后在RetryScheduler的update方法中对返回结果处理(弹Toast)。

短信发送结果:

在SmsSingleRecipientSender中发送后会以action为SmsReceiverService.MESSAGE_SENT_ACTION启动SmsReceiverService,最后在handleSmsSent方法里处理结果值,如果没插卡,mResultCode == SmsManager.RESULT_ERROR_NO_SERVICE会把短信状态切回type ==6.

原创粉丝点击