Note: Using this method requires that your app has the
* {@link android.Manifest.permission#SEND_SMS} permission.
Note: Beginning with Android 4.4 (API level 19), if
* and only if an app is not selected as the default SMS app, the system automatically
* writes messages sent using this method to the SMS Provider (the default SMS app is always
* responsible for writing its sent messages to the SMS Provider). For information about
* how to behave as the default SMS app, see {@link android.provider.Telephony}.
PendingIntent
is
Activity.RESULT_OK
for success,
RESULT_ERROR_GENERIC_FAILURE
RESULT_ERROR_RADIO_OFF
RESULT_ERROR_NULL_PDU
RESULT_ERROR_GENERIC_FAILURE
the sentIntent may include
PendingIntent
is
divideMessage
.
Note: Using this method requires that your app has the
* {@link android.Manifest.permission#SEND_SMS} permission.
Note: Beginning with Android 4.4 (API level 19), if
* and only if an app is not selected as the default SMS app, the system automatically
* writes messages sent using this method to the SMS Provider (the default SMS app is always
* responsible for writing its sent messages to the SMS Provider). For information about
* how to behave as the default SMS app, see {@link android.provider.Telephony}.
ArrayList
of strings that, in order,
ArrayList
of
PendingIntent
s (one for each message part) that is
Activity.RESULT_OK
for success,
RESULT_ERROR_GENERIC_FAILURE
RESULT_ERROR_RADIO_OFF
RESULT_ERROR_NULL_PDU
RESULT_ERROR_GENERIC_FAILURE
each sentIntent may include
ArrayList
of
PendingIntent
s (one for each message part) that is
PendingIntent
is
Activity.RESULT_OK for success,
* or one of these errors:
* RESULT_ERROR_GENERIC_FAILURE
* RESULT_ERROR_RADIO_OFF
* RESULT_ERROR_NULL_PDU
* For RESULT_ERROR_GENERIC_FAILURE
the sentIntent may include
* the extra "errorCode" containing a radio technology specific value,
* generally only useful for troubleshooting.
* The per-application based SMS control checks sentIntent. If sentIntent
* is NULL the caller will be checked against all unknown applications,
* which cause smaller number of SMS to be sent in checking period.
* @param deliveryIntent if not NULL this PendingIntent
is
* broadcast when the message is delivered to the recipient. The
* raw pdu of the status report is in the extended data ("pdu").
*/
private void sendTextInternal(String callingPackage, String destAddr, String scAddr,
String text, PendingIntent sentIntent, PendingIntent deliveryIntent,
boolean persistMessageForNonDefaultSmsApp) {
if (Rlog.isLoggable("SMS", Log.VERBOSE)) {
log("sendText: destAddr=" + destAddr + " scAddr=" + scAddr +
" text='"+ text + "' sentIntent=" +
sentIntent + " deliveryIntent=" + deliveryIntent);
}
if (mAppOps.noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(),
callingPackage) != AppOpsManager.MODE_ALLOWED) {
return;
}
if (!persistMessageForNonDefaultSmsApp) {
// Only allow carrier app to skip auto message persistence.
enforceCarrierPrivilege();
}
destAddr = filterDestAddress(destAddr);
mDispatcher.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent,
null/*messageUri*/, callingPackage, persistMessageForNonDefaultSmsApp);
}
也没做啥事情,destAddr = filterDestAddress(destAddr); 接收者的电话号码到是被过滤了一下,这个过滤规则和运营商有关系,没有细看~影响不大,貌似中国的过滤完是不变的。
mDispatcher.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent,
null/*messageUri*/, callingPackage, persistMessageForNonDefaultSmsApp);
mDispatcher 是ImsSmsDispatcher
protected void sendText(String destAddr, String scAddr, String text, PendingIntent sentIntent,
PendingIntent deliveryIntent, Uri messageUri, String callingPkg,
boolean persistMessage) {
Rlog.d(TAG, "sendText");
if (isCdmaMo()) {
mCdmaDispatcher.sendText(destAddr, scAddr,
text, sentIntent, deliveryIntent, messageUri, callingPkg, persistMessage);
} else {
mGsmDispatcher.sendText(destAddr, scAddr,
text, sentIntent, deliveryIntent, messageUri, callingPkg, persistMessage);
}
}
mGsmDispatcher 是GsmSmsDispatcher
protected void sendText(String destAddr, String scAddr, String text, PendingIntent sentIntent,
PendingIntent deliveryIntent, Uri messageUri, String callingPkg,
boolean persistMessage) {
SmsMessage.SubmitPdu pdu = null;
if (FEATURE_VALIDITY_PERIOD_ID == 0 || !mContext.getResources().getBoolean(
FEATURE_VALIDITY_PERIOD_ID)) {
pdu = SmsMessage.getSubmitPdu(
scAddr, destAddr, text, (deliveryIntent != null));
} else {
SmsManager manager = SmsManager.getSmsManagerForSubscriptionId(getSubId());
pdu = (SmsMessage.SubmitPdu)mSmsInterface.getSubmitPdu(
scAddr, destAddr, text, (deliveryIntent != null),
manager.getSmsValidityPeriod());
}
if (pdu != null) {
HashMap map = getSmsTrackerMap(destAddr, scAddr, text, pdu);
SmsTracker tracker = getSmsTracker(map, sentIntent, deliveryIntent, getFormat(),
messageUri, false /*isExpectMore*/, text /*fullMessageText*/, true /*isText*/,
persistMessage);
String carrierPackage = getCarrierAppPackageName();
if (carrierPackage != null) {
Rlog.d(TAG, "Found carrier package.");
TextSmsSender smsSender = new TextSmsSender(tracker);
smsSender.sendSmsByCarrierApp(carrierPackage, new SmsSenderCallback(smsSender));
} else {
Rlog.v(TAG, "No carrier package.");
sendRawPdu(tracker);
}
} else {
Rlog.e(TAG, "GsmSMSDispatcher.sendText(): getSubmitPdu() returned null");
}
}
第一步先生成pdu,然后把destAddr,scAddr,text,pdu集成到一个map里。
HashMap map = getSmsTrackerMap(destAddr, scAddr, text, pdu);
第二步构造tracker,SmsTracker tracker = ...
carrierPackage没见过,所以一般都走这里
Rlog.v(TAG, "No carrier package.");
sendRawPdu(tracker); //检查pdu,package name,appinfo...
->sendSms(tracker);
--> Rlog.d(TAG, "sendSms: "
+ " isIms()=" + isIms()
+ " mRetryCount=" + tracker.mRetryCount
+ " mImsRetry=" + tracker.mImsRetry
+ " mMessageRef=" + tracker.mMessageRef
+ " SS=" + mPhone.getServiceState().getState());
//这算一个关键的log吧~
sendSmsByPstn(tracker);
--->这里会根据是否注册上ims和其他相关条件来调用不用的方法,
Ims:
mCi.sendImsGsmSms(IccUtils.bytesToHexString(smsc),
IccUtils.bytesToHexString(pdu), tracker.mImsRetry,
tracker.mMessageRef, reply);
非Ims:
mCi.sendSMS(IccUtils.bytesToHexString(smsc),
IccUtils.bytesToHexString(pdu), reply);
sendSmsByPstn这个方法内还有一个回调,Message reply = obtainMessage(EVENT_SEND_SMS_COMPLETE, tracker);
看一下放松成功后的处理,在SmsDispather
handleSendComplete((AsyncResult) msg.obj);
处理根据结果是否携带异常分为成功和失败两种,
success:
tracker.onSent(mContext);
fail:
tracker.onFailed
or sendMessageDelayed(retryMsg, SEND_RETRY_DELAY);
看一下成功的处理
SmsTracker
persistOrUpdateMessage(context, messageType, 0/*errorCode*/);//貌似要保存信息
/**
* Persist or update an SMS depending on if we send a new message or a stored message
*
* @param context
* @param messageType The message folder for this SMS, FAILED or SENT
* @param errorCode The current error code for this SMS or SMS part
*/
private void persistOrUpdateMessage(Context context, int messageType, int errorCode) {
if (mMessageUri != null) {
updateMessageState(context, messageType, errorCode);//已经存过了,更新一下状态?
} else {
mMessageUri = persistSentMessageIfRequired(context, messageType, errorCode);//存?
}
}
mSentIntent.send(context, Activity.RESULT_OK, fillIn);//用来通知app??