android中发送普通信息的详细流程

从信息编辑页面开始,编辑好信息,选择联系人后,点击可用的卡即可发送。这个开始的类是ComposeMessageActivity。
在onCreate和onResume中,主要是设置页面显示的,比如检测一下当前插入了几个卡,若只有一个,那个相应的卡(比如卡一)为可用状态。点击可用的卡发送信息时触发下面的函数执行:
 public void onClick(View v) {
        // Set phone id label,0 for phone 1, 1 for phone 2.
        if (TelephonyManager.getPhoneCount() > 1) {//==============双卡的情况下
            if (v == mSendButton2) {
                mPhoneId = PHONE_ID_2;
            } else if (v == mSendButton1) {
                mPhoneId = PHONE_ID_1;
            }          
            //点击了 卡一或者卡二发送,并且已经准备好要发送了
            if ((v == mSendButton1 || v == mSendButton2) && isPreparedForSending()) {
                //确认发送信息
                confirmSendMessageIfNeeded();
                //list中保存着所有需要发送的联系人信息,信息发送完之后清空它的内容
                list.clear();
            } else if (v == mContactsSelectButton) {
                //点击了选择联系人的按钮
                try {
                    startPickContactActivity();
                } catch (ActivityNotFoundException e) {
                    // contacts has not provided the function.
                    Log.e(TAG,
                            "No Activity found to handle Intent { act=com.android.contacts.MULTIOPERATELIST }",
                            e);
                    Toast.makeText(getApplicationContext(),
                            R.string.No_Activity_found_to_handle_Intent, Toast.LENGTH_SHORT).show();
                }
            }
        } else {//===========================================只有一张卡的情况下         
      }
    }

然后继续调用下面函数:
private void confirmSendMessageIfNeeded() {
        if (!isRecipientsEditorVisible()) {
            Log.d(TAG, "autosendMSG");
            sendMessage(true);
            return;
        }
       //布尔值确定当前信息是否需要发送彩信
        boolean isMms = mWorkingMessage.requiresMms();
        if (mRecipientsEditor.hasInvalidRecipient(isMms)) {           
            //是否含有不合法的收件人
            Log.d(TAG, "bobo  发彩信");
            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,
                            new SendIgnoreInvalidRecipientListener())
                    .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 {
            Log.d("ComposeMessageActivity","sms");
            sendMessage(true);
        }
    }

    private void sendMessage(boolean bCheckEcmMode) {
        if (bCheckEcmMode) {
            // TODO: expose this in telephony layer for SDK build
            ////判断电话是否处于紧急拨号模式,得到的inEcm一般为空
            String inEcm = SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE);
            if (Boolean.parseBoolean(inEcm)) {
                Log.i("Bug2311", "BOBOBO  ECM 111");
                try {
                    Log.i("Bug2311", "BOBOBO  ECM 2222");
                    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 first and then add
            // them back once the recipient list has settled.
            removeRecipientsListeners();//==============取消对收件人的监听
            // cienet edit maotianliang 2011-6-9:
            // mWorkingMessage.send();
            Log.i("Bug2311", "sendMessage(boolean bCheckEcmMode)");
            mWorkingMessage.send(mPhoneId);//============发送信息
            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();
        }
    }

再继续调用就跳到了类WorkingMessage中了:
  public void send(final int subscription) {
        if (DEBUG || Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {
            LogTag.debug("send");
        }
        Log.i("Bug2311", "send(final int subscription)");
        // Get ready to write to disk.
        //主要做一下同步收件人和WorkingMessage,彩信时在准备其他一些东西
        prepareForSave(true );
      // We need the recipient list for both SMS and MMS.
        final Conversation conv = mConversation;
        String msgTxt = mText.toString();

        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;
            final PduPersister persister = PduPersister.getPduPersister(mContext);

            final SlideshowModel slideshow = mSlideshow;
            //cienet edit maotianliang 2011-6-10:
            final SendReq sendReq = makeSendReq(conv, mSubject, subscription);

            // 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();
                    //cienet edit maotianliang 2011-6-10:
                    sendMmsWorker(conv, mmsUri, persister, slideshow, sendReq, subscription);
                }
            }).start();
        } else {
            // Same rules apply as above.
            final String msgText = mText.toString();//取出信息
            new Thread(new Runnable() {
                public void run() {
                    //cienet edit maotianliang 2011-6-10:
                    Log.d("WorkingMessage", "preSendSmsWorker..sms");
                    //subscription是传递过来的参数,即为phoneId,,,发送信息
                    preSendSmsWorker(conv, msgText, subscription);
                }
            }).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;
    }

private void preSendSmsWorker(Conversation conv, String msgText, int subscription) {
        // If user tries to send the message, it's a signal the inputted text is what they wanted.
        //如果用户尝试发送信息,这就是一个信号,说明输入的文字是他们想要的
        UserHappinessSignals.userAcceptedImeText(mContext);

        //mStatusListener是一个回调接口,在发送信息前调用此函数
        //重置一些信息,比如清空输入内容框、一些监听等等
        mStatusListener.onPreMessageSent();

        // Make sure we are still using the correct thread ID for our recipient set.
        //新建获得会话线程ID
        long threadId = conv.ensureThreadId();

        //获得收件人列表,并将其序列化
        final String semiSepRecipients = conv.getRecipients().serialize();

        //只需要做一个正常的发送。我们已经在一个非UI线程中,所以不必启动其他线程来做这个工作
        //发送信息==》
        sendSmsWorker(msgText, semiSepRecipients, threadId, subscription);

        // Be paranoid and clean any draft SMS up.
        //清理草稿信息
        deleteDraftSmsMessage(threadId);
    }

  private void sendSmsWorker(String msgText, String semiSepRecipients, long threadId, int subscription) {
    String[] dests = TextUtils.split(semiSepRecipients, ";");
        if (DEBUG || Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {
            LogTag.debug("sendSmsWorker sending message");
        }
        MessageSender sender;

        // runtime check for dsds
        if(TelephonyManager.getPhoneCount()>1){
            sender = new SmsMessageSender(mContext, dests, msgText, threadId,
                        subscription);//subscription这个参数即为phoneId
        } else {
            sender = new SmsMessageSender(mContext, dests, msgText, threadId);
        }
        try {
            sender.sendMessage(threadId);//根据ThreadID发送信息----》

            // Make sure this thread isn't over the limits in message count
            //确保这个线程不超过限制的邮件数
            Recycler.getSmsRecycler().deleteOldMessagesByThreadId(mContext, threadId);
        } catch (Exception e) {
            Log.e(TAG, "Failed to send SMS message, threadId=" + threadId, e);
        }

      //mStatusListener是一个回调接口,在发送信息时调用此函数
        mStatusListener.onMessageSent();
    }

public boolean sendMessage(long token) throws MmsException {
        // In order to send the message one by one, instead of sending now, the message will split,
        // and be put into the queue along with each destinations
        return queueMessage(token);
    }

    private boolean queueMessage(long token) throws MmsException {
        Log.d("SmsMessageSender","mNumberOfDests =---------------1:" +  mNumberOfDests);
        //mNumberOfDests 即为目标地址的数量,即收信人数量
       
        if ((mMessageText == null) || (mNumberOfDests == 0)) {
            //如果信息内容为空或者收信人数量为0,那么会抛出异常
            // Don't try to send an empty message.
            throw new MmsException("Null message body or dest.");
        }

        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
        //确认是否要求有发送报告,默认值是没有
        boolean requestDeliveryReport = prefs.getBoolean(
                MessagingPreferenceActivity.SMS_DELIVERY_REPORT_MODE,
                DEFAULT_DELIVERY_REPORT_MODE);
        Log.d("SmsMessageSender","mNumberOfDests =---------------2:" +  mNumberOfDests);
        for (int i = 0; i < mNumberOfDests; i++) {
            //==================根据收件人数目分别建立短信放入发送队列
            try {
                if(TelephonyManager.getPhoneCount()>1){
                    log(" DSDS enabled: updating Database with sub = " + mPhoneId);
                    Sms.addMessageToUri(mContext.getContentResolver(),
                            Uri.parse("content://sms/queued"), mDests[i],
                            mMessageText, null, mTimestamp,
                            true ,
                            requestDeliveryReport,
                            mThreadId, mPhoneId);
                } else {
                    log(" DSDS not enabled: updating Database without sub");
                    Sms.addMessageToUri(mContext.getContentResolver(),
                            Uri.parse("content://sms/queued"), mDests[i],
                            mMessageText, null, mTimestamp,
                            true ,
                            requestDeliveryReport,
                            mThreadId);
                }
                //cienet end yuanman.
            } catch (SQLiteException e) {
                SqliteWrapper.checkSQLiteException(mContext, e);
            }
        }
        // Notify the SmsReceiverService to send the message out
        //通知SmsReceiverService来发送短信,传递参数ACTION_SEND_MESSAGE
        mContext.sendBroadcast(new Intent(SmsReceiverService.ACTION_SEND_MESSAGE,
                null,
                mContext,
                SmsReceiver.class));
        return false;
    }

上面发出的广播由SmsReceiver广播接收器进行接收::

public void onReceive(Context context, Intent intent) {
        onReceiveWithPrivilege(context, intent, false);
    }

    protected void onReceiveWithPrivilege(Context context, Intent intent, boolean privileged) {
              
        intent.setClass(context, SmsReceiverService.class);
        intent.putExtra("result", getResultCode());//??????????????????????????????????????????
        beginStartingService(context, intent);
    }

public static void beginStartingService(Context context, Intent intent) {
        synchronized (mStartingServiceSync) {
            if (mStartingService == null) {
                PowerManager pm =
                    (PowerManager)context.getSystemService(Context.POWER_SERVICE);
                mStartingService = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
                        "StartingAlertService");
                mStartingService.setReferenceCounted(false);
            }
            mStartingService.acquire();
            context.startService(intent);
        }
    }

启动了SmsReceiverService::::

public int onStartCommand(Intent intent, int flags, int startId) {
        mResultCode = intent != null ? intent.getIntExtra("result", 0) : 0;

        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
        return Service.START_NOT_STICKY;
    }

public void handleMessage(Message msg) {
            int serviceId = msg.arg1;
            Intent intent = (Intent)msg.obj;
            if (intent != null) {
                String action = intent.getAction();

                int error = intent.getIntExtra("errorCode", 0);

                if (MESSAGE_SENT_ACTION.equals(intent.getAction())) {
                    handleSmsSent(intent, error);
                } else if (SMS_RECEIVED_ACTION.equals(action)) {
                    //==================接收短信息
                    handleSmsReceived(intent, error);
                } else if (WAP_PUSH_RECEIVED_ACTION.equals(action)) {
                    Log.i(TAG,"WAP_PUSH_RECEIVED_ACTION");
                    handleWapPushReceived(intent, error);
                } else if (ACTION_BOOT_COMPLETED.equals(action)) {
                    handleBootCompleted();
                } else if (TelephonyIntents.ACTION_SERVICE_STATE_CHANGED.equals(action)) {
                    handleServiceStateChanged(intent);
                } else if (ACTION_SEND_MESSAGE.endsWith(action)) {
                    //===================发送短信
                    handleSendMessage();
                }
            }
            // NOTE: We MUST not call stopSelf() directly, since we need to
            // make sure the wake lock acquired by AlertReceiver is released.
            SmsReceiver.finishStartingService(SmsReceiverService.this, serviceId);
        }
    }

private void handleSendMessage() {
        if (!mSending) {//如果没有发送,则准备发送队列中的第一条
            sendFirstQueuedMessage();
        }
    }

public synchronized void sendFirstQueuedMessage() {
        boolean success = true;
        // get all the queued messages from the database
        //从数据库中取得所有的信息队列
        final Uri uri = Uri.parse("content://sms/queued");
        ContentResolver resolver = getContentResolver();
        ////查询队列中的信息,包括上次没有发送出去存放在发送队列的信息 ,按用户发送日期的升序排列信息
        Cursor c = SqliteWrapper.query(this, resolver, uri,
                        SEND_PROJECTION, null, null, "date ASC");   // date ASC so we send out in
                                                                    // same order the user tried
                                                                    // to send messages.
        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 phoneId = c.getInt(SEND_COLUMN_PHONE_ID);
                    int msgId = c.getInt(SEND_COLUMN_ID);
                    Uri msgUri = ContentUris.withAppendedId(Sms.CONTENT_URI, msgId);

                  //cienet edit yuanman 2011-6-16:  Runtime check for dsds
                    SmsMessageSender sender;
                    if(TelephonyManager.getPhoneCount()>1){
                        sender = new SmsSingleRecipientSender(this, address,
                                msgText, threadId,
                                status == Sms.STATUS_PENDING, msgUri, phoneId);
                    } else {
                        sender = new SmsSingleRecipientSender(this, address,
                                msgText, threadId,
                                status == Sms.STATUS_PENDING, msgUri);
                    }
                    if (DEBUG || Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {
                        Log.v(TAG, "sendFirstQueuedMessage " + msgUri +
                                ", address: " + address +
                                ", threadId: " + threadId +
                                ", body: " + msgText +
                                ", phoneId:"+ phoneId);
                    }
                    try {
                        //进行单个信息发送
                        sender.sendMessage(SendingProgressTokenManager.NO_TOKEN);;
                        mSending = true;
                    } catch (MmsException e) {
                    } finally {
                c.close();
            }
        }
    }

public boolean sendMessage(long token) throws MmsException {
        Log.d("SmsSingleRecipientSender" , "sendMessage");
        if (mMessageText == null) {
            // Don't try to send an empty message, and destination should be just
            // one.
            throw new MmsException("Null message body or have multiple destinations.");
        }
        SmsManager smsManager = SmsManager.getDefault();
        ArrayList<String> messages = null;
        if ((MmsConfig.getEmailGateway() != null) &&//==============发送彩信需要进行的处理
                (Mms.isEmailAddress(mDest) || MessageUtils.isAlias(mDest))) {
            String msgText;
            msgText = mDest + " " + mMessageText;
            mDest = MmsConfig.getEmailGateway();
            messages = smsManager.divideMessage(msgText);
        } else {//=================发送普通短信息
            //把长信息拆分的合适大小的信息段
           messages = smsManager.divideMessage(mMessageText);
           // remove spaces from destination number (e.g. "801 555 1212" -> "8015551212")
           //把目的号码中的空格去掉
           mDest = mDest.replaceAll(" ", "");
        }
        //查看信息分成了多少个部分
        int messageCount = messages.size();
       

        //把信息放到指定的文件夹中
        boolean moved = Sms.moveMessageToFolder(mContext, mUri, Sms.MESSAGE_TYPE_OUTBOX, 0);
        if (!moved) {
            throw new MmsException("SmsMessageSender.sendMessage: couldn't move message " +
                    "to outbox: " + mUri);
        }

        //modify by dory.zheng for fdn begin
        //???????????????????????????????????
        ITelephony iTelePhony = ITelephony.
       Stub.asInterface(ServiceManager.getService(PhoneFactory.getServiceName(Context.TELEPHONY_SERVICE, mPhoneId)));
        String smscPhoneNum = "";
        try {
            smscPhoneNum = iTelePhony.getSmsc();
        } catch (RemoteException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
       
        switch(mPhoneId){
        case 0:
            boolean sim1_fdn_enabled = SystemProperties.getBoolean("gsm.sim1.fdn.enable", false);
            if(sim1_fdn_enabled && !queryFDN(sim1_fdnUri, mDest))
                throw new MmsException("FDN_CHECK_FAILURE");
            if(sim1_fdn_enabled && !queryFDN(sim1_fdnUri, smscPhoneNum))
                throw new MmsException("SMSC_FDN_CHECK_FAILURE");
            break;
        case 1:
            boolean sim2_fdn_enabled = SystemProperties.getBoolean("gsm.sim2.fdn.enable", false);
            if(sim2_fdn_enabled && !queryFDN(sim2_fdnUri, mDest))
                throw new MmsException("FDN_CHECK_FAILURE");
            if(sim2_fdn_enabled && !queryFDN(sim2_fdnUri, smscPhoneNum))
                throw new MmsException("SMSC_FDN_CHECK_FAILURE");
            break;
        }
        //modify by dory.zheng for fdn end       
        ArrayList<PendingIntent> deliveryIntents =  new ArrayList<PendingIntent>(messageCount);
        ArrayList<PendingIntent> sentIntents = new ArrayList<PendingIntent>(messageCount);
        for (int i = 0; i < messageCount; i++) {
            if (mRequestDeliveryReport) {//===========================如果需要发送报告时,进行如下处理
                // TODO: Fix: It should not be necessary to
                // specify the class in this intent.  Doing that
                // unnecessarily limits customizability.
                deliveryIntents.add(PendingIntent.getBroadcast(
                        mContext, 0,
                        new Intent(
                                MessageStatusReceiver.MESSAGE_STATUS_RECEIVED_ACTION,
                                mUri,
                                mContext,
                                MessageStatusReceiver.class),
                        0));
            }
            Intent intent  = new Intent(SmsReceiverService.MESSAGE_SENT_ACTION,
                    mUri,
                    mContext,
                    SmsReceiver.class);
            if (i == messageCount -1) {
                intent.putExtra(SmsReceiverService.EXTRA_MESSAGE_SENT_SEND_NEXT, true);
            }
            sentIntents.add(PendingIntent.getBroadcast(
                    mContext, i, intent, 0));
        }
        try {
          if(TelephonyManager.getPhoneCount()>1){
                smsManager.sendMultipartTextMessage(mDest, mServiceCenter, messages, sentIntents, deliveryIntents, mPhoneId);
            } else {
                smsManager.sendMultipartTextMessage(mDest, mServiceCenter, messages, sentIntents, deliveryIntents);
            }
            //cienet end yuanman.
        } catch (Exception ex) {
        }
        return false;
    }

public void sendMultipartTextMessage(
            String destinationAddress, String scAddress, ArrayList<String> parts,
            ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents, int phoneId) {
        if (TextUtils.isEmpty(destinationAddress)) {//收件人地址为空时会触发异常
            throw new IllegalArgumentException("Invalid destinationAddress");
        }
        if (parts == null || parts.size() < 1) {//parts是信息分割后分成的部分,为空时触发异常
            throw new IllegalArgumentException("Invalid message body");
        }

        if (parts.size() > 1) {//长短信的情况
            try {
                ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService(PhoneFactory.getServiceName("isms",phoneId)));
                if (iccISms != null) {
                    iccISms.sendMultipartText(destinationAddress, scAddress, parts,
                            sentIntents, deliveryIntents);
                }
            } catch (RemoteException ex) {
                // ignore it
            }
        } else {//这里是parts==1的情况,即短信不是长短信,没有分割
            PendingIntent sentIntent = null;
            PendingIntent deliveryIntent = null;
            if (sentIntents != null && sentIntents.size() > 0) {
                sentIntent = sentIntents.get(0);
            }
            if (deliveryIntents != null && deliveryIntents.size() > 0) {
                deliveryIntent = deliveryIntents.get(0);
            }
            sendTextMessage(destinationAddress, scAddress, parts.get(0),
                    sentIntent, deliveryIntent, phoneId);
        }
    }

public void sendTextMessage(
            String destinationAddress, String scAddress, String text,
            PendingIntent sentIntent, PendingIntent deliveryIntent, int phoneId) {
        if (TextUtils.isEmpty(destinationAddress)) {
            throw new IllegalArgumentException("Invalid destinationAddress");
        }

        if (TextUtils.isEmpty(text)) {
            throw new IllegalArgumentException("Invalid message body");
        }

        try {
            ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService(PhoneFactory.getServiceName("isms", phoneId)));
            if (iccISms != null) {
                iccISms.sendText(destinationAddress, scAddress, text, sentIntent, deliveryIntent);
            }
        } catch (RemoteException ex) {
            // ignore it
            Log.d(TAG,"sendTextMessage() exception",ex);
        }
    }
从这里跳到了类IccSmaInterfaceMangerProxy中进行处理
public void sendText(String destAddr, String scAddr,
            String text, PendingIntent sentIntent, PendingIntent deliveryIntent) {
        mIccSmsInterfaceManager.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent);
    }
一下不再赘述。。。

posted @ 2014-07-07 12:54  xiaoaidelala  阅读(988)  评论(0编辑  收藏  举报