Android短信发送流程之普通短信发送(原)
16lz
2022-08-04
我们先来看最简单的流程入手分析,即收件人只有一个,而且不是长短信的情况。
一、地址有效性检测
[java] view plain copy
- @ComposeMessageActivity.java
- public void onClick(View v) {
- if ((v == mSendButtonSms || v == mSendButtonMms) && isPreparedForSending()) {
- //确认发送
- confirmSendMessageIfNeeded();
- } else if ((v == mRecipientsPicker)) {
- launchMultiplePhonePicker();
- }
- }
[java] view plain copy
- private void confirmSendMessageIfNeeded() {
- if (!isRecipientsEditorVisible()) {
- //当前的收件人编辑框不可见,说明所发送的对象已经存在短信的会话,也说明当前的收件人地址是ok的
- sendMessage(true);
- return;
- }
- //判断是否为MMS
- 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)
- .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)
- .setTitle(R.string.cannot_send_message)
- .setMessage(R.string.cannot_send_message_reason)
- .setPositiveButton(R.string.yes, new CancelSendingListener())
- .show();
- }
- } else {
- //收件人地址都是有效的,发送
- ContactList contacts = mRecipientsEditor.constructContactsFromInput(false);
- mDebugRecipients = contacts.serialize();
- sendMessage(true);
- }
- }
[java] view plain copy
- private void sendMessage(boolean bCheckEcmMode) {
- if (bCheckEcmMode) {
- //判断当前是否为紧急呼叫模式
- String inEcm = SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE);
- 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) {
- Log.e(TAG, "Cannot find EmergencyCallbackModeExitDialog", e);
- }
- }
- }
- //判断当前是否有短信正在发送
- if (!mSendingMessage) {
- //重置收件人控件的监听器
- removeRecipientsListeners();
- //进入WorkingMessage处理流程
- mWorkingMessage.send(mDebugRecipients);
- mSentMessage = true;
- mSendingMessage = true;
- addRecipientsListeners();
- mScrollOnSend = true; // in the next onQueryComplete, scroll the list to the end.
- }
- // But bail out if we are supposed to exit after the message is sent.
- if (mSendDiscreetMode) {
- finish();
- }
- }
二、创建短彩信的发送线程
[java] view plain copy
- @WorkingMessage.java
- public void send(final String recipientsInUI) {
- long origThreadId = mConversation.getThreadId();
- removeSubjectIfEmpty(true /* notify */);
- prepareForSave(true /* notify */);
- //拿到当前的会话
- final Conversation conv = mConversation;
- String msgTxt = mText.toString();
- if (requiresMms() || addressContainsEmailToMms(conv, msgTxt)) {
- //彩信发送
- if (MmsConfig.getUaProfUrl() == null) {
- String err = "WorkingMessage.send MMS sending failure. mms_config.xml is " +
- "missing uaProfUrl setting. uaProfUrl is required for MMS service, " +
- "but can be absent for SMS.";
- RuntimeException ex = new NullPointerException(err);
- Log.e(TAG, err, ex);
- // now, let's just crash.
- throw ex;
- }
- final Uri mmsUri = mMessageUri;
- final PduPersister persister = PduPersister.getPduPersister(mActivity);
- final SlideshowModel slideshow = mSlideshow;
- final CharSequence subject = mSubject;
- final boolean textOnly = mAttachmentType == TEXT;
- //彩信发送线程
- new Thread(new Runnable() {
- @Override
- public void run() {
- final SendReq sendReq = makeSendReq(conv, subject);
- slideshow.prepareForSend();
- sendMmsWorker(conv, mmsUri, persister, slideshow, sendReq, textOnly);
- updateSendStats(conv);
- }
- }, "WorkingMessage.send MMS").start();
- } else {
- //短信发送流程
- final String msgText = mText.toString();
- new Thread(new Runnable() {
- @Override
- public void run() {
- preSendSmsWorker(conv, msgText, recipientsInUI);
- updateSendStats(conv);
- }
- }, "WorkingMessage.send SMS").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;
- }
[java] view plain copy
- private void preSendSmsWorker(Conversation conv, String msgText, String recipientsInUI) {
- UserHappinessSignals.userAcceptedImeText(mActivity);
- //UI刷新
- mStatusListener.onPreMessageSent();
- //获取初始的线程ID
- long origThreadId = conv.getThreadId();
- //获取分配的线程ID
- long threadId = conv.ensureThreadId();
- String semiSepRecipients = conv.getRecipients().serialize();
- // recipientsInUI can be empty when the user types in a number and hits send
- if (LogTag.SEVERE_WARNING && ((origThreadId != 0 && origThreadId != threadId) || (!semiSepRecipients.equals(recipientsInUI) && !TextUtils.isEmpty(recipientsInUI)))) {
- }else {
- //发送短信
- sendSmsWorker(msgText, semiSepRecipients, threadId);
- //删除草稿
- deleteDraftSmsMessage(threadId);
- }
- }
在上面的preSendSmsWorker中进行了四个处理:
1、更新UI(更新编辑框等控件);
2、获取当前发送的ThreadID;
3、发送短信;
4、删除草稿;
接下来我们继续来看发送的过程:[java] view plain copy
- private void sendSmsWorker(String msgText, String semiSepRecipients, long threadId) {
- //获取当前发送的收件人地址
- String[] dests = TextUtils.split(semiSepRecipients, ";");
- //获取MessageSender对象,传递进去4个参数分别为:收件人、信息文本、当前的threadId、SimID。
- MessageSender sender = new SmsMessageSender(mActivity, dests, msgText, threadId);
- try {
- //通过MessageSender发送出去
- 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);
- }
- //更新UI
- mStatusListener.onMessageSent();
- MmsWidgetProvider.notifyDatasetChanged(mActivity);
- }
经过上面WorkingMessage的sendSmsWorker过程,创建了MessageSender对象,并通过该对象的sendMessage()方法将信息发送出去,并在发送之后再次更新UI界面(正在发送中)。
三、通过SmsMessageSender拆分多个收件人
[java] view plain copy
- public boolean sendMessage(long token) throws MmsException {};
- private boolean queueMessage(long token) throws MmsException {};
- private String getOutgoingServiceCenter(long threadId) {};
下面来看其具体实现过程。
[java] view plain copy
- @SmsMessageSender.java
- public boolean sendMessage(long token) throws MmsException {
- return queueMessage(token);
- }
- private boolean queueMessage(long token) throws MmsException {
- if ((mMessageText == null) || (mNumberOfDests == 0)) {
- //空信息不能发送
- 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);
- //根据当前短信的收件人数目,遍历当前的发送队列
- for (int i = 0; i < mNumberOfDests; i++) {
- try {
- //将当前要发送的短消息放入发送队列中
- Sms.addMessageToUri(mContext.getContentResolver(),
- Uri.parse("content://sms/queued"), mDests[i],
- mMessageText, null, mTimestamp,
- true /* read */,
- requestDeliveryReport,
- mThreadId);
- } catch (SQLiteException e) {
- if (LogTag.DEBUG_SEND) {
- Log.e(TAG, "queueMessage SQLiteException", e);
- }
- SqliteWrapper.checkSQLiteException(mContext, e);
- }
- }
- //通知SmsReceiverService发送短信
- mContext.sendBroadcast(new Intent(SmsReceiverService.ACTION_SEND_MESSAGE,
- null,
- mContext,
- SmsReceiver.class));
- return false;
- }
[java] view plain copy
- @SmsReceiver.java
- public void onReceive(Context context, Intent intent) {
- onReceiveWithPrivilege(context, intent, false);
- }
- protected void onReceiveWithPrivilege(Context context, Intent intent, boolean privileged) {
- if (!privileged && intent.getAction().equals(Intents.SMS_DELIVER_ACTION)) {
- return;
- }
- //将请求转交给SmsReceiverService来处理
- intent.setClass(context, SmsReceiverService.class);
- intent.putExtra("result", getResultCode());
- beginStartingService(context, intent);
- }
下面来看SmsReceiverService对于发送短消息的处理过程。
这个Service被创建时,会创建一个子线程(HandlerThread)以及该线程的Handler对象(ServiceHandler):
[java] view plain copy
- @SmsReceiverService.java
- public void onCreate() {
- //创建子线程处理各种消息
- HandlerThread thread = new HandlerThread(TAG, Process.THREAD_PRIORITY_BACKGROUND);
- thread.start();
- mServiceLooper = thread.getLooper();
- mServiceHandler = new ServiceHandler(mServiceLooper);
- }
[java] view plain copy
- public int onStartCommand(Intent intent, int flags, int startId) {
- mResultCode = intent != null ? intent.getIntExtra("result", 0) : 0;
- //通知Handler处理当前的请求
- Message msg = mServiceHandler.obtainMessage();
- msg.arg1 = startId;
- msg.obj = intent;
- mServiceHandler.sendMessage(msg);
- return Service.START_NOT_STICKY;
- }
- private final class ServiceHandler extends Handler {
- public ServiceHandler(Looper looper) {
- super(looper);
- }
- @Override
- public void handleMessage(Message msg) {
- int serviceId = msg.arg1;
- Intent intent = (Intent)msg.obj;
- if (intent != null && MmsConfig.isSmsEnabled(getApplicationContext())) {
- String action = intent.getAction();
- int error = intent.getIntExtra("errorCode", 0);
- if (MESSAGE_SENT_ACTION.equals(intent.getAction())) {
- handleSmsSent(intent, error);
- } else if (SMS_DELIVER_ACTION.equals(action)) {
- handleSmsReceived(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();
- } else if (ACTION_SEND_INACTIVE_MESSAGE.equals(action)) {
- handleSendInactiveMessage();
- }
- }
- SmsReceiver.finishStartingService(SmsReceiverService.this, serviceId);
- }
- }
- private void handleSendMessage() {
- if (!mSending) {
- //当前没有其他任务时就触发发送的操作
- sendFirstQueuedMessage();
- }
- }
- public synchronized void sendFirstQueuedMessage() {
- boolean success = true;
- final Uri uri = Uri.parse("content://sms/queued");
- ContentResolver resolver = getContentResolver();
- //从队列中拿到要发送的短信
- Cursor c = SqliteWrapper.query(this, resolver, uri, SEND_PROJECTION, null, 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对象
- SmsMessageSender sender = new SmsSingleRecipientSender(this,
- address, msgText, threadId, status == Sms.STATUS_PENDING,
- msgUri);
- try {
- //发送
- sender.sendMessage(SendingProgressTokenManager.NO_TOKEN);;
- mSending = true;
- } catch (MmsException e) {
- mSending = false;
- messageFailedToSend(msgUri, SmsManager.RESULT_ERROR_GENERIC_FAILURE);
- success = false;
- sendBroadcast(new Intent(SmsReceiverService.ACTION_SEND_MESSAGE,
- null,
- this,
- SmsReceiver.class));
- }
- }
- } finally {
- c.close();
- }
- }
- if (success) {
- unRegisterForServiceStateChanges();
- }
- }
我们看到,经过SmsReceiverService中Handler的处理,将数据库中的当前要发送的短信队列取出来,然后取出队列中第一个短消息任务,通过SmsSingleRecipientSender的sendMessage()方法发送出去。至此SmsReceiverService的流程就走完了,他的作用主要就是拿到队列中的第一条短消息,构建SmsSingleRecipientSender对象并发送出去。
四、通过SmsSingleRecipientSender拆分长短信
[java] view plain copy
- public boolean sendMessage(long token) throws MmsException {};
- @SmsSingleRecipientSender.java
- public boolean sendMessage(long token) throws MmsException {
- if (mMessageText == null) {
- throw new MmsException("Null message body or have multiple destinations.");
- }
- SmsManager smsManager = SmsManager.getDefault();
- ArrayList
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);
- mDest = PhoneNumberUtils.stripSeparators(mDest);
- mDest = Conversation.verifySingleRecipient(mContext, mThreadId, mDest);
- }
- int messageCount = messages.size();
- if (messageCount == 0) {
- throw new MmsException("SmsMessageSender.sendMessage: divideMessage returned " + "empty messages. Original message is \"" + mMessageText + "\"");
- }
- 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);
- }
- ArrayList
deliveryIntents = new ArrayList (messageCount); - ArrayList
sentIntents = new ArrayList (messageCount); - for (int i = 0; i < messageCount; i++) {
- if (mRequestDeliveryReport && (i == (messageCount - 1))) {
- //所有短信被发送完毕后,在最后一条短信后面添加送达报告的Intent
- deliveryIntents.add(PendingIntent.getBroadcast(
- mContext, 0,
- new Intent(
- MessageStatusReceiver.MESSAGE_STATUS_RECEIVED_ACTION,
- mUri,
- mContext,
- MessageStatusReceiver.class),
- 0));
- } else {
- deliveryIntents.add(null);
- }
- //对于拆分后的短消息,需要在每条信息发送完毕后发送该Intent,从而接着发送剩下的拆分短信
- Intent intent = new Intent(SmsReceiverService.MESSAGE_SENT_ACTION,
- mUri,
- mContext,
- SmsReceiver.class);
- int requestCode = 0;
- if (i == messageCount -1) {
- //收到该附加数据说明当前的拆分短信已经发送完毕
- requestCode = 1;
- intent.putExtra(SmsReceiverService.EXTRA_MESSAGE_SENT_SEND_NEXT, true);
- }
- sentIntents.add(PendingIntent.getBroadcast(mContext, requestCode, intent, 0));
- }
- try {
- //发送
- smsManager.sendMultipartTextMessage(mDest, mServiceCenter, messages, sentIntents, deliveryIntents);
- } catch (Exception ex) {
- throw new MmsException("SmsMessageSender.sendMessage: caught " + ex + " from SmsManager.sendTextMessage()");
- }
- return false;
- }
MESSAGE_STATUS_RECEIVED_ACTION:当所有长短信(或短消息)发送完毕后,发送该Intent。
MESSAGE_SENT_ACTION:分割后的短消息,每发送一条,都会发送该Intent, 当最后一条发送完毕后,将会在该Intent中附加EXTRA_MESSAGE_SENT_SEND_NEXT=true的数据。
具体细节在发送完毕后再分析。
接下来看SmsManager,这里的SmsManager是 单例模型,通过其自己的getDefault()或者getSmsManagerForSubscriber()方法就可以得到该对象。 [java] view plain copy
- @SmsManager.java
- public void sendMultipartTextMessage( String destinationAddress, String scAddress, ArrayList
parts, ArrayList sentIntents, ArrayList deliveryIntents) { - if (TextUtils.isEmpty(destinationAddress)) {
- throw new IllegalArgumentException("Invalid destinationAddress");
- }
- if (parts == null || parts.size() < 1) {
- throw new IllegalArgumentException("Invalid message body");
- }
- if (parts.size() > 1) {
- //长短信发送
- try {
- ISms iccISms = getISmsServiceOrThrow();
- iccISms.sendMultipartText(ActivityThread.currentPackageName(),
- destinationAddress, scAddress, parts,
- sentIntents, deliveryIntents);
- } catch (RemoteException ex) {
- }
- } else {
- //普通短信发送
- 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);
- }
- }
- public void sendTextMessage( String destinationAddress, String scAddress, String text, PendingIntent sentIntent, PendingIntent deliveryIntent) {
- if (TextUtils.isEmpty(destinationAddress)) {
- throw new IllegalArgumentException("Invalid destinationAddress");
- }
- if (TextUtils.isEmpty(text)) {
- throw new IllegalArgumentException("Invalid message body");
- }
- try {
- //继续
- ISms iccISms = getISmsServiceOrThrow();
- iccISms.sendText(ActivityThread.currentPackageName(), destinationAddress, scAddress, text, sentIntent, deliveryIntent);
- } catch (RemoteException ex) {
- }
- }
到这里,SmsMessage通过调用iccISms对象的sendText()方法将短信继续传递,而SmsMessage的流程就此结束。
五、发送单条短信
[java] view plain copy
- private static ISms getISmsService() {
- return ISms.Stub.asInterface(ServiceManager.getService("isms"));
- }
[java] view plain copy
- @UiccSmsController.java
- public void sendText(String callingPackage, String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent) {
- sendTextForSubscriber(getPreferredSmsSubscription(), callingPackage, destAddr, scAddr, text, sentIntent, deliveryIntent);
- }
- public void sendTextForSubscriber(long subId, String callingPackage, String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent) {
- IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId);
- if (iccSmsIntMgr != null) {
- //通过IccSmsInterfaceManager发送短信
- iccSmsIntMgr.sendText(callingPackage, destAddr, scAddr, text, sentIntent, deliveryIntent);
- } else {
- }
- }
IccSmsInterfaceManager这个类没有父类,他在创建PhoneProxy的时候进行初始化,其 作用是把请求发送给相应的处理者。比如对于sendText()将会转交给ImsSMSDispatcher来实现。 [java] view plain copy
- @IccSmsInterfaceManager.java
- public void sendText(String callingPackage, String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent) {
- //是否声明了发短信的权限
- mPhone.getContext().enforceCallingPermission( Manifest.permission.SEND_SMS, "Sending SMS message");
- //该操作是否被用户允许
- if (mAppOps.noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(), callingPackage) != AppOpsManager.MODE_ALLOWED) {
- return;
- }
- //调用ImsSMSDispatcher发送
- destAddr = filterDestAddress(destAddr);
- mDispatcher.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent, null, callingPackage);
- }
SMSDispatcher总共派生出三个子类:CdmaSMSDispatcher、GsmSMSDispatcher、ImsSMSDispatcher,在IccSmsInterfaceManager创建时只创建ImsSMSDispatcher,而在ImsSMSDispatcher创建过程中会对创建其他两种制式的SMSDispatcher,IccSmsInterfaceManager把请求发送给ImsSMSDispatcher后,由ImsSMSDispatcher根据当前网络状态选择使用CdmaSMSDispatcher还是GsmSMSDispatcher。 [java] view plain copy
- @ImsSMSDispatcher.java
- protected void sendText(String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, Uri messageUri, String callingPkg) {
- //根据当前网络类型发送,我们只分析GSM
- if (isCdmaMo()) {
- mCdmaDispatcher.sendText(destAddr, scAddr,
- text, sentIntent, deliveryIntent, messageUri, callingPkg);
- } else {
- mGsmDispatcher.sendText(destAddr, scAddr,
- text, sentIntent, deliveryIntent, messageUri, callingPkg);
- }
- }
这是Framework层与RILJ最接近的对象,他将请求发送给RILJ。 [java] view plain copy
- @GsmSMSDispatcher.java
- protected void sendText(String destAddr, String scAddr, String text, PendingIntent sentIntent, PendingIntent deliveryIntent, Uri messageUri, String callingPkg) {
- //对短信内容进行编码
- SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu( scAddr, destAddr, text, (deliveryIntent != null));
- if (pdu != null) {
- if (messageUri == null) {
- if (SmsApplication.shouldWriteMessageForPackage(callingPkg, mContext)) {
- //写入发件箱
- messageUri = writeOutboxMessage(
- getSubId(),
- destAddr,
- text,
- deliveryIntent != null,
- callingPkg);
- }
- } else {
- //移到发件箱
- moveToOutbox(getSubId(), messageUri, callingPkg);
- }
- HashMap map = getSmsTrackerMap(destAddr, scAddr, text, pdu);
- //发送
- SmsTracker tracker = getSmsTracker(map, sentIntent, deliveryIntent, getFormat(), messageUri, false);
- sendRawPdu(tracker);
- } else {
- }
- }
- @SMSDispatcher.java
- protected void sendRawPdu(SmsTracker tracker) {
- HashMap map = tracker.mData;
- byte pdu[] = (byte[]) map.get("pdu");
- if (mSmsSendDisabled) {
- tracker.onFailed(mContext, RESULT_ERROR_NO_SERVICE, 0/*errorCode*/);
- return;
- }
- if (pdu == null) {
- tracker.onFailed(mContext, RESULT_ERROR_NULL_PDU, 0/*errorCode*/);
- return;
- }
- PackageManager pm = mContext.getPackageManager();
- String[] packageNames = pm.getPackagesForUid(Binder.getCallingUid());
- if (packageNames == null || packageNames.length == 0) {
- // Refuse to send SMS if we can't get the calling package name.
- tracker.onFailed(mContext, RESULT_ERROR_GENERIC_FAILURE, 0/*errorCode*/);
- return;
- }
- // Get package info via packagemanager
- PackageInfo appInfo;
- try {
- // XXX this is lossy- apps can share a UID
- appInfo = pm.getPackageInfo(packageNames[0], PackageManager.GET_SIGNATURES);
- } catch (PackageManager.NameNotFoundException e) {
- Rlog.e(TAG, "Can't get calling app package info: refusing to send SMS");
- tracker.onFailed(mContext, RESULT_ERROR_GENERIC_FAILURE, 0/*errorCode*/);
- return;
- }
- // checkDestination() returns true if the destination is not a premium short code or the
- // sending app is approved to send to short codes. Otherwise, a message is sent to our
- // handler with the SmsTracker to request user confirmation before sending.
- if (checkDestination(tracker)) {
- // check for excessive outgoing SMS usage by this app
- if (!mUsageMonitor.check(appInfo.packageName, SINGLE_PART_SMS)) {
- sendMessage(obtainMessage(EVENT_SEND_LIMIT_REACHED_CONFIRMATION, tracker));
- return;
- }
- //发送
- sendSms(tracker);
- }
- }
- @GsmSMSDispatcher.java
- protected void sendSms(SmsTracker tracker) {
- HashMap
map = tracker.mData; - byte pdu[] = (byte[]) map.get("pdu");
- if (tracker.mRetryCount > 0) {
- // per TS 23.040 Section 9.2.3.6: If TP-MTI SMS-SUBMIT (0x01) type
- // TP-RD (bit 2) is 1 for retry
- // and TP-MR is set to previously failed sms TP-MR
- if (((0x01 & pdu[0]) == 0x01)) {
- pdu[0] |= 0x04; // TP-RD
- pdu[1] = (byte) tracker.mMessageRef; // TP-MR
- }
- }
- // Send SMS via the carrier app.
- BroadcastReceiver resultReceiver = new SMSDispatcherReceiver(tracker);
- Intent intent = new Intent(Intents.SMS_SEND_ACTION);
- String carrierPackage = getCarrierAppPackageName(intent);
- if (carrierPackage != null) {
- intent.setPackage(carrierPackage);
- intent.putExtra("pdu", pdu);
- intent.putExtra("smsc", (byte[]) map.get("smsc"));
- intent.putExtra("format", getFormat());
- if (tracker.mSmsHeader != null && tracker.mSmsHeader.concatRef != null) {
- SmsHeader.ConcatRef concatRef = tracker.mSmsHeader.concatRef;
- intent.putExtra("concat.refNumber", concatRef.refNumber);
- intent.putExtra("concat.seqNumber", concatRef.seqNumber);
- intent.putExtra("concat.msgCount", concatRef.msgCount);
- }
- intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT);
- Rlog.d(TAG, "Sending SMS by carrier app.");
- mContext.sendOrderedBroadcast(intent, android.Manifest.permission.RECEIVE_SMS,
- AppOpsManager.OP_RECEIVE_SMS, resultReceiver,
- null, Activity.RESULT_CANCELED, null, null);
- } else {
- //发送
- sendSmsByPstn(tracker);
- }
- }
- protected void sendSmsByPstn(SmsTracker tracker) {
- int ss = mPhone.getServiceState().getState();
- if (!isIms() && ss != ServiceState.STATE_IN_SERVICE) {
- tracker.onFailed(mContext, getNotInServiceError(ss), 0/*errorCode*/);
- return;
- }
- //拿到SmsTracker中保存的信息
- HashMap
map = tracker.mData; - byte smsc[] = (byte[]) map.get("smsc");
- byte[] pdu = (byte[]) map.get("pdu");
- Message reply = obtainMessage(EVENT_SEND_SMS_COMPLETE, tracker);
- if (0 == tracker.mImsRetry && !isIms()) {
- if (tracker.mRetryCount > 0) {
- if (((0x01 & pdu[0]) == 0x01)) {
- pdu[0] |= 0x04; // TP-RD
- pdu[1] = (byte) tracker.mMessageRef; // TP-MR
- }
- }
- if (tracker.mRetryCount == 0 && tracker.mExpectMore) {
- //调用RILJ发送短信
- mCi.sendSMSExpectMore(IccUtils.bytesToHexString(smsc),
- IccUtils.bytesToHexString(pdu), reply);
- } else {
- mCi.sendSMS(IccUtils.bytesToHexString(smsc),
- IccUtils.bytesToHexString(pdu), reply);
- }
- } else {
- //通过IMS发送短信
- mCi.sendImsGsmSms(IccUtils.bytesToHexString(smsc),
- IccUtils.bytesToHexString(pdu), tracker.mImsRetry,
- tracker.mMessageRef, reply);
- // increment it here, so in case of SMS_FAIL_RETRY over IMS
- // next retry will be sent using IMS request again.
- tracker.mImsRetry++;
- }
- }
以上就是普通单收件人,短信的发送流程。
整个过程的流程图如下:
下一节来介绍长短信的发送流程。
Source: http://blog.csdn.net/u010961631/article/details/50272705
更多相关文章
- 读取android手机流量信息
- Android(安卓)bluetooth介绍(四): a2dp connect流程分析
- android用户界面-组件Widget-地图视图MapView
- android打电话发短信
- Android(安卓)开发中的倒计时
- [APP] Android(安卓)开发笔记 006-使用短信验证SDK进行短信验证
- android studio升级方法
- android adb工具
- Android学习笔记_79_ Android(安卓)使用 搜索框