@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);
}
}
在上面的方法中,对于长短信将会通过iccISms对象也就是UiccSmsController的sendMultipartText()方法发送出去:
@UiccSmsController.java
public void sendMultipartText(String callingPackage, String destAddr, String scAddr, List parts, List sentIntents, List deliveryIntents) throws android.os.RemoteException {
sendMultipartTextForSubscriber(getPreferredSmsSubscription(), callingPackage, destAddr, scAddr, parts, sentIntents, deliveryIntents);
}
public void sendMultipartTextForSubscriber(long subId, String callingPackage, String destAddr, String scAddr, List parts, List sentIntents, List deliveryIntents) throws android.os.RemoteException {
IccSmsInterfaceManager iccSmsIntMgr = getIccSmsInterfaceManager(subId);
if (iccSmsIntMgr != null ) {
iccSmsIntMgr.sendMultipartText(callingPackage, destAddr, scAddr, parts, sentIntents,
deliveryIntents);
} else {
}
}
接下来UiccSmsController又把流程交给IccSmsInterfaceManager的sendMultipartText()来处理:
@IccSmsInterfaceManager.java
public void sendMultipartText(String callingPackage, String destAddr, String scAddr, List parts, List sentIntents, List deliveryIntents) {
//权限检查
mPhone.getContext().enforceCallingPermission( Manifest.permission.SEND_SMS, "Sending SMS message");
if (mAppOps.noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(), callingPackage) != AppOpsManager.MODE_ALLOWED) {
return;
}
if (parts.size() > 1 && parts.size() < 10 && !SmsMessage.hasEmsSupport()) {
//当前运营商不支持长短新,需要自行将短信分割后分别发送
for (int i = 0; i < parts.size(); i++) {
// If EMS is not supported, we have to break down EMS into single segment SMS
// and add page info " x/y".
String singlePart = parts.get(i);
if (SmsMessage.shouldAppendPageNumberAsPrefix()) {
singlePart = String.valueOf(i + 1) + '/' + parts.size() + ' ' + singlePart;
} else {
singlePart = singlePart.concat(' ' + String.valueOf(i + 1) + '/' + parts.size());
}
PendingIntent singleSentIntent = null;
if (sentIntents != null && sentIntents.size() > i) {
singleSentIntent = sentIntents.get(i);
}
PendingIntent singleDeliveryIntent = null;
if (deliveryIntents != null && deliveryIntents.size() > i) {
singleDeliveryIntent = deliveryIntents.get(i);
}
//将长短信分割,挨个发送
mDispatcher.sendText(destAddr, scAddr, singlePart,
singleSentIntent, singleDeliveryIntent,
null/*messageUri*/, callingPackage);
}
return;
}
//运营商支持长短信,直接发送即可
mDispatcher.sendMultipartText(destAddr, scAddr, (ArrayList) parts,
(ArrayList) sentIntents, (ArrayList) deliveryIntents,
null/*messageUri*/, callingPackage);
}
从上面来看,对于长短信,
需要区分运营商是否支持的情况,如果不支持,需要我们将短信分割后逐条发送,如果支持,需要走不同流程,由于逐条发送时的流程与普通短信发送流程相同,因此这里主要分析以下运营商支持长短信的情况,也就时sendMultipartText()的流程:
@ImsSMSDispatcher.java
protected void sendMultipartText(String destAddr, String scAddr,
ArrayList parts, ArrayList sentIntents,
ArrayList deliveryIntents, Uri messageUri, String callingPkg) {
if (isCdmaMo()) {
//CDMA
mCdmaDispatcher.sendMultipartText(destAddr, scAddr,
parts, sentIntents, deliveryIntents, messageUri, callingPkg);
} else {
//GSM
mGsmDispatcher.sendMultipartText(destAddr, scAddr,
parts, sentIntents, deliveryIntents, messageUri, callingPkg);
}
}
和普通短信类似,也许要区分当前的网络环境,对于GSM来说,就是使用GsmSMSDispatcher来继续处理,这个处理是在GsmSMSDispatcher父类SMSDispatcher中完成的:
@SMSDispatcher.java
protected void sendMultipartText(String destAddr, String scAddr, ArrayList parts, ArrayList sentIntents, ArrayList deliveryIntents, Uri messageUri, String callingPkg) {
//将短信移入或写入发件箱
if (messageUri == null) {
if (SmsApplication.shouldWriteMessageForPackage(callingPkg, mContext)) {
messageUri = writeOutboxMessage(
getSubId(),
destAddr,
getMultipartMessageText(parts),
deliveryIntents != null && deliveryIntents.size() > 0,
callingPkg);
}
} else {
moveToOutbox(getSubId(), messageUri, callingPkg);
}
int refNumber = getNextConcatenatedRef() & 0x00FF;
int msgCount = parts.size();
int encoding = SmsConstants.ENCODING_UNKNOWN;
TextEncodingDetails[] encodingForParts = new TextEncodingDetails[msgCount];
for (int i = 0; i < msgCount; i++) {
TextEncodingDetails details = calculateLength(parts.get(i), false);
if (encoding != details.codeUnitSize
&& (encoding == SmsConstants.ENCODING_UNKNOWN
|| encoding == SmsConstants.ENCODING_7BIT)) {
encoding = details.codeUnitSize;
}
encodingForParts[i] = details;
}
// States to track at the message level (for all parts)
final AtomicInteger unsentPartCount = new AtomicInteger(msgCount);
final AtomicBoolean anyPartFailed = new AtomicBoolean(false);
for (int i = 0; i < msgCount; i++) {
SmsHeader.ConcatRef concatRef = new SmsHeader.ConcatRef();
concatRef.refNumber = refNumber;
concatRef.seqNumber = i + 1; // 1-based sequence
concatRef.msgCount = msgCount;
// TODO: We currently set this to true since our messaging app will never
// send more than 255 parts (it converts the message to MMS well before that).
// However, we should support 3rd party messaging apps that might need 16-bit
// references
// Note: It's not sufficient to just flip this bit to true; it will have
// ripple effects (several calculations assume 8-bit ref).
concatRef.isEightBits = true;
SmsHeader smsHeader = new SmsHeader();
smsHeader.concatRef = concatRef;
// Set the national language tables for 3GPP 7-bit encoding, if enabled.
if (encoding == SmsConstants.ENCODING_7BIT) {
smsHeader.languageTable = encodingForParts[i].languageTable;
smsHeader.languageShiftTable = encodingForParts[i].languageShiftTable;
}
PendingIntent sentIntent = null;
if (sentIntents != null && sentIntents.size() > i) {
sentIntent = sentIntents.get(i);
}
PendingIntent deliveryIntent = null;
if (deliveryIntents != null && deliveryIntents.size() > i) {
deliveryIntent = deliveryIntents.get(i);
}
//逐条发送
sendNewSubmitPdu(destAddr, scAddr, parts.get(i), smsHeader, encoding,
sentIntent, deliveryIntent, (i == (msgCount - 1)),
unsentPartCount, anyPartFailed, messageUri);
}
}
在上面的过程中我们看到,对于运营商支持的长短信情况,
需要把拆分出来的短信分别加上短信头编码,也就是SmsHeader,然后分别调用sendNewSubmitPdu()方法进行发送。
protected void sendNewSubmitPdu(String destinationAddress, String scAddress, String message, SmsHeader smsHeader, int encoding, PendingIntent sentIntent, PendingIntent deliveryIntent, boolean lastPart, AtomicInteger unsentPartCount, AtomicBoolean anyPartFailed, Uri messageUri) {
//对短信内容进行编码
SmsMessage.SubmitPdu pdu = SmsMessage.getSubmitPdu(scAddress, destinationAddress,
message, deliveryIntent != null, SmsHeader.toByteArray(smsHeader),
encoding, smsHeader.languageTable, smsHeader.languageShiftTable);
if (pdu != null) {
HashMap map = getSmsTrackerMap(destinationAddress, scAddress, message, pdu);
//发送
SmsTracker tracker = getSmsTracker(map, sentIntent,
deliveryIntent, getFormat(), unsentPartCount, anyPartFailed, messageUri,
smsHeader, !lastPart);
sendRawPdu(tracker);
} else {
Rlog.e(TAG, "GsmSMSDispatcher.sendNewSubmitPdu(): getSubmitPdu() returned null");
}
}
接下来的流程和普通短信一样,最终通过RILJ将短信发送出去,并且注册回调消息为EVENT_SEND_SMS_COMPLETE。
所以当SMSDispatcher接收到EVENT_SEND_SMS_COMPLETE消息时,就说明,无论是普通短信或者长短信,都已经发送完毕。
以上就是长短信的发送流程。
多收件人的情况,请见下节介绍。