How MMS Message sending is implemented
1. IntroductionYou may be very clear about how to send a single text message, but you may be confused about how to send a single text message? This chapter focuses on the implementation of the MMS Short Message group function. Note that if you are not clear about the text message sending process, you can refer to the text message sending and receiving process I mentioned earlier.
2. Summary
2.1 class diagram
2.2. Time Sequence DiagramPlease forgive me because the timing diagram is too large and unclear;
3. Detailed AnalysisThe time sequence diagram is too large, so it is not very clear. Here we will parse the time sequence diagram, most of which are the process of sending text messages. So here we will focus on the differences between Group Sending and single text messages;
3.1 text messages are sent to the database to be sent tableFirst of all, let's talk about mmsms here. the SMS table in the DB database, which stores the text message content, as shown in: This indicates that the text message content is saved, you can view the details of the table after you come down. Here we will talk about the type field. This field is very important. Let's first look at the type classification:
public static final int MESSAGE_TYPE_ALL = 0; public static final int MESSAGE_TYPE_INBOX = 1; public static final int MESSAGE_TYPE_SENT = 2; public static final int MESSAGE_TYPE_DRAFT = 3; public static final int MESSAGE_TYPE_OUTBOX = 4; public static final int MESSAGE_TYPE_FAILED = 5; // for failed outgoing messages public static final int MESSAGE_TYPE_QUEUED = 6; // for messages to send later public static final int MESSAGE_TYPE_INBOX_SUB1 = 7; public static final int MESSAGE_TYPE_INBOX_SUB2 = 8;
You can see that you have no idea. Please refer to step 3 of the timing diagram and save the text message to the Quen queue. See the following code:
private boolean queueMessage(long token) throws MmsException { if ((mMessageText == null) || (mNumberOfDests == 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); for (int i = 0; i < mNumberOfDests; i++) { try { log("updating Database with sub = " + mSubscription); Sms.addMessageToUri(mContext.getContentResolver(), Uri.parse("content://sms/queued"), mDests[i], mMessageText, null, mTimestamp, true /* read */, requestDeliveryReport, mThreadId, mSubscription); } catch (SQLiteException e) { SqliteWrapper.checkSQLiteException(mContext, e); } } // Notify the SmsReceiverService to send the message out Intent intent = new Intent(SmsReceiverService.ACTION_SEND_MESSAGE, null, mContext, SmsReceiver.class);intent.putExtra(SUBSCRIPTION, mSubscription); mContext.sendBroadcast(intent); return false; }
In the for loop, add the content of the corresponding text message to content: // SMS/queued. This may be confusing, in order not to confuse everyone, the following describes the insert () method of smsprovider,
Before inserting data into the database, the insert method parses the URI content: // SMS/queued. After parsing, it sets the value of the type field based on the URI type, and then inserts the data into the database. If the value of the type field of the queued Type above is 6.
Note:The value of this field is very important and will be repaired multiple times later.
3.2 retrieve the first text message and send itIn step 4-8 of the time sequence diagram, we can see that there is no actual content, but the task sent is passed to the smsreceiverservice. This service is very important. When you see it, you don't think it is important, you know the importance of the entire process. It performs asynchronous processing and transfers the work to servicehandler. Steps 9 and 12 are sent here. Steps 9 and 10 are too simple and there is no need for much analysis. Please refer to Step 11 to call the sendfirstqueuedmessage () method. The core code of this method is as follows:
String where = Sms.SUB_ID + "=" + subscription; Cursor c = SqliteWrapper.query(this, resolver, uri, SEND_PROJECTION, where, 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 msgId = c.getInt(SEND_COLUMN_ID); Uri msgUri = ContentUris.withAppendedId(Sms.CONTENT_URI, msgId);
There is not much complicated logic in this code. We can see that each piece of data in the first article is retrieved;
Then call the sendmessage method of smssinglerecipentsender to send the message.
sender = new SmsSingleRecipientSender(this, address, msgText, threadId, status == Sms.STATUS_PENDING, msgUri, subscription); sender.sendMessage(SendingProgressTokenManager.NO_TOKEN);;
About
public boolean sendMessage(long token) throws MmsException { 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(); if (messageCount == 0) { // Don't try to send an empty message. 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<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); int requestCode = 0; if (i == messageCount -1) { // Changing the requestCode so that a different pending intent // is created for the last fragment with // EXTRA_MESSAGE_SENT_SEND_NEXT set to true. requestCode = 1; intent.putExtra(SmsReceiverService.EXTRA_MESSAGE_SENT_SEND_NEXT, true); intent.putExtra(SUBSCRIPTION, mSubscription); } sentIntents.add(PendingIntent.getBroadcast(mContext, requestCode, intent, 0)); } smsManager.sendMultipartTextMessage(mDest, mServiceCenter, messages, sentIntents, deliveryIntents, mSubscription); return false; }
This method will do four things:
1. Splitting of long messages;
2. Add sentintent and delieveryintent;Note: sentintent refers to an intent that will be executed after the text message is sent. Some students may not understand it here, simply put, an intent delieveryintent that will be called back after a text message is sent: the intent of the Transfer Report
3. Save the text message to the sender;It must be clear that this is actually an update of the type field in the SMS table. 6 will be changed to 4, which indicates the sender, the sending text message, and 6 will indicate the text message to be sent.
4. Call the sendmultiparttextmessage method of the smsmanager API in the middle layer to send the text message.The framework is processed by rild, And the rild is parsed and sent by the AT command. Therefore, there is no need to analyze this issue.
3.3 send an unsent text message after sending the messageAfter sending a text message, you must be confused. You can find that the first text message is sent in the list to be sent. How can you send other text messages? Before analysis, let's take a look at it. When we request rild to send a text message, rild will give us feedback. This is mentioned in the previous section about sending a single text message, the reported event is ril_request_send_sms, which is then called back to the handmessage method of the smsdispatcher class. As for the introduction of this handler, the intermediate layer of text message sending has been described in detail. If you do not know it, you can review it. In the handmessage method of smsdipatcher, there is a special processing for the sent information, handlesendcomplete method. Here we will mention the sentintent mentioned above. Here sentintent will send COM. android. MMS. transaction. message_sent broadcasts messages to the application layer. Remember that there is a variable value of send_next_msg_extra. the application layer uses this variable to determine whether to send the next message;
Intent sendNext = new Intent(); sendNext.putExtra(SEND_NEXT_MSG_EXTRA, true); sentIntent.send(mContext, Activity.RESULT_OK, sendNext);
You can see the sentintent declaration at the application layer:
Intent intent = new Intent(SmsReceiverService.MESSAGE_SENT_ACTION, mUri, mContext, SmsReceiver.class); int requestCode = 0; if (i == messageCount -1) { // Changing the requestCode so that a different pending intent // is created for the last fragment with // EXTRA_MESSAGE_SENT_SEND_NEXT set to true. requestCode = 1; intent.putExtra(SmsReceiverService.EXTRA_MESSAGE_SENT_SEND_NEXT, true); intent.putExtra(SUBSCRIPTION, mSubscription); } sentIntents.add(PendingIntent.getBroadcast(mContext, requestCode, intent, 0))
In this case, the receiver that registers com. Android. mms. transaction. message_sent in MMS has only smsreceiver
It does not take any processing and then throws it to smsreceiverservice. "This is for you, I am using Soy Sauce." smsreceiverservice should be familiar to everyone, as mentioned above, the importance of sending and receiving cannot escape its control, and it plays a secondary role. It is a service. After the service is started, it sends a message to servicehandler for asynchronous processing. Handler performs sent Processing Based on the intent action. The handlesmssent method is called here. The following is the core implementation:
boolean sendNextMsg = intent.getBooleanExtra(EXTRA_MESSAGE_SENT_SEND_NEXT, false); if (mResultCode == Activity.RESULT_OK) { if (!Sms.moveMessageToFolder(this, uri, Sms.MESSAGE_TYPE_SENT, error)) { Log.e(TAG, "handleSmsSent: failed to move message " + uri + " to sent folder"); } if (sendNextMsg) { if (TelephonyManager.isMultiSimEnabled()) { sendFirstQueuedMessage(intent.getIntExtra(SUBSCRIPTION , 0)); } else { sendFirstQueuedMessage(); } }
I want to see this, you will surely suddenly realize it. First, you will get the value mentioned above in sendnextmsg. Here we will send the next message based on this value, the method to call is still the sendfirstqueuedmessage method mentioned earlier. This method will retrieve whether there are any text messages to be sent in the current database. If there are any messages to continue sending the first one, if no messages are directly returned. Note that there is an SMS. movemessagetofolder (this, Uri, SMS. message_type_sent, error) is still the type field in the updated SMS table. The value is set to 2, indicating that the message has been sent successfully, at this time, the interface will change the sending status to the sent status. The implementation of the interface is to listen to the database. Once the database changes, the interface will be updated. I will not describe it here, it is mentioned in Receiving text messages.
4. SummaryIn fact, there is no difference between sending a group of text messages and sending a text message. After the previous text message is sent, the second text message is sent, I am worried that the process for sending a single text message is not very clear. I have made some simple additions here, hoping to help you understand how to send the text message.