Android普通短信发送有下面几个类:
一个一个类看 :
1 . ComposeMessageActivity.java 详情页面
2 . WoringMessage.java 处理一些发送短信-或-彩信方法
3. SmsMessageSender.java 普通短信插入本地数据库
4. SmsReceiver.java 打开广播开启一个发送服务
5. SmsReceiverService.java 开启服务进行发送,这个服务里面包含发送普通短信 和彩信 各种发送操作服务每一个发 送都会进入该服务里面
6. SmsSindleRecipientSender.java 主要功能是从数据库里面取出将要发送的数据进行传输给底层进行发送
7. SmsManagerWrapper.java 底层类调用底层发送方法
发送步骤:
ComposeMessageActivity.java详情,点击发送,WoringMessage.java发送处理一些发送短信-或-彩信方法,触发插入短信到数据库里面 , 插入数据库 SmsMessageSender.java 插入成功,启动广播SmsReceiver.java广播主要开启开启SmsReceiverService.java进行发送调用SmsSindleRecipientSender.java发送短信,发送成功后开启SmsReceiver.java在启动服务SmsReceiverService.java更改状态、
改变数据库状态 Sms.MESSAGE_TYPE_FAILED发送失败等等...
TelephonyWrapper.Sms.moveMessageToFolder(getApplicationContext(), uri, Sms.MESSAGE_TYPE_FAILED, error);
开始发送步骤 :
第一步:ComposeMessageActivity.java 类 mWorkingMessage.sen() 方法开始发送
private void sendMessage(boolean bCheckEcmMode) {
// Check message size, if >= max message size, do not send message.
if(checkMessageSizeExceeded()){
LogTag.debugD("MessageSizeExceeded");
return;
}
if (bCheckEcmMode) {
// TODO: expose this in telephony layer for SDK build
String inEcm = SystemProperties.get(ConstantsWrapper.TelephonyProperty.PROPERTY_INECM_MODE);
if (Boolean.parseBoolean(inEcm)) {
try {
startActivityForResult(
new Intent(ConstantsWrapper.TelephonyIntent.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null),
REQUEST_CODE_ECM_EXIT_DIALOG);
return;
} catch (ActivityNotFoundException e) {
// continue to send message
Log.e(TAG, "Cannot find EmergencyCallbackModeExitDialog", e);
}
}
}
// Make the recipients editor lost focus, recipients editor will shrink
// and filter useless char in recipients to avoid send sms failed.
if (isRecipientsEditorVisible()
&& mRecipientsEditor.isFocused()
&& !mWorkingMessage.requiresMms()) {
mTextEditor.requestFocus();
}
if (!mSendingMessage) {
if (LogTag.SEVERE_WARNING) {
String sendingRecipients = mConversation.getRecipients().serialize();
if (!sendingRecipients.equals(mDebugRecipients)) {
String workingRecipients = mWorkingMessage.getWorkingRecipients();
if (workingRecipients != null && !mDebugRecipients.equals(workingRecipients)) {
LogTag.warnPossibleRecipientMismatch("ComposeMessageActivity.sendMessage" +
" recipients in window: \"" +
mDebugRecipients + "\" differ from recipients from conv: \"" +
sendingRecipients + "\" and working recipients: " +
workingRecipients, this);
}
}
sanityCheckConversation();
}
// send can change the recipients. Make sure we remove the listeners first and then add
// them back once the recipient list has settled.
removeRecipientsListeners();
if (mWorkingMessage.getResendMultiRecipients()) {
// If resend sms recipient is more than one, use mResendSmsRecipient
LogTag.debugD("mWorkingMessage send mResendSmsRecipient=" + mResendSmsRecipient);
mWorkingMessage.send(mResendSmsRecipient);
} else {
LogTag.debugD("mWorkingMessage send mDebugRecipients=" + mDebugRecipients);
mWorkingMessage.send(mDebugRecipients);
}
//群发时设置状态 liwangjiang
if (mConversation!=null){
if (mMsgListAdapter.getCount()<1){//判断第一次发送
boolean flock = mConversation.getRecipients().size()>=2;
if (flock){
mMsgListAdapter.flockSendSate(flock,mConversation.getRecipients().size());
mMsgListAdapter.changeCursor(null);
}
}
}
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 || MessageUtils.isMailboxMode()) {
finish();
}
}
跳转到WorkingMessage.java
WorkingMessage类里面有一个Send方法这个send方法发送包括普通短信和彩信
/**
* Send this message over the network. Will call back with onMessageSent() once
* it has been dispatched to the telephony stack. This WorkingMessage object is
* no longer useful after this method has been called.
*
* @throws ContentRestrictionException if sending an MMS and uaProfUrl is not defined
* in mms_config.xml.
*/
public void send(final String recipientsInUI) {
long origThreadId = mConversation.getThreadId();
LogTag.debugD("send origThreadId: " + origThreadId);
removeSubjectIfEmpty(true /* notify */);
// Get ready to write to disk.
prepareForSave(true /* notify */);
// Make sure the mConversation has Recipients
checkConversationHasRecipients(recipientsInUI);
// We need the recipient list for both SMS and MMS.
final Conversation conv = mConversation;
String msgTxt = mText.toString();
if (requiresMms() || addressContainsEmailToMms(conv, msgTxt)) {//发送彩信
// uaProfUrl setting in mms_config.xml must be present to send an MMS.
// However, SMS service will still work in the absence of a uaProfUrl address.
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;
}
// Make local copies of the bits we need for sending a message,
// because we will be doing it off of the main thread, which will
// immediately continue on to resetting some of this state.
final Uri mmsUri = mMessageUri;
final PduPersister persister = PduPersister.getPduPersister(mActivity);
final SlideshowModel slideshow = mSlideshow;
final CharSequence subject = mSubject;
final boolean textOnly = mAttachmentType == TEXT;
LogTag.debugD("Send mmsUri: " + mmsUri);
// Do the dirty work of sending the message off of the main UI thread.
new Thread(new Runnable() {
@Override
public void run() {
final SendReq sendReq = makeSendReq(conv, subject);
// Make sure the text in slide 0 is no longer holding onto a reference to
// the text in the message text box.
slideshow.prepareForSend();
sendMmsWorker(conv, mmsUri, persister, slideshow, sendReq, textOnly);
updateSendStats(conv);
}
}, "WorkingMessage.send MMS").start();
} else { //发送普通短信
// Same rules apply as above.
// Add user's signature first if this feature is enabled.
String text = mText.toString();
LogTag.debugD("mText="+text);
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mActivity);
if (sp.getBoolean("pref_key_enable_signature", false)) {
String signature = (sp.getString("pref_key_edit_signature", "")).trim();
if (signature.length() > 0) {
String sigBlock = "\n" + signature;
if (!text.endsWith(sigBlock)) {
// Signature should be written behind the text in a
// newline while the signature has changed.
text += sigBlock;
}
}
}
final String msgText = text;
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;
}
send里面执行他会开启一个线程去调用 preSendSmsWorker(Conversation conv, String msgText, String recipientsInUI)
方法 和 updateSendState(Conversation conv)方法
preSendSmsWorker方法里面主要的操作是调用了 sendSmsWorker 方法
private void sendSmsWorker(String msgText, String semiSepRecipients, long threadId) {//发送普通短信
String[] dests = TextUtils.split(semiSepRecipients, ";");
LogTag.debugD("sendSmsWorker sending message: recipients=" +
semiSepRecipients + ", threadId=" + threadId);
MessageSender sender = null;
if (MessageUtils.isMsimIccCardActive()) {
sender = new SmsMessageSender(mActivity, dests, msgText, threadId,
mCurrentConvSubId);
} else {
sender = new SmsMessageSender(mActivity, dests, msgText, threadId,
SubscriptionManager.getDefaultDataSubscriptionId());
}
try {
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);
}
mStatusListener.onMessageSent();
MmsWidgetProvider.notifyDatasetChanged(mActivity);
}
sendSmsWorker 只需要看这一行
sender = new SmsMessageSender(mActivity, dests, msgText, threadId,
SubscriptionManager.getDefaultDataSubscriptionId());
SmsMessageSender 他继承了 MessageSender
sender.sendMessage(threadId);
sender.sendMessage(threadId);作用是去执行 SmsMessageSender.java 类里面的SendMessage方法SendMessage里面调用了queueMessage(long token)方法
private boolean queueMessage(long token) throws MmsException {
if ((mMessageText == null) || (mNumberOfDests == 0)) {
// Don't try to send an empty message.
if (!(mMessageText == null &&
mContext.getResources().getBoolean(R.bool.enable_send_blank_message))) {
throw new MmsException("Null message body or dest.");
}
}
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
boolean requestDeliveryReport = false;
if (MessageUtils.isMultiSimEnabledMms()) {
int slotId = SubscriptionManagerWrapper.getSlotId(mSubId);
if (MessageUtils.isMsimIccCardActive()) {
requestDeliveryReport = prefs.getBoolean((slotId == ConstantsWrapper.Phone.SUB1) ?
MessagingReportsPreferenceActivity.SMS_DELIVERY_REPORT_SUB1 :
MessagingReportsPreferenceActivity.SMS_DELIVERY_REPORT_SUB2,
DEFAULT_DELIVERY_REPORT_MODE);
} else {
requestDeliveryReport = prefs.getBoolean((slotId == ConstantsWrapper.Phone.SUB1) ?
SmsPreferenceActivity.SMS_DELIVERY_REPORT_SIM1 :
SmsPreferenceActivity.SMS_DELIVERY_REPORT_SIM2,
DEFAULT_DELIVERY_REPORT_MODE);
}
} else {
requestDeliveryReport = prefs.getBoolean(
SmsPreferenceActivity.SMS_DELIVERY_REPORT_NO_MULTI,
DEFAULT_DELIVERY_REPORT_MODE);
}
int priority = -1;
try {
String priorityStr = PreferenceManager.getDefaultSharedPreferences(mContext).getString(
"pref_key_sms_cdma_priority", "");
priority = Integer.parseInt(priorityStr);
} catch (Exception e) {
Log.w(TAG, "get priority error:" + e);
}
for (int i = 0; i < mNumberOfDests; i++) { //设置群发插入数据
try {
LogTag.debugD("queueMessage mDests[i]: " + mDests[i] + " mThreadId: " + mThreadId);
// Check to see whether short message count is up to 2000 for cmcc
if (MessageUtils.checkIsPhoneMessageFull(mContext)) {
break;
}
log("updating Database with subId = " + mSubId);
if (mNumberOfDests>=2){
Log.v("liwangjiangnamess","属于群发");
}else {
Log.v("liwangjiangnamess","属于单发");
}
TelephonyWrapper.Sms.addMessageToUri(mSubId, mContext.getContentResolver(),
Uri.parse("content://sms/queued"), mDests[i],
mMessageText, null, mTimestamp,
true /* read */,
requestDeliveryReport,
mThreadId, priority);
MessageUtils.updateThreadAttachTypeByThreadId(mContext, mThreadId);
} catch (SQLiteException e) {
if (LogTag.DEBUG_SEND) {
Log.e(TAG, "queueMessage SQLiteException", e);
}
SqliteWrapper.checkSQLiteException(mContext, e);
}
}
Intent intent = new Intent(SmsReceiverService.ACTION_SEND_MESSAGE, null, mContext,
SmsReceiver.class);
intent.putExtra(ConstantsWrapper.Phone.SUBSCRIPTION_KEY, mSubId);
intent.putExtra(SmsReceiverService.FLOCK_SEND_STATE, mNumberOfDests);//传输是否是群发
// Notify the SmsReceiverService to send the message out
mContext.sendBroadcast(intent);
return false;
}
在这个方法里面有一个 for 循环 表示插入数据库等待发送mNumberOfDests表示插入多少条哦 ---这个涉及到群发
数据插入完成后开启一个广播 SmsReceiver.java 这个广播主要功能是服务MmsReceiverService.java服务
SmsReceiver.java类
/**
* Handle incoming SMSes. Just dispatches the work off to a Service.
*/
public class SmsReceiver extends BroadcastReceiver {
static final Object mStartingServiceSync = new Object();
static PowerManager.WakeLock mStartingService;
private static SmsReceiver sInstance;
public static SmsReceiver getInstance() {
if (sInstance == null) {
sInstance = new SmsReceiver();
}
return sInstance;
}
@Override
public void onReceive(Context context, Intent intent) {
onReceiveWithPrivilege(context, intent, false);
Log.v("SendSmsReceiver","isSendOk Action = "+intent.getAction());
}
protected void onReceiveWithPrivilege(Context context, Intent intent, boolean privileged) {
if (!MessageUtils.hasBasicPermissions()) {
Log.d("Mms", "SmsReceiver do not have basic permissions");
return;
}
String action = intent.getAction();
LogTag.debugD("onReceiveWithPrivilege:intent="+intent+"|privileged="+privileged);
// If 'privileged' is false, it means that the intent was delivered to the base
// no-permissions receiver class. If we get an SMS_RECEIVED message that way, it
// means someone has tried to spoof the message by delivering it outside the normal
// permission-checked route, so we just ignore it.
if (!privileged && (Intents.SMS_DELIVER_ACTION.equals(action) ||
"android.cellbroadcastreceiver.CB_AREA_INFO_RECEIVED".equals(action))) {
return;
}
intent.setClass(context, SmsReceiverService.class);
intent.putExtra("result", getResultCode());
beginStartingService(context, intent);
}
// N.B.: <code>beginStartingService</code> and
// <code>finishStartingService</code> were copied from
// <code>com.android.calendar.AlertReceiver</code>. We should
// factor them out or, even better, improve the API for starting
// services under wake locks.
/**
* Start the service to process the current event notifications, acquiring
* the wake lock before returning to ensure that the service will run.
*/
public static void beginStartingService(Context context, Intent intent) {
synchronized (mStartingServiceSync) {
if (mStartingService == null) {
PowerManager pm =
(PowerManager)context.getSystemService(Context.POWER_SERVICE);
mStartingService = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"StartingAlertService");
mStartingService.setReferenceCounted(false);
}
mStartingService.acquire();
context.startService(intent);
}
}
/**
* Called back by the service when it has finished processing notifications,
* releasing the wake lock if the service is now stopping.
*/
public static void finishStartingService(Service service, int startId) {
synchronized (mStartingServiceSync) {
if (mStartingService != null) {
if (service.stopSelfResult(startId)) {
mStartingService.release();
}
}
}
}
}
在 这个类里面传给SmsReceiverService一个Action当这个进行匹配,因为SmsReceiverService.java 这个类有很多操作发送彩信下载图片等等....
SmsReceiverService.java
如果看见四大组件就从生命周期开始看起,
@Override
public void onCreate() {
// Temporarily removed for this duplicate message track down.
// if (Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE) || LogTag.DEBUG_SEND) {
// Log.v(TAG, "onCreate");
// }
// Start up the thread running the service. Note that we create a
// separate thread because the service normally runs in the process's
// main thread, which we don't want to block.
HandlerThread thread = new HandlerThread(TAG, Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
在OnCreate里面主要是开启一个线程和初始化一个Handler
主要看 onStartCommand
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (!MmsConfig.isSmsEnabled(this)) {
LogTag.debugD("SmsReceiverService: is not the default sms app");
// NOTE: We MUST not call stopSelf() directly, since we need to
// make sure the wake lock acquired by AlertReceiver is released.
SmsReceiver.finishStartingService(SmsReceiverService.this, startId);
return Service.START_NOT_STICKY;
}
// Temporarily removed for this duplicate message track down.
int resultCode = intent != null ? intent.getIntExtra("result", 0) : 0;
if (resultCode != 0) {
LogTag.debugD("onStart: #" + startId + " resultCode: " + resultCode +
" = " + translateResultCode(resultCode));
}
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
return Service.START_NOT_STICKY;
}
他返回的是一个Service.START_NOT_STICKY 他的作用是服务启动执行完就销毁 就更Hanlder一样
mServceHandler.sendMessage(msg); 他发送了一条消息
看MmsReciverService里面的Hanlder
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
/**
* Handle incoming transaction requests.
* The incoming requests are initiated by the MMSC Server or by the MMS Client itself.
*/
@Override
public void handleMessage(Message msg) {
int serviceId = msg.arg1;
Intent intent = (Intent)msg.obj;
LogTag.debugD("handleMessage serviceId: " + serviceId + " intent: " + intent);
if (intent != null && MmsConfig.isSmsEnabled(getApplicationContext())) {
String action = intent.getAction();
//用来判断是否是群发
mNumberOfDests = intent.getIntExtra(FLOCK_SEND_STATE,0);
int error = intent.getIntExtra("errorCode", 0);
LogTag.debugD("handleMessage action: " + action + " error: " + error);
if (MESSAGE_SENT_ACTION.equals(intent.getAction())) {
handleSmsSent(intent, error);
} else if (SMS_DELIVER_ACTION.equals(action)) {
handleSmsReceived(intent, error);
} else if (CB_AREA_INFO_RECEIVED_ACTION.equals(action)) {
handleCbSmsReceived(intent, error);
} else if (ACTION_BOOT_COMPLETED.equals(action)) {
handleBootCompleted();
} else if (ConstantsWrapper.TelephonyIntent.ACTION_SERVICE_STATE_CHANGED.
equals(action)) {
handleServiceStateChanged(intent);
} else if (ACTION_SEND_MESSAGE.endsWith(action)) {//单条短信发送
handleSendMessage(intent);
} else if (ACTION_SEND_INACTIVE_MESSAGE.equals(action)) {
handleSendInactiveMessage();
}
}
// NOTE: We MUST not call stopSelf() directly, since we need to
// make sure the wake lock acquired by AlertReceiver is released.
SmsReceiver.finishStartingService(SmsReceiverService.this, serviceId);
}
}
handleSendMessage(intent);//发送普通短信调用的这个方法
private void handleSendMessage(Intent intent) {
int subId = intent.getIntExtra(ConstantsWrapper.Phone.SUBSCRIPTION_KEY,
SubscriptionManager.getDefaultSmsSubscriptionId());
if (mSending.get(subId) == null) {
mSending.put(subId, false);
}
if (!mSending.get(subId)) {
sendFirstQueuedMessage(subId);
} else {
LogTag.debugD("subId=" + subId + " is in mSending ");
}
}
sendFirstQueuedMessage(subId);
// Send first queued message of the given subscription 单条短信发送
public synchronized void sendFirstQueuedMessage(int subscription) {
boolean success = true;
boolean isExpectMore = false;
// get all the queued messages from the database
final Uri uri = Uri.parse("content://sms/queued");
ContentResolver resolver = getContentResolver();
String where = "sub_id=?";
String[] whereArgs = new String[] {Integer.toString(subscription)};
Cursor c = SqliteWrapper.query(this, resolver, uri,
SEND_PROJECTION, where, whereArgs, "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);
Log.v("addressaddress","address = "+address);
int threadId = c.getInt(SEND_COLUMN_THREAD_ID);
int status = c.getInt(SEND_COLUMN_STATUS);
int msgId = c.getInt(SEND_COLUMN_ID);
int subId = c.getInt(SEND_COLUMN_SUB_ID);
int priority = c.getInt(SEND_COLUMN_PRIORITY);
Uri msgUri = ContentUris.withAppendedId(Sms.CONTENT_URI, msgId);
// Get the information of is there any messages are pending to process.
// If yes, send this inforamtion to framework to control the link and send all
// messages on same link based on the support in framework
if (c.moveToNext()) {
isExpectMore = true;
}
SmsMessageSender sender = new SmsSingleRecipientSender(this,
address, msgText, threadId, status == Sms.STATUS_PENDING,
msgUri, subId, isExpectMore);
MessageUtils.markAsNotificationThreadIfNeed(this, threadId, address);
if(priority != -1){
((SmsSingleRecipientSender)sender).setPriority(priority);
}
LogTag.debugD("sendFirstQueuedMessage " + msgUri +
", address: " + address +
", threadId: " + threadId);
try {
sender.sendMessage(SendingProgressTokenManager.NO_TOKEN);;
mSending.put(subscription, true);
} catch (MmsException e) {
Log.e(TAG, "sendFirstQueuedMessage: failed to send message " + msgUri
+ ", caught ", e);
mSending.put(subscription, false);
messageFailedToSend(msgUri, SmsManager.RESULT_ERROR_GENERIC_FAILURE);
success = false;
// Sending current message fails. Try to send more pending messages
// if there is any.
Intent intent = new Intent(SmsReceiverService.ACTION_SEND_MESSAGE, null,
this,
SmsReceiver.class);
intent.putExtra(ConstantsWrapper.Phone.SUBSCRIPTION_KEY, subscription);
sendBroadcast(intent);
}
}
} finally {
c.close();
}
}
if (success) {
// We successfully sent all the messages in the queue. We don't need to
// be notified of any service changes any longer.
// In case of MSIM don't unregister service state change if there are any messages
// pending for process on other subscriptions. There may be a chance of other
// subscription is register and waiting for sevice state changes to process the message.
TelephonyManager tm = (TelephonyManager)this.
getSystemService(Context.TELEPHONY_SERVICE);
if (!(tm.getPhoneCount() > 1) ||
isUnRegisterAllowed(subscription)) {
unRegisterForServiceStateChanges();
}
}
}
sendFirstQueuedMessage(subId);这个方法主要功能是从SmsMessageSender.java 类里面插入的短信进行取出,进行发送
SmsSingleRecipientSender.java 发送的主要类
sender.sendMessage(SendingProgressTokenManager.NO_TOKEN);;
开始发送... 进入SmsSingleRecipientSender.java数据传入
public boolean sendMessage(long token) throws MmsException {
boolean deliveryReport=SharePreferencesUtils.getBoolean(mContext,SharePreferencesUtils.ADVANCED_SWITCH);
if (mMessageText == null) {
// Don't try to send an empty message, and destination should be just
// one.
throw new MmsException("Null message body or have multiple destinations.");
}
SmsManager smsManager = SmsManager.getSmsManagerForSubscriptionId(mSubId);
ArrayList<String> messages = null;
if ((MmsConfig.getEmailGateway() != null) &&
(ContactRecipientEntryUtils.isEmailAddress(mDest)
|| MessageUtils.isAlias(mDest))) {
String msgText;
msgText = mDest + " " + mMessageText;
mDest = MmsConfig.getEmailGateway();
messages = smsManager.divideMessage(msgText);
} else {
messages = smsManager.divideMessage(mMessageText);
// remove spaces and dashes from destination number
// (e.g. "801 555 1212" -> "8015551212")
// (e.g. "+8211-123-4567" -> "+82111234567")
mDest = PhoneNumberUtils.stripSeparators(mDest);
mDest = Conversation.verifySingleRecipient(mContext, mThreadId, mDest);
mDest = MessageUtils.checkIdp(mContext, mDest, mSubId);
}
int messageCount = messages.size();
if (messageCount == 0) {
if (!mContext.getResources().getBoolean(R.bool.enable_send_blank_message)) {
// Don't try to send an empty message.
throw new MmsException("SmsMessageSender.sendMessage: divideMessage returned " +
"empty messages. Original message is \"" + mMessageText + "\"");
} else {
return sendEmptyMessage();
}
}
boolean moved = TelephonyWrapper.Sms.moveMessageToFolder(mContext, mUri, Sms.MESSAGE_TYPE_OUTBOX, 0);
if (!moved) {
throw new MmsException("SmsMessageSender.sendMessage: couldn't move message " +
"to outbox: " + mUri);
}
//liwangjiang deliveryIntents 和 sentIntents 可以设置送达报告
ArrayList<PendingIntent> deliveryIntents = new ArrayList<PendingIntent>(messageCount);
ArrayList<PendingIntent> sentIntents = new ArrayList<PendingIntent>(messageCount);
for (int i = 0; i < messageCount; i++) {
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(ConstantsWrapper.Phone.SUBSCRIPTION_KEY, mSubId);
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);
}
sentIntents.add(PendingIntent.getBroadcast(mContext, requestCode, intent, 0));
}
int validityPeriod = getValidityPeriod(mSubId);
// Remove all attributes for CDMA international roaming.
if (mContext.getResources().getBoolean(R.bool.config_ignore_sms_attributes) &&
MessageUtils.isCDMAInternationalRoaming(mSubId)) {
Log.v(TAG, "sendMessage during CDMA international roaming.");
mPriority = -1;
deliveryIntents = null;
validityPeriod = -1;
}
try {
LogTag.debugD("sendMultipartTextMessage:mDest=" + mDest
+ "|mServiceCenter=" + mServiceCenter
+ "|messages=" + ((messages != null) ? TextUtils.join(">", messages) : "empty")
+ "|mPriority=" + mPriority
+ "|isExpectMore=" + isExpectMore
+ "|validityPeriod=" + validityPeriod
+ "|threadId=" + mThreadId
+ "|uri=" + mUri
+ "|msgs.count=" + messageCount
+ "|token=" + token
+ "|mSubId=" + mSubId
+ "|mRequestDeliveryReport=" + mRequestDeliveryReport
);
//liwangjiang 送达报告开关锁
if (deliveryReport){
if (deliveryIntents==null){
deliveryIntents=new ArrayList<>();
}
ArrayList<PendingIntent> deliverIntentList=new ArrayList<>();
Intent deliveryIntent = new Intent(DeliveryReportReceiver.DELIVERE_SMS_ACTION);
PendingIntent mBackIntent = PendingIntent.getBroadcast(mContext, 0,
deliveryIntent, 0);
deliverIntentList.add(mBackIntent);
// SmsManagerWrapper.sendMultipartTextMessage(smsManager, mDest, mServiceCenter, messages,
// sentIntents, intentss, mPriority, isExpectMore, validityPeriod);
// 拆分短信内容(手机短信长度限制)
//发送短信
// smsManager.sendMultipartTextMessage(mDest,mServiceCenter, messages,sentIntents,deliverIntentList);
SmsManagerWrapper.sendMultipartTextMessage(smsManager, mDest, mServiceCenter, messages,
sentIntents, deliverIntentList, mPriority, isExpectMore, validityPeriod);
}else{
SmsManagerWrapper.sendMultipartTextMessage(smsManager, mDest, mServiceCenter, messages,
sentIntents, deliveryIntents, mPriority, isExpectMore, validityPeriod);
}
} catch (Exception ex) {
Log.e(TAG, "SmsMessageSender.sendMessage: caught", ex);
throw new MmsException("SmsMessageSender.sendMessage: caught " + ex +
" from SmsManager.sendMultipartTextMessage()");
}
return false;
}
获取发送短信对象
SmsManager smsManager = SmsManager.getSmsManagerForSubscriptionId(mSubId);
SmsManagerWrapper.sendMultipartTextMessage(smsManager, mDest, mServiceCenter, messages,
sentIntents, deliveryIntents, mPriority, isExpectMore, validityPeriod);
使用SmsManageWrapper类里面的sendMultipartTextMessage方法 ,
SmsManagerWrapper这个类是底层提供的
public class SmsManagerWrapper {
private static final String TAG = "SmsManagerWrapper";
public static final int RESULT_ERROR_FDN_CHECK_FAILURE =
SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE;
public static final int RESULT_ERROR_LIMIT_EXCEEDED = SmsManager.RESULT_ERROR_LIMIT_EXCEEDED;
/**
* Get SMS prompt property, enabled or not
*
* @return true if enabled, false otherwise
*/
public static boolean isSMSPromptEnabled(SmsManager sm) {
boolean ret = sm.isSMSPromptEnabled();
LogUtils.logi(TAG, "isSMSPromptEnabled=" + ret);
return ret;
}
/**
* Get the capacity count of sms on Icc card
*
* @return the capacity count of sms on Icc card
*/
public static int getSmsCapacityOnIcc(SmsManager sm) {
int ret = sm.getSmsCapacityOnIcc();
LogUtils.logi(TAG, "getSmsCapacityOnIcc=" + ret);
return ret;
}
public static void sendMultipartTextMessage(SmsManager sm, String destinationAddress,
String scAddress, ArrayList<String> parts,
ArrayList<PendingIntent> sentIntents,
ArrayList<PendingIntent> deliveryIntents,
int priority, boolean isExpectMore,
int validityPeriod) {
LogUtils.logi(TAG, "sendMultipartTextMessage");
sm.sendMultipartTextMessage(destinationAddress, scAddress, parts, sentIntents,
deliveryIntents, priority, isExpectMore, validityPeriod);
}
}
好了 短信应用发送过程就在于此