• 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);
        }
    一下不再赘述。。。

  • 相关阅读:
    CURL POST提交json类型字符串数据和伪造IP和来源
    windows下nginx的配置
    常用JS兼容问题工具
    无限级分类--Array写法
    JS获取对象指定属性在样式中的信息
    解决IE和Firefox获取来源网址Referer的JS方法
    异步轮询函数
    响应式布局--特殊设备检测
    jQuery Validate校验
    [LeetCode#124]Binary Tree Maximum Path Sum
  • 原文地址:https://www.cnblogs.com/kevincode/p/3829462.html
Copyright © 2020-2023  润新知