Android系统应用Mms之Sms短信发送流程(Mms应用部分)二

1. 新建一条短信, 在发送短信之前, 首先创建的是一个会话Conversation, 
以后所有与该接收人(一个或多个接收人)的消息交互, 都在该会话Conversation中.
ComposeMessageActivity:
private void initActivityState(Bundle bundle) {
    ...
    mConversation = Conversation.get(this, ContactList.getByNumbers(recipients, false /* don't block */, true /* replace number */), false);
    ...
}
1.1. 在创建会话的过程中会初始化一些参数, 如ThreadId
Conversation:
public static Conversation get(Context context, ContactList recipients, boolean allowQuery) {
    ...
    // 重点: 创建获取ThreadId
    long threadId = getOrCreateThreadId(context, recipients);
    // 创建会话
    conv = new Conversation(context, threadId, allowQuery);
    ...
    
}
1.2. ThreadId贯穿着整个信息的发送流程, 因此我们需要查看ThreadId的创建流程
public static long getOrCreateThreadId(Context context, ContactList list) {
    ...
    long retVal = 0;
    try {
        retVal = Threads.getOrCreateThreadId(context, recipients, names);
    } catch (IllegalArgumentException e) {
        Log.e(TAG, " Failed to get or create threadId, exception : " + e);
    }
    ...
}
1.3. 继续创建ThreadId
Telephony$Threads:
public static long getOrCreateThreadId(Context context, Set<String> recipients, Set<String> recipientNames) {
    // 重点: THREAD_ID_CONTENT_URI = "content://mms-sms/threadID"
    Uri.Builder uriBuilder = THREAD_ID_CONTENT_URI.buildUpon();
    ...
    // 此处可以看见并没有对ThreadId的创建, 只有一个查询的过程
    // 因此我们需要通过THREAD_ID_CONTENT_URI找到对应的ContentProvider, 看看查询的实现逻辑
    Cursor cursor = SqliteWrapper.query(context, context.getContentResolver(),
            uri, ID_PROJECTION, null, null, null);
    if (cursor != null) {
        try {
            if (cursor.moveToFirst()) {
                return cursor.getLong(0);
            } else {
                Rlog.e(TAG, "getOrCreateThreadId returned no rows!");
            }
        } finally {
            cursor.close();
        }
    }
}
1.4. 由于上面的步骤只看见ThreadId的查询过程, 并没有看见ThreadId的创建,
因此我们需要到短信的内容提供者MmsSmsProvider中看看ThreadId的具体查询过程
MmsSmsProvider:
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
    ...
    switch(URI_MATCHER.match(uri)) {
    ...
    case URI_THREAD_ID: // 此处即为ThreadId的查询
        List<String> recipients = uri.getQueryParameters("recipient");
        List<String> recipientNames = uri.getQueryParameters("recipientNames");
        // 获取ThreadId
        cursor = getThreadId(recipients,recipientNames);
        break;
    ...
    }
}

1.5. 查看查询过程中ThreadId的具体查询过程
MmsSmsProvider:
private synchronized Cursor getThreadId(List<String> recipients,List<String> recipientNames) {
    ...
    // 重点: 根据接收人获取地址id
    // 每个接收人的地址id, 在短信模块中有且只有一个addressId
    // 该addressId通过接收人的号码生成, 无论联系人的姓名怎样变化, 该id都不会发生改变
    Set<Long> addressIds = getAddressIds(recipients);
    ...
}

1.5.1. 查看联系人的addressId的查询和创建过程
MmsSmsProvider:
private Set<Long> getAddressIds(List<String> addresses) {
    ...
    for (String address : addresses) {
        if (!address.equals(PduHeaders.FROM_INSERT_ADDRESS_TOKEN_STR)) {
            // 获取联系人的唯一addressId
            long id = getSingleAddressId(address);
            if (id != -1L) {
                result.add(id);
            } else {
                Log.e(LOG_TAG, "getAddressIds: address ID not found for " + address);
            }
        }
    }
    ...
}

1.5.2. 继续查看联系人addressId的查询和创建过程
MmsSmsProvider:
private long getSingleAddressId(String address) {
    ...
    // 前面是一些联系人的类型判断和查询参数的拼接
    // 注意: sql中的PHONE_NUMBERS_EQUAL函数是android独有的
    // 查询接收人的addressId
    cursor = db.query("canonical_addresses", ID_PROJECTION, selection, selectionArgs, null, null, null);
    if (cursor.getCount() == 0) { // 如果之前没有改接收人的addressId
        ContentValues contentValues = new ContentValues(1);
        contentValues.put(CanonicalAddressesColumns.ADDRESS, refinedAddress);
        db = mOpenHelper.getWritableDatabase();
        // 创建接收人的addressId
        retVal = db.insert("canonical_addresses", CanonicalAddressesColumns.ADDRESS, contentValues);
        Log.d(LOG_TAG, "getSingleAddressId: insert new canonical_address for " +
                /*address*/ "xxxxxx" + ", _id=" + retVal);
        return retVal;
    }

    if (cursor.moveToFirst()) { // 如果已经有接收人的addressId, 直接获取返回
        retVal = cursor.getLong(cursor.getColumnIndexOrThrow(BaseColumns._ID));
    }

    ...
}

1.6. 在获取完所有接收的addressId, 接下来继续看获取ThreadId的流程
MmsSmsProvider:
private synchronized Cursor getThreadId(List<String> recipients,List<String> recipientNames) {
    ...
    // 获取接收人的addressId
    Set<Long> addressIds = getAddressIds(recipients);
    ...
    // 如果有多个接收人, 需要对接收人的addressIds进行处理, 保证唯一
    // 防止因为顺序等原因导致重复
    recipientIds = getSpaceSeparatedNumbers(getSortedSet(addressIds));
    ...
    // 通过接收人的addressIds进行查询
    Cursor cursor = db.rawQuery(THREAD_QUERY, selectionArgs);
    if (cursor.getCount() == 0) { // 如果没有查询到ThreadId, 则进行创建
        // 插入ThreadId
        insertThread(recipientIds, recipients.size() ,addresses ,names);

        db = mOpenHelper.getReadableDatabase();
        // 查询ThreadId
        cursor = db.rawQuery(THREAD_QUERY, selectionArgs);    
    }
    if (cursor.getCount() > 1) { // 如果查询到ThreadId, 直接返回
        Log.w(LOG_TAG, "getThreadId: why is cursorCount=" + cursor.getCount());
    }
    return cursor;
    ...
}

1.6.1. 查看插入ThreadId的步骤
MmsSmsProvider:
private void insertThread(String recipientIds, int numberOfRecipients, String addresses ,String names) {
    ContentValues values = new ContentValues(4);

    long date = System.currentTimeMillis();
    values.put(ThreadsColumns.DATE, date - date % 1000); // 时间
    values.put(ThreadsColumns.RECIPIENT_IDS, recipientIds); // 接收人addressIds
    if (numberOfRecipients > 1) {
        values.put(Threads.TYPE, Threads.BROADCAST_THREAD); // 类型
    }
    values.put(ThreadsColumns.MESSAGE_COUNT, 0);// 消息数量
    values.put(ThreadsColumns.RECIPIENT_ADDRESSES, addresses);// 接收人的号码
    values.put(ThreadsColumns.RECIPIENT_NAMES, names);// 接收人的姓名

    // TABLE_THREADS = threads
    // 从此处可以看出, threads数据保存的是会话信息, threadId是每条会话信息的Id
    long result = mOpenHelper.getWritableDatabase().insert(TABLE_THREADS, null, values);
    Log.d(LOG_TAG, "insertThread: created new thread_id " + result +
            " for recipientIds " + /*recipientIds*/ "xxxxxxx");
   
    getContext().getContentResolver().notifyChange(MmsSms.CONTENT_URI, null);
}


2. 开始进入发送短信的流程
WorkingMessage:
public void send(final String recipientsInUI, final int phoneId) {
    ...
    //TODO 如果是新建短信, 则threadId为0
    long origThreadId = mConversation.getThreadId();
    ...
    // 短信的发送
    // Same rules apply as above.
    final String msgText = mText.toString();
    // 启动线程完成发送短信的操作, 目的是不影响界面的返回
    new Thread(new Runnable() {
        @Override
        public void run() {
            // 准备短信发送工作, 包含短信发送工作sendSmsWorker
            preSendSmsWorker(conv, mmsUri, msgText, recipientsInUI, phoneId);
            updateSendStats(conv);
        }
    }, "WorkingMessage.send SMS").start();
}
 
3. 准备短信的发送工作
WorkingMessage:
private void preSendSmsWorker(Conversation conv, Uri mmsUri, String msgText, String recipientsInUI, int phoneId) {
    ...
    // 重点:
    long origThreadId = conv.getThreadId();// 新建短信的ThreadId为0
    Log.d(TAG, "origThreadId: " + origThreadId);
    
    // Make sure we are still using the correct thread ID for our recipient set.
    long threadId = conv.ensureThreadId();// 创建ThreadId
    Log.d(TAG, "threadId: " + threadId);
    ...
}

3.1 根据接收人确保ThreadId
Conversation:
public synchronized long ensureThreadId() {
    ...
    if (mThreadId <= 0) {
        mThreadId = getOrCreateThreadId(mContext, mRecipients);
    }
    ...
}

3.2 获取或创建id, 如果接收人是之前没有过短信记录, 则创建ThreadId
注意: 如果接收人有多个, 而其中某个或者全部接收, 之前都有自己单独的信息记录, 
此处依然会创建ThreadId
public static long getOrCreateThreadId(Context context, ContactList list) {
    ...
    long retVal = 0;
    try {
        // recipients: 接收人的号码
        // names: 接收人的姓名
        retVal = Threads.getOrCreateThreadId(context, recipients, names);
    } catch (IllegalArgumentException e) {
            Log.e(TAG, " Failed to get or create threadId, exception : " + e);
    }
    ...
}

3.3 通过接收人的号码和姓名获取或创建ThreadId
Threads:
public static long getOrCreateThreadId(Context context, Set<String> recipients, Set<String> recipientNames) {
    ...
    // 中间有一段设置查询参数
    Cursor cursor = SqliteWrapper.query(context, context.getContentResolver(), uri, ID_PROJECTION, null, null, null);
    if (cursor != null) {
        try {
            if (cursor.moveToFirst()) {
                return cursor.getLong(0);
            } else {
                Rlog.e(TAG, "getOrCreateThreadId returned no rows!");
            }
        } finally {
            cursor.close();
        }
    }
    ...
}
4. 获取到ThreadId, 即会话的id后, 继续消息发送的流程
WorkingMessage:
private void preSendSmsWorker(Conversation conv, Uri mmsUri, String msgText, String recipientsInUI, int phoneId) {
    ...
    // 重点:
    long origThreadId = conv.getThreadId();// 新建短信的ThreadId为0
    Log.d(TAG, "origThreadId: " + origThreadId);
    
    // Make sure we are still using the correct thread ID for our recipient set.
    long threadId = conv.ensureThreadId();// 创建ThreadId
    Log.d(TAG, "threadId: " + threadId);
    ...
    // 进行短信发送, 主要逻辑分为两步:
    // 1. 创建SmsMessageSender对象
    // 2. 调用SmsMessageSender.sendMessage继续发起发送短信请求
    sendSmsWorker(msgText, semiSepRecipients, threadId, phoneId);

    // Be paranoid and clean any draft SMS up.
    deleteDraftSmsMessage(threadId);
}

5. 执行消息的发送
WorkingMessage:
private void sendSmsWorker(String msgText, String semiSepRecipients, long threadId, int phoneId) {
    ...
    // 1. 创建信息发送者
    MessageSender sender;
    if (SignatureAppend.getInstance().isSignatureEnabled()) {
        Log.e(TAG, "sign:signatureText sender true");
        sender = new SmsMessageSender(mActivity, dests, msgText, threadId,phoneId, signatureText);
    } else {sender = new SmsMessageSender(mActivity, dests, msgText, threadId,phoneId);
        Log.e(TAG, "sign:signatureText sender false");
    }

    try {
        // 2. 进行信息的发送
        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);
    }
}

6. 将即将发送的消息, 添加到消息队列, 并发送广播
SmsMessageSender:
public boolean sendMessage(long token) throws MmsException {
    return queueMessage(token);
}

private boolean queueMessage(long token) throws MmsException {
    ...
    // 获取编码模式: Auto, 7bit, 16bit
    requestDeliveryReport = prefs.getBoolean(SimSettingPreferenceActivity.SMS_DELIVERY_REPORT_MODE, DEFAULT_DELIVERY_REPORT_MODE);
    ...
    for (int i = 0; i < mNumberOfDests; i++) {
        // 将消息添加到消息队列
        Sms.addMessageToUri(mContext.getContentResolver(),
                Uri.parse("content://sms/queued"), mDests[i],
                mMessageText, null,
                mSignatureText, mTimestamp,
                true /* read */,
                requestDeliveryReport,
                mThreadId,
                // SPRD: Add for multi-sim module.
                mPhoneId);
    }
    ...
    // 发送消息发送的广播
    Intent intent = new Intent(SmsReceiverService.ACTION_SEND_MESSAGE,
            null,
            mContext,
            SmsReceiver.class);// 发送到指定的广播接收者
    intent.putExtra(Sms.PHONE_ID, mPhoneId);
    mContext.sendBroadcast(intent);    
    ...
    
}

7. 在SmsReceiver中接收处理SmsReceiverService.ACTION_SEND_MESSAGE的广播
SmsReceiver:
protected void onReceiveWithPrivilege(Context context, Intent intent, boolean privileged) {
    ...
    intent.setClass(context, SmsReceiverService.class);
    intent.putExtra("result", getResultCode());
    beginStartingService(context, intent);    // 启动SmsReceiverService服务, 处理消息的发送
}

8. 在SmsReceiverService进行短信发送处理
SmsReceiverService:
public int onStartCommand(Intent intent, int flags, int startId) {
    Message msg = mServiceHandler.obtainMessage();
    msg.arg1 = startId;
    msg.obj = intent;
    mServiceHandler.sendMessage(msg); // 发送消息到线程处理
}
SmsReceiverService$ServiceHandler:
public void handleMessage(Message msg) {
    ...
    else if (ACTION_SEND_MESSAGE.endsWith(action)) {
        // 处理发送消息
        handleSendMessage(intent.getIntExtra(Sms.PHONE_ID, 0));
    }
    ...
}
SmsReceiverService:
private void handleSendMessage(int phoneId) {
    if (!mSending) { // 未发送
        // 发送消息队列中的第一条消息
        sendFirstQueuedMessage(phoneId);
    }
}
public synchronized void sendFirstQueuedMessage(int selectionPhoneId) {
    ...
    // 查询待发送的消息
    final Uri uri = Uri.parse("content://sms/queued");
    ContentResolver resolver = getContentResolver();
    // date ASC so we send out in  same order the user tried to send messages.
    Cursor c = SqliteWrapper.query(this, resolver, uri, SEND_PROJECTION, selection, null, "date ASC");  
    ...
    if (c.moveToFirst()) { // 查询到有待发送的消息
        ...
        // 创建消息发送器
        SmsMessageSender sender = new SmsSingleRecipientSender(this, address, msgText, threadId, status == Sms.STATUS_PENDING, msgUri, phoneId);
        ...
        // 发送消息
        sender.sendMessage(SendingProgressTokenManager.NO_TOKEN);;
        mSending = true;
    }    
}

9. 最终在SmsSingleRecipientSender中, 执行消息的发送
SmsSingleRecipientSender:
public boolean sendMessage(long token) throws MmsException {
    ...
    // 消息管理
    SmsManager smsManager = SmsManager.getDefault(mPhoneId);
    ArrayList<String> messages = null;
    // 增加签名
    SmsSignatureAppend smsSignatureAppend = new SmsSignatureAppend(mContext, mUri);
    // 增加签名后的消息内容
    mMessageText = smsSignatureAppend.addSignatureToMsgText(mMessageText);    
    ...
    // 获取编码类型, 0: Auto; 1: 7bit; 3: 16bit
    if (OperatorUtils.OPEN_MARKET && Settings.System.getInt(mContext.getContentResolver(), Settings.System.SMS_ENCODE_TYPE, 1) == 3) {
        messages = divideMessageFor16Bit(mMessageText); // 进行16bit编码进行消息分割
    } else {
        messages = smsManager.divideMessage(mMessageText);// 进行7bit编码进行消息的分割
    }
}

9.1. 查看16bit编码进行消息分割
private ArrayList<String> divideMessageFor16Bit(String text) {
    int msgCount;
    int limit;
    int count = text.length() * 2;// 如果是16bit, 短信允许的长度为70个字符
    if (count > SmsMessage.MAX_USER_DATA_BYTES/*140*/) { // 说明短信的条数大于1条
        // 因为java的除法没有小数, 因此这里直接+1条进行计算, 如5.2/2==(int)2; 而我们需要3, (5.2+1)/2==3
        msgCount = (count + (SmsMessage.MAX_USER_DATA_BYTES_WITH_HEADER/*134*/ - 1))
                / SmsMessage.MAX_USER_DATA_BYTES_WITH_HEADER/*134*/;
    } else {// 说明短信的条数为1
        msgCount = 1;
    }
    if (msgCount > 1) {// 如果短信的条数大于1, 则每条短信的长度为134, 会比只有1条短信少6个字节, 少的6个字节存储索引等数据
        limit = SmsMessage.MAX_USER_DATA_BYTES_WITH_HEADER/*134*/;
    } else {// 如果短信的条数小于1, 则短信的长度为140
        limit = SmsMessage.MAX_USER_DATA_BYTES/*140*/;
    }
    ArrayList<String> result = new ArrayList<String>(msgCount);
    int pos = 0; // Index in code units.
    int textLen = text.length();
    while (pos < textLen) {
        int nextPos = 0; // Counts code units.
        // limit/2: 实际的文本长度
        nextPos = pos + Math.min(limit / 2, textLen - pos);// 获取截止的索引

        if ((nextPos <= pos) || (nextPos > textLen)) {
            Log.e(TAG, "fragmentText failed (" + pos + " >= " + nextPos
                    + " or " + nextPos + " >= " + textLen + ")");
            break;
        }
        result.add(text.substring(pos, nextPos));// 保存截取的信息, 注意List是有序的
        pos = nextPos;
    }
    return result;
}

9.2. 查看7bit编码进行消息的分割
SmsManager:
public ArrayList<String> divideMessage(String text) {
    return SmsMessage.fragmentText(text);
}
public static ArrayList<String> fragmentText(String text) {
    // This function is for MO SMS
    TextEncodingDetails ted = (useCdmaFormatForMoSms()) ?// 此处用的是gsm格式
        com.android.internal.telephony.cdma.SmsMessage.calculateLength(text, false) :// 计算长度
        com.android.internal.telephony.gsm.SmsMessage.calculateLength(text, false);// 执行此处

    // TODO(cleanup): The code here could be rolled into the logic
    // below cleanly if these MAX_* constants were defined more
    // flexibly...

    int limit;
    if (ted.codeUnitSize == SmsConstants.ENCODING_7BIT) {// 执行此处
        int udhLength;
        if (ted.languageTable != 0 && ted.languageShiftTable != 0) {
            udhLength = GsmAlphabet.UDH_SEPTET_COST_TWO_SHIFT_TABLES;
        } else if (ted.languageTable != 0 || ted.languageShiftTable != 0) {
            udhLength = GsmAlphabet.UDH_SEPTET_COST_ONE_SHIFT_TABLE;
        } else {
            udhLength = 0;// 执行此处
        }

        if (ted.msgCount > 1) { 
            udhLength += GsmAlphabet.UDH_SEPTET_COST_CONCATENATED_MESSAGE/*6*/;
        }

        if (udhLength != 0) {
            udhLength += GsmAlphabet.UDH_SEPTET_COST_LENGTH;
        }
        // 如果消息的条数大于1, 则limit为153, 如果消息的条数等于1, 则limit为160
        limit = SmsConstants.MAX_USER_DATA_SEPTETS - udhLength;// 
    } else {
        if (ted.msgCount > 1) {
            limit = SmsConstants.MAX_USER_DATA_BYTES_WITH_HEADER;
        } else {
            limit = SmsConstants.MAX_USER_DATA_BYTES;
        }
    }
    
    // 以下进行短信的分割和16bit消息的分割一致
    int pos = 0;  // Index in code units.
    int textLen = text.length();
    ArrayList<String> result = new ArrayList<String>(ted.msgCount);
    while (pos < textLen) {
        int nextPos = 0;  // Counts code units.
        if (ted.codeUnitSize == SmsConstants.ENCODING_7BIT) {
            if (useCdmaFormatForMoSms() && ted.msgCount == 1) {
                // For a singleton CDMA message, the encoding must be ASCII...
                nextPos = pos + Math.min(limit, textLen - pos);
            } else {
                // For multi-segment messages, CDMA 7bit equals GSM 7bit encoding (EMS mode).
                nextPos = GsmAlphabet.findGsmSeptetLimitIndex(text, pos, limit,
                        ted.languageTable, ted.languageShiftTable);
            }
        } else {  // Assume unicode.
            nextPos = pos + Math.min(limit / 2, textLen - pos);
        }
        if ((nextPos <= pos) || (nextPos > textLen)) {
            Rlog.e(LOG_TAG, "fragmentText failed (" + pos + " >= " + nextPos + " or " +
                      nextPos + " >= " + textLen + ")");
            break;
        }
        result.add(text.substring(pos, nextPos));
        pos = nextPos;
    }
    return result; 
}

9.2.1 查看文本长度的计算
com.android.internal.telephony.gsm.SmsMessage:
public static TextEncodingDetails calculateLength(CharSequence msgBody, boolean use7bitOnly) {
    TextEncodingDetails ted = GsmAlphabet.countGsmSeptets(msgBody, use7bitOnly);//计算, 此处use7bitOnly==false 
    ...
}
9.2.2 继续文本的计算
GsmAlphabet:
public static TextEncodingDetails countGsmSeptets(CharSequence s, boolean use7bitOnly) {
    ...
    // fast path for common case where no national language shift tables are enabled
    // 常见情况的快速路径,没有启用国家语言转换表
    if (sEnabledSingleShiftTables.length + sEnabledLockingShiftTables.length == 0) {// 执行此处
        TextEncodingDetails ted = new TextEncodingDetails();
        int septets = GsmAlphabet.countGsmSeptetsUsingTables(s, use7bitOnly, 0, 0); // use7bitOnly此处为false
        if (septets == -1) {
            return null;
        }
        ted.codeUnitSize = SmsConstants.ENCODING_7BIT;
        ted.codeUnitCount = septets;// 编码后的消息长度
        if (septets > SmsConstants.MAX_USER_DATA_SEPTETS/*160*/) { // 说明条数大于1条
            ted.msgCount = (septets + (SmsConstants.MAX_USER_DATA_SEPTETS_WITH_HEADER/*153*/ - 1)) /
                    SmsConstants.MAX_USER_DATA_SEPTETS_WITH_HEADER/*153*/;// 计算条数
            ted.codeUnitsRemaining = (ted.msgCount *
                    SmsConstants.MAX_USER_DATA_SEPTETS_WITH_HEADER) - septets;// 获取剩余的数量
        } else {// 说明条数为1条
            ted.msgCount = 1;
            ted.codeUnitsRemaining = SmsConstants.MAX_USER_DATA_SEPTETS - septets;// 获取剩余的数量
        }
        ted.codeUnitSize = SmsConstants.ENCODING_7BIT;// 设置为7bit编码
        return ted;
    }
    ...
}

9.2.3 继续文本长度的计算
GsmAlphabet:
public static int countGsmSeptetsUsingTables(CharSequence s, boolean use7bitOnly,// s, false
        int languageTable, int languageShiftTable) {//0, 0
    int count = 0;
    int sz = s.length();
    SparseIntArray charToLanguageTable = sCharsToGsmTables[languageTable]; // GSM 7 bit Default Alphabet Extension Table
    SparseIntArray charToShiftTable = sCharsToShiftTables[languageShiftTable];// GSM 7 bit Default Alphabet Extension Table
    for (int i = 0; i < sz; i++) {
        char c = s.charAt(i);
        if (c == GSM_EXTENDED_ESCAPE) {
            Rlog.w(TAG, "countGsmSeptets() string contains Escape character, skipping.");
            continue;
        }
        if (charToLanguageTable.get(c, -1) != -1) {
            count++;
        } else if (charToShiftTable.get(c, -1) != -1) {
            count += 2; // escape + shift table index
        } else if (use7bitOnly) {
            count++;    // encode as space
        } else {
            return -1;  // caller must check for this case
        }
    }
    return count;
}

10. 继续消息的发送流程
SmsSingleRecipientSender:
public boolean sendMessage(long token) throws MmsException {
   ...
    if (OperatorUtils.OPEN_MARKET && Settings.System.getInt(mContext.getContentResolver(), Settings.System.SMS_ENCODE_TYPE, 1) == 3) {
        messages = divideMessageFor16Bit(mMessageText);
    } else {
        messages = smsManager.divideMessage(mMessageText);// 进行发送信息
    }   
    ...
    
    // 将消息移到发件箱, 因此在content://sms/queued中只会存在待发送的信息
    boolean moved = Sms.moveMessageToFolder(mContext, mUri, Sms.MESSAGE_TYPE_OUTBOX, 0);
    ...
    ArrayList<PendingIntent> deliveryIntents =  new ArrayList<PendingIntent>(messageCount);
    ArrayList<PendingIntent> sentIntents = new ArrayList<PendingIntent>(messageCount);
    for (int i = 0; i < messageCount; i++) {
        // mRequestDeliveryReport: 接收人接收到消息的状态的回复
        if (mRequestDeliveryReport && (i == (messageCount - 1))) {
            // 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));
        } else {
            deliveryIntents.add(null);
        }
        
        // 消息发送的意图
        Intent intent  = new Intent(SmsReceiverService.MESSAGE_SENT_ACTION,
                mUri,
                mContext,
                SmsReceiver.class);

        intent.putExtra("smssignature", mMessageText);
        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(Sms.PHONE_ID, mPhoneId);
        }
        sentIntents.add(PendingIntent.getBroadcast(mContext, requestCode, intent, 0));
    }
    ...
    // 执行消息的发送
    smsManager.sendMultipartTextMessage(mDest, mServiceCenter, messages, sentIntents, deliveryIntents);
}

11. 消息发送转移至IccSmsInterfaceManager
SmsManager:
public void sendMultipartTextMessage(
            String destinationAddress, String scAddress, ArrayList<String> parts,
            ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) {
    ...
    if (parts.size() > 1) {
        try {
            ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService(TelephonyManager.getServiceName("isms", mPhoneId)));
            if (iccISms != null) {
                // 发送消息, 至此Mms中的流程已经走完, 下面进入framework层的流程
                iccISms.sendMultipartText(ActivityThread.currentPackageName(), destinationAddress, scAddress, parts, sentIntents, deliveryIntents);
            }
        } catch (RemoteException ex) {
            // ignore it
        }
    } else {
        ...
        // 发送消息
        sendTextMessage(destinationAddress, scAddress, parts.get(0),
                sentIntent, deliveryIntent);
    }    
}

public void sendTextMessage(
            String destinationAddress, String scAddress, String text,
            PendingIntent sentIntent, PendingIntent deliveryIntent) {
    ...
    try {
        ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService(TelephonyManager.getServiceName("isms", mPhoneId)));
        if (iccISms != null) {
            // 发送消息, 至此Mms中的流程已经走完, 下面进入framework层的流程
            iccISms.sendText(ActivityThread.currentPackageName(), destinationAddress,
                    scAddress, text, sentIntent, deliveryIntent);
        }
    } catch (RemoteException ex) {
        // ignore it
    }    
}

 

posted @ 2019-04-16 19:54  luo0612  阅读(1401)  评论(0编辑  收藏  举报