您的位置:首页 > 其它

发一条短信路程简介

2014-06-27 16:36 141 查看
1.      短信应用启动

(a).AndroidManifest.xml配置

  <activityandroid:name=".ui.BootActivity" android:theme="@android:style/Theme.NoDisplay">

           <intent-filter>

                <actionandroid:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER"/>

                <categoryandroid:name="android.intent.category.DEFAULT" />

           </intent-filter>

                     …...

 </activity>

(b).启动时中转,我们一般会以会话形式显示短信

文件路径:com.android.mms.ui.BootActivity

public void onCreate(Bundle savedInstanceState) {

        ……

        enterMms();

}

private void enterMms() {

        ……

             //判断是文件夹形式显示,还是会话形式显示短信,这里启动ConversationList

        if(MmsConfig.getFolderModeEnabled() && dirMode) {

            intent = newIntent(this, FolderViewList.class);

           intent.putExtra("floderview_key",FolderViewList.OPTION_INBOX);// show inbox by default

        } else {

            intent = newIntent(this, ConversationList.class);

        }

       intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);///M:changed for alps00437708

        startActivity(intent);

    }

(c).短信会话界面的构建

文件路径:com.android.mms.ui.ConversationList

protected void onCreate(Bundle savedInstanceState) {

           ……

           //构建界面布局

           setContentView(R.layout.conversation_list_screen);

 

           ……

           //初始化sim卡信息适配器,以便填充布局中ListView

initListAdapter();

}

private
void
initListAdapter(){
     //构建会话适配器对象,其中会调用ConversationListAdapter类中bindView
        mListAdapter =
new
ConversationListAdapter(this,
null);
       // ConversationList类继承ListActivity, 调用setListAdapter函数将数据进行绑定到视图
        setListAdapter(mListAdapter);
        ……
}

文件路径:com.android.mms.ui.ConversationListAdapter

  public void bindView(View view, Contextcontext, Cursor cursor) {

            /每个对话记录的视图

        ConversationListItem headerView =(ConversationListItem) view;

 

        if (!mIsScrolling) {

            ……

                    //对话内容的获取

            Conversation conv =Conversation.from(context, cursor);

            ……

                    //对话内容绑定到视图

            headerView.bind(context, conv);

        } else {

            headerView.bindDefault();

        }

       ……

    }

小结:上面内容是MMS应用的启动,到会话记录界面,以及会话内容的加载过程。

 

 

2.      一条短信的发出

(a).界面(ui): 输入文本或者添加多媒体附件后,单击按钮发送后,将检查信息合法性以及区分ip或者非ip 消息,单卡或者双卡情况

文件路径:com.android.mms.ui.ComposeMessageActivity

public
void
onClick(View v) {
        if (v ==
mSendButtonSms || v ==
mSendButtonMms || v == mSendButtonIpMessage) {
            if (mSendButtonCanResponse) {
                mSendButtonCanResponse =
false;
             //检查是否满足发送条件,包括收件人不为空,文本或多媒体内容不为空
                if (isPreparedForSending()) {
                    ……
                    checkRecipientsCount();
                }
           }
 }

private void checkRecipientsCount() {

final int mmsLimitCount =MmsConfig.getMmsRecipientLimit();

//检查多媒体休息收件人个数,如果超过一定限制,会提示是否继续发送,选择继续发送时会有一些收件人被删除

        if(mWorkingMessage.requiresMms() && recipientCount() > mmsLimitCount){

         ……

           builder.setPositiveButton(R.string.yes, newDialogInterface.OnClickListener() {
                public
void
onClick(DialogInterface dialog,
int
which) {
               //这里另开启一个线程用于发送MMS消息
                    runOnUiThread(new Runnable() {
                       public
void
run() {

                   ……

                   //单卡,双卡情况下的处理

simSelection();
                        }
         });

}else{

      //检查收件人是否为空,如果为空,则取消发送,否则进入下面else部分

       ……

      else{

       ……

//单卡,双卡情况下的处理

simSelection()

}

}

}

备注:为了简化发送情况,目前只以单卡情况进行分析

private
void
simSelection() {
     //单卡情况
        if (EncapsulatedFeatureOption.MTK_GEMINI_SUPPORT ==
false) {
            confirmSendMessageIfNeeded();
      }

     ……

}

private voidconfirmSendMessageIfNeeded() {

        if (!isRecipientsEditorVisible()) {

//首先判断联系人输入框是否可见,如果不可见,那么可以直接发送。

           checkConditionsAndSendMessage(true);

            return;

        }

            ……

        if(mRecipientsEditor.hasInvalidRecipient(isMms)) {

                           ……

                //检查是否有非法的联系人,如果存在,弹出AlertDialog给用户提示

            } else {

//如果没有非法的联系人,那么直接发送。

               checkConditionsAndSendMessage(true);

}

        }

}

private voidcheckConditionsAndSendMessage(boolean bCheckEcmMode){

             ……

             //当是ip消息时

if (mIsMessageDefaultSimIpServiceEnabled && isNetworkConnected(getApplicationContext())
               && isCurrentRecipientIpMessageUser()
                && (mIpMessageDraft !=
null ||
mIpMessageForSend != null
                        || (mIpMessageDraft ==
null && !mWorkingMessage.requiresMms()))){
                     checkIpMessageBeforeSendMessage(bCheckEcmMode);
                     return[/b];
          }

        //当是非ip消息时

final
int
result = mCellMgr.handleCellConn(slotId,requestType,
new Runnable() {
            public
void
run() {
             ……
               checkIpMessageBeforeSendMessage(bCEM);
            }
});

备注:当前流程只以非ip信息进行分析

private voidcheckIpMessageBeforeSendMessage(boolean bCheckEcmMode) {

       ……

            sendMessage(bCheckEcmMode);

            …..

}

private voidsendMessage(boolean bCheckEcmMode) {

      ……

           //当前没有消息正在发送时

if (!mSendingMessage) {

       ……

       mWorkingMessage.send(mDebugRecipients,mSelectedSimId);

       ……

}

}

(b).数据(data):将要发送的信息保存到数据库中,并发送广播通知

文件路径:com.android.mms.data.WorkingMessage

public voidsend(final String recipientsInUI, final int simId) {

           ……

           //检查当前信息的mMmsState以及是否含有email地址,来判断当前信息是否会转化为彩信

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

       ……

new Thread(new Runnable() {
                public
void
run() {
                    final
SendReq sendReq = makeSendReq(conv,subject);
                    slideshow.prepareForSend();
                    sendMmsWorker(conv, mmsUri,persister, slideshow, sendReq, simId);
          updateSendStats(conv);}}, "WorkingMessage.sendMMS").start();

} else {   //处理短信的逻辑

         final String msgText= mText.toString();

               //开启一个线程,主线程返回,在新开启的线程里会执行

         new Thread(newRunnable() {

            public void run(){                 

                   preSendSmsWorker(conv, msgText, recipientsInUI, simId);

                    updateSendStats(conv);

                }

            },"WorkingMessage.send SMS").start();

}

……

}

 

private voidpreSendSmsWorker(Conversation conv, String msgText, String recipientsInUI, intsimId) {

             //首先 检查/创建 一个threadId,并且调用sendSmsWorker方法。最后删除当前会话内的草稿短信。

比较重要的是两个方法,第一个是conv.ensureThreadId,另一个是sendSmsWorker

            long origThreadId = conv.getThreadId();

        long threadId = conv.ensureThreadId();

            ……

            sendSmsWorker(msgText, semiSepRecipients, threadId, simId);

            ……

}

private voidsendSmsWorker(String msgText, String semiSepRecipients, long threadId, intsimId) {

            //获取所有收件人

        String[] dests =TextUtils.split(semiSepRecipients, ";");

        ……

           //新建一个SmsMessageSender对象,将联系人的发送地址,发送内容,会话id(threadId)作为参数,然后调用sendMessage方法

        MessageSender sender = newSmsMessageSender(mActivity, dests, msgText, threadId);

        sender.setSimId(simId);

        try {

            sender.sendMessage(threadId);

                 ……

        } catch (Exception e) {

            Log.e(TAG, "Failed to send SMSmessage, threadId=" + threadId, e);

        }

//回调函数,通知ComposeMessageActivity发送完成

                    mStatusListener.onMessageSent();

                ……

}

文件路径:com.android.mms.trasaction.SmsMessageSender

public booleansendMessage(long token) throws MmsException {

       returnqueueMessage(token);

}

private booleanqueueMessage(long token) throws MmsException{

           //检查设置,是否需要发送报告

           ……

           //然后根据mNumberOfDests,执行Sms.addMessageToUri,将信息插入到数据库中

           ……

else {

            EncapsulatedTelephony.Sms.addMessageToUri(mContext.getContentResolver(),

                Uri.parse("content://sms/queued"), mDests[i],

                 mMessageText, null,mTimestamp,

                 true /* read */,

                 requestDeliveryReport,

                 mThreadId,

                 mSimId);

      }

           ……

           //发起一个广播,通知SmsReceiverService进行处理

Intent sentIt = new Intent(SmsReceiverService.ACTION_SEND_MESSAGE,null, mContext,

                SmsReceiver.class);

     sentIt.putExtra(EncapsulatedPhone.GEMINI_SIM_ID_KEY, mSimId);

      mContext.sendBroadcast(sentIt);

}

(c). 广播中的处理逻辑

文件路径: com.android.mms.trasaction.SmsReceiverService

private finalclass ServiceHandler extends Handler {

      ……

      public void handleMessage(Message msg){

                  ……

                  else if(ACTION_SEND_MESSAGE.endsWith(action)) {

               handleSendMessage(intent) ;

          }

                  ……

}

}

private voidhandleSendMessage(Intent intent) {

      if(!mSending) {//当前没有信息正在发送时

            if(EncapsulatedFeatureOption.MTK_GEMINI_SUPPORT) {

                sendFirstQueuedMessage(intent.getIntExtra(EncapsulatedPhone.GEMINI_SIM_ID_KEY,-1));

            } else {

                           //发送信息

                sendFirstQueuedMessage(-1);

            }

}

}

publicsynchronized void sendFirstQueuedMessage(int simId) {

           //要发送信息保存在数据库位置

final Uri uri = Uri.parse("content://sms/queued");

……

Cursor c = SqliteWrapper.query(this, resolver, uri, SEND_PROJECTION,where, null, "date ASC");//按时间倒序查出

if (c != null) {

    try {

       if (c.moveToFirst()) {

       String msgText =c.getString(SEND_COLUMN_BODY);

       String address =c.getString(SEND_COLUMN_ADDRESS);

       int threadId =c.getInt(SEND_COLUMN_THREAD_ID);

       int status =c.getInt(SEND_COLUMN_STATUS);

int msgId =c.getInt(SEND_COLUMN_ID);

       Uri msgUri =ContentUris.withAppendedId(Sms.CONTENT_URI, msgId);

          //查出的数据封装成SmsSingleRecipientSender对象,然后进行发送

SmsMessageSendersender = new SmsSingleRecipientSender(this,

              address,msgText, threadId, status == Sms.STATUS_PENDING, msgUri);

 

try {

           sender.sendMessage(SendingProgressTokenManager.NO_TOKEN);;

            mSending = true;

       }

}

}

文件路径: com.android.mms.trasaction.SmsSingleRecipientSender

public booleansendMessage(long token) throws MmsException {

           ……

           //到这里才算得真正调用Api中接口,将短信内容细分,EncapsulatedSmsManager是MTK对SmsManager的封装

           messages =EncapsulatedSmsManager.divideMessage(msgText, codingType);

           ……

else {

        //调用EncapsulatedSmsManager中发短信的方法,EncapsulatedSmsManager是MTK对SmsManager的封装

           EncapsulatedSmsManager.sendMultipartTextMessageWithEncodingType(mDest,mServiceCenter, messages,

                codingType, sentIntents,deliveryIntents);

      }

           ……

}

文件路径: com.mediatek.encapsulation.android.telephony.EncapsulatedSmsManager

public staticArrayList<String> divideMessage(String text, int encodingType) {

     if (EncapsulationConstant.USE_MTK_PLATFORM){

          returnSmsManagerEx.getDefault().divideMessage(text, encodingType);

     } else {

          returnSmsManager.getDefault().divideMessage(text);

     }

}

public staticvoid sendMultipartTextMessageWithEncodingType(String destAddr, String scAddr,

            ArrayList<String> parts, intencodingType, ArrayList<PendingIntent> sentIntents,

            ArrayList<PendingIntent>deliveryIntents) {

     if(EncapsulationConstant.USE_MTK_PLATFORM) {

            SmsManagerEx.getDefault().sendMultipartTextMessageWithEncodingType(destAddr,scAddr,

              parts, encodingType, 0,sentIntents, deliveryIntents);

     } else {}

}

 

总结: 应用层流程简介:

上面简要介绍了短信应用的启动,以及一条短信发送到Framework层的过程。应用部分为SmsMessageSender(发送者)和SmsReceiverService(接受者),

发送者先把短信内容存入数据,再广播告知接受者,接受者短信内容从数据库查出,调用MTK封装好的api接口进行发送。

Framework层流程简介:

(Framework/opt/telephony/src/java/android/telephony/SmsManager.java)------>sendMultipartTextMessageWithEncodingType()----->GeminiSmsManager.sendMultipartTextMessageWithEncodingTypeGemini()

(mediatek/frameworks-ext/base/telephony/java/android/telephony/gemini/GeminiSmsManager.java)----->sendMultipartTextMessageWithEncodingTypeGemini()------>iccISms.sendTextWithEncodingType()

(Framework/opt/ telephony/src/java/com/android/internal/telephony/IccSmsInterfaceManagerProxy.java)----->sendTextWithEncodingType()------> mIccSmsInterfaceManager.sendTextWithEncodingType()

(Framework/opt/telephony/src/java/com/android/internal/telephony/IccSmsInterfaceManager.java)----->sendTextWithEncodingType()------>mDispatcher.sendTextWithEncodingType()

(Framework/opt/telephony/src/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java)----->sendTextWithEncodingType ()------>sendRawPdu()------>sendSMS()

(Framework/opt/ telephony/src/java/com/android/internal/telephony/RIL.java)sendSMS (String smscPDU, String pdu, Message result)

RIL层流程简介:

Java-RIL将信息内容组装成RILRequest,,加入消息标志和令牌,然后将数据以byte形式写入Scoket,与C-RIL的守护进程RILD进行通讯。

RILD进程取出信息内容,根据消息标志,组装成相应AT命令,发送给基带芯片,并等待基带的处理和回应,然后逐步返回。

 

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: