android中发送普通信息的详细流程
从信息编辑页面开始,编辑好信息,选择联系人后,点击可用的卡即可发送。这个开始的类是ComposeMessageActivity。
在onCreate和onResume中,主要是设置页面显示的,比如检测一下当前插入了几个卡,若只有一个,那个相应的卡(比如卡一)为可用状态。点击可用的卡发送信息时触发下面的函数执行:
public void onClick(View v) {
// Set phone id label,0 for phone 1, 1 for phone 2.
if (TelephonyManager.getPhoneCount() > 1) {//==============双卡的情况下
if (v == mSendButton2) {
mPhoneId = PHONE_ID_2;
} else if (v == mSendButton1) {
mPhoneId = PHONE_ID_1;
}
//点击了 卡一或者卡二发送,并且已经准备好要发送了
if ((v == mSendButton1 || v == mSendButton2) && isPreparedForSending()) {
//确认发送信息
confirmSendMessageIfNeeded();
//list中保存着所有需要发送的联系人信息,信息发送完之后清空它的内容
list.clear();
} else if (v == mContactsSelectButton) {
//点击了选择联系人的按钮
try {
startPickContactActivity();
} catch (ActivityNotFoundException e) {
// contacts has not provided the function.
Log.e(TAG,
"No Activity found to handle Intent { act=com.android.contacts.MULTIOPERATELIST }",
e);
Toast.makeText(getApplicationContext(),
R.string.No_Activity_found_to_handle_Intent, Toast.LENGTH_SHORT).show();
}
}
} else {//===========================================只有一张卡的情况下
}
}
然后继续调用下面函数:
private void confirmSendMessageIfNeeded() {
if (!isRecipientsEditorVisible()) {
Log.d(TAG, "autosendMSG");
sendMessage(true);
return;
}
//布尔值确定当前信息是否需要发送彩信
boolean isMms = mWorkingMessage.requiresMms();
if (mRecipientsEditor.hasInvalidRecipient(isMms)) {
//是否含有不合法的收件人
Log.d(TAG, "bobo 发彩信");
if (mRecipientsEditor.hasValidRecipient(isMms)) {
//有合法的和不合法的,弹出尝试发送对话框
String title = getResourcesString(R.string.has_invalid_recipient,
mRecipientsEditor.formatInvalidNumbers(isMms));
new AlertDialog.Builder(this)
.setIcon(android.R.drawable.ic_dialog_alert)
.setTitle(title)
.setMessage(R.string.invalid_recipient_message)
.setPositiveButton(R.string.try_to_send,
new SendIgnoreInvalidRecipientListener())
.setNegativeButton(R.string.no, new CancelSendingListener())
.show();
} else {////如果全是不合法的联系人,提示不能发送信息
new AlertDialog.Builder(this)
.setIcon(android.R.drawable.ic_dialog_alert)
.setTitle(R.string.cannot_send_message)
.setMessage(R.string.cannot_send_message_reason)
.setPositiveButton(R.string.yes, new CancelSendingListener())
.show();
}
} else {
Log.d("ComposeMessageActivity","sms");
sendMessage(true);
}
}
private void sendMessage(boolean bCheckEcmMode) {
if (bCheckEcmMode) {
// TODO: expose this in telephony layer for SDK build
////判断电话是否处于紧急拨号模式,得到的inEcm一般为空
String inEcm = SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE);
if (Boolean.parseBoolean(inEcm)) {
Log.i("Bug2311", "BOBOBO ECM 111");
try {
Log.i("Bug2311", "BOBOBO ECM 2222");
startActivityForResult(
new Intent(TelephonyIntents.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);
}
}
}
if (!mSendingMessage) {
// send can change the recipients. Make sure we remove the listeners first and then add
// them back once the recipient list has settled.
removeRecipientsListeners();//==============取消对收件人的监听
// cienet edit maotianliang 2011-6-9:
// mWorkingMessage.send();
Log.i("Bug2311", "sendMessage(boolean bCheckEcmMode)");
mWorkingMessage.send(mPhoneId);//============发送信息
mSentMessage = true;
mSendingMessage = true;
addRecipientsListeners();//=================重新添加收件人监听
}
// But bail out if we are supposed to exit after the message is sent.
if (mExitOnSent) {//=======如果mExitOnSent为true,信息发送完成后退出Activity
finish();
}
}
再继续调用就跳到了类WorkingMessage中了:
public void send(final int subscription) {
if (DEBUG || Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {
LogTag.debug("send");
}
Log.i("Bug2311", "send(final int subscription)");
// Get ready to write to disk.
//主要做一下同步收件人和WorkingMessage,彩信时在准备其他一些东西
prepareForSave(true );
// We need the recipient list for both SMS and MMS.
final Conversation conv = mConversation;
String msgTxt = mText.toString();
if (requiresMms() || addressContainsEmailToMms(conv, msgTxt)) {
// 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(mContext);
final SlideshowModel slideshow = mSlideshow;
//cienet edit maotianliang 2011-6-10:
final SendReq sendReq = makeSendReq(conv, mSubject, subscription);
// Do the dirty work of sending the message off of the main UI thread.
new Thread(new Runnable() {
public void run() {
// Make sure the text in slide 0 is no longer holding onto a reference to
// the text in the message text box.
slideshow.prepareForSend();
//cienet edit maotianliang 2011-6-10:
sendMmsWorker(conv, mmsUri, persister, slideshow, sendReq, subscription);
}
}).start();
} else {
// Same rules apply as above.
final String msgText = mText.toString();//取出信息
new Thread(new Runnable() {
public void run() {
//cienet edit maotianliang 2011-6-10:
Log.d("WorkingMessage", "preSendSmsWorker..sms");
//subscription是传递过来的参数,即为phoneId,,,发送信息
preSendSmsWorker(conv, msgText, subscription);
}
}).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;
}
private void preSendSmsWorker(Conversation conv, String msgText, int subscription) {
// If user tries to send the message, it's a signal the inputted text is what they wanted.
//如果用户尝试发送信息,这就是一个信号,说明输入的文字是他们想要的
UserHappinessSignals.userAcceptedImeText(mContext);
//mStatusListener是一个回调接口,在发送信息前调用此函数
//重置一些信息,比如清空输入内容框、一些监听等等
mStatusListener.onPreMessageSent();
// Make sure we are still using the correct thread ID for our recipient set.
//新建获得会话线程ID
long threadId = conv.ensureThreadId();
//获得收件人列表,并将其序列化
final String semiSepRecipients = conv.getRecipients().serialize();
//只需要做一个正常的发送。我们已经在一个非UI线程中,所以不必启动其他线程来做这个工作
//发送信息==》
sendSmsWorker(msgText, semiSepRecipients, threadId, subscription);
// Be paranoid and clean any draft SMS up.
//清理草稿信息
deleteDraftSmsMessage(threadId);
}
private void sendSmsWorker(String msgText, String semiSepRecipients, long threadId, int subscription) {
String[] dests = TextUtils.split(semiSepRecipients, ";");
if (DEBUG || Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {
LogTag.debug("sendSmsWorker sending message");
}
MessageSender sender;
// runtime check for dsds
if(TelephonyManager.getPhoneCount()>1){
sender = new SmsMessageSender(mContext, dests, msgText, threadId,
subscription);//subscription这个参数即为phoneId
} else {
sender = new SmsMessageSender(mContext, dests, msgText, threadId);
}
try {
sender.sendMessage(threadId);//根据ThreadID发送信息----》
// Make sure this thread isn't over the limits in message count
//确保这个线程不超过限制的邮件数
Recycler.getSmsRecycler().deleteOldMessagesByThreadId(mContext, threadId);
} catch (Exception e) {
Log.e(TAG, "Failed to send SMS message, threadId=" + threadId, e);
}
//mStatusListener是一个回调接口,在发送信息时调用此函数
mStatusListener.onMessageSent();
}
public boolean sendMessage(long token) throws MmsException {
// In order to send the message one by one, instead of sending now, the message will split,
// and be put into the queue along with each destinations
return queueMessage(token);
}
private boolean queueMessage(long token) throws MmsException {
Log.d("SmsMessageSender","mNumberOfDests =---------------1:" + mNumberOfDests);
//mNumberOfDests 即为目标地址的数量,即收信人数量
if ((mMessageText == null) || (mNumberOfDests == 0)) {
//如果信息内容为空或者收信人数量为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);
Log.d("SmsMessageSender","mNumberOfDests =---------------2:" + mNumberOfDests);
for (int i = 0; i < mNumberOfDests; i++) {
//==================根据收件人数目分别建立短信放入发送队列
try {
if(TelephonyManager.getPhoneCount()>1){
log(" DSDS enabled: updating Database with sub = " + mPhoneId);
Sms.addMessageToUri(mContext.getContentResolver(),
Uri.parse("content://sms/queued"), mDests[i],
mMessageText, null, mTimestamp,
true ,
requestDeliveryReport,
mThreadId, mPhoneId);
} else {
log(" DSDS not enabled: updating Database without sub");
Sms.addMessageToUri(mContext.getContentResolver(),
Uri.parse("content://sms/queued"), mDests[i],
mMessageText, null, mTimestamp,
true ,
requestDeliveryReport,
mThreadId);
}
//cienet end yuanman.
} catch (SQLiteException e) {
SqliteWrapper.checkSQLiteException(mContext, e);
}
}
// Notify the SmsReceiverService to send the message out
//通知SmsReceiverService来发送短信,传递参数ACTION_SEND_MESSAGE
mContext.sendBroadcast(new Intent(SmsReceiverService.ACTION_SEND_MESSAGE,
null,
mContext,
SmsReceiver.class));
return false;
}
上面发出的广播由SmsReceiver广播接收器进行接收::
public void onReceive(Context context, Intent intent) {
onReceiveWithPrivilege(context, intent, false);
}
protected void onReceiveWithPrivilege(Context context, Intent intent, boolean privileged) {
intent.setClass(context, SmsReceiverService.class);
intent.putExtra("result", getResultCode());//??????????????????????????????????????????
beginStartingService(context, intent);
}
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);
}
}
启动了SmsReceiverService::::
public int onStartCommand(Intent intent, int flags, int startId) {
mResultCode = intent != null ? intent.getIntExtra("result", 0) : 0;
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
return Service.START_NOT_STICKY;
}
public void handleMessage(Message msg) {
int serviceId = msg.arg1;
Intent intent = (Intent)msg.obj;
if (intent != null) {
String action = intent.getAction();
int error = intent.getIntExtra("errorCode", 0);
if (MESSAGE_SENT_ACTION.equals(intent.getAction())) {
handleSmsSent(intent, error);
} else if (SMS_RECEIVED_ACTION.equals(action)) {
//==================接收短信息
handleSmsReceived(intent, error);
} else if (WAP_PUSH_RECEIVED_ACTION.equals(action)) {
Log.i(TAG,"WAP_PUSH_RECEIVED_ACTION");
handleWapPushReceived(intent, error);
} else if (ACTION_BOOT_COMPLETED.equals(action)) {
handleBootCompleted();
} else if (TelephonyIntents.ACTION_SERVICE_STATE_CHANGED.equals(action)) {
handleServiceStateChanged(intent);
} else if (ACTION_SEND_MESSAGE.endsWith(action)) {
//===================发送短信
handleSendMessage();
}
}
// 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);
}
}
private void handleSendMessage() {
if (!mSending) {//如果没有发送,则准备发送队列中的第一条
sendFirstQueuedMessage();
}
}
public synchronized void sendFirstQueuedMessage() {
boolean success = true;
// get all the queued messages from the database
//从数据库中取得所有的信息队列
final Uri uri = Uri.parse("content://sms/queued");
ContentResolver resolver = getContentResolver();
////查询队列中的信息,包括上次没有发送出去存放在发送队列的信息 ,按用户发送日期的升序排列信息
Cursor c = SqliteWrapper.query(this, resolver, uri,
SEND_PROJECTION, null, 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 phoneId = c.getInt(SEND_COLUMN_PHONE_ID);
int msgId = c.getInt(SEND_COLUMN_ID);
Uri msgUri = ContentUris.withAppendedId(Sms.CONTENT_URI, msgId);
//cienet edit yuanman 2011-6-16: Runtime check for dsds
SmsMessageSender sender;
if(TelephonyManager.getPhoneCount()>1){
sender = new SmsSingleRecipientSender(this, address,
msgText, threadId,
status == Sms.STATUS_PENDING, msgUri, phoneId);
} else {
sender = new SmsSingleRecipientSender(this, address,
msgText, threadId,
status == Sms.STATUS_PENDING, msgUri);
}
if (DEBUG || Log.isLoggable(LogTag.TRANSACTION, Log.VERBOSE)) {
Log.v(TAG, "sendFirstQueuedMessage " + msgUri +
", address: " + address +
", threadId: " + threadId +
", body: " + msgText +
", phoneId:"+ phoneId);
}
try {
//进行单个信息发送
sender.sendMessage(SendingProgressTokenManager.NO_TOKEN);;
mSending = true;
} catch (MmsException e) {
} finally {
c.close();
}
}
}
public boolean sendMessage(long token) throws MmsException {
Log.d("SmsSingleRecipientSender" , "sendMessage");
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.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();
//把信息放到指定的文件夹中
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);
}
//modify by dory.zheng for fdn begin
//???????????????????????????????????
ITelephony iTelePhony = ITelephony.
Stub.asInterface(ServiceManager.getService(PhoneFactory.getServiceName(Context.TELEPHONY_SERVICE, mPhoneId)));
String smscPhoneNum = "";
try {
smscPhoneNum = iTelePhony.getSmsc();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
switch(mPhoneId){
case 0:
boolean sim1_fdn_enabled = SystemProperties.getBoolean("gsm.sim1.fdn.enable", false);
if(sim1_fdn_enabled && !queryFDN(sim1_fdnUri, mDest))
throw new MmsException("FDN_CHECK_FAILURE");
if(sim1_fdn_enabled && !queryFDN(sim1_fdnUri, smscPhoneNum))
throw new MmsException("SMSC_FDN_CHECK_FAILURE");
break;
case 1:
boolean sim2_fdn_enabled = SystemProperties.getBoolean("gsm.sim2.fdn.enable", false);
if(sim2_fdn_enabled && !queryFDN(sim2_fdnUri, mDest))
throw new MmsException("FDN_CHECK_FAILURE");
if(sim2_fdn_enabled && !queryFDN(sim2_fdnUri, smscPhoneNum))
throw new MmsException("SMSC_FDN_CHECK_FAILURE");
break;
}
//modify by dory.zheng for fdn end
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);
if (i == messageCount -1) {
intent.putExtra(SmsReceiverService.EXTRA_MESSAGE_SENT_SEND_NEXT, true);
}
sentIntents.add(PendingIntent.getBroadcast(
mContext, i, intent, 0));
}
try {
if(TelephonyManager.getPhoneCount()>1){
smsManager.sendMultipartTextMessage(mDest, mServiceCenter, messages, sentIntents, deliveryIntents, mPhoneId);
} else {
smsManager.sendMultipartTextMessage(mDest, mServiceCenter, messages, sentIntents, deliveryIntents);
}
//cienet end yuanman.
} catch (Exception ex) {
}
return false;
}
public void sendMultipartTextMessage(
String destinationAddress, String scAddress, ArrayList<String> parts,
ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents, int phoneId) {
if (TextUtils.isEmpty(destinationAddress)) {//收件人地址为空时会触发异常
throw new IllegalArgumentException("Invalid destinationAddress");
}
if (parts == null || parts.size() < 1) {//parts是信息分割后分成的部分,为空时触发异常
throw new IllegalArgumentException("Invalid message body");
}
if (parts.size() > 1) {//长短信的情况
try {
ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService(PhoneFactory.getServiceName("isms",phoneId)));
if (iccISms != null) {
iccISms.sendMultipartText(destinationAddress, scAddress, parts,
sentIntents, deliveryIntents);
}
} catch (RemoteException ex) {
// ignore it
}
} else {//这里是parts==1的情况,即短信不是长短信,没有分割
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, phoneId);
}
}
public void sendTextMessage(
String destinationAddress, String scAddress, String text,
PendingIntent sentIntent, PendingIntent deliveryIntent, int phoneId) {
if (TextUtils.isEmpty(destinationAddress)) {
throw new IllegalArgumentException("Invalid destinationAddress");
}
if (TextUtils.isEmpty(text)) {
throw new IllegalArgumentException("Invalid message body");
}
try {
ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService(PhoneFactory.getServiceName("isms", phoneId)));
if (iccISms != null) {
iccISms.sendText(destinationAddress, scAddress, text, sentIntent, deliveryIntent);
}
} catch (RemoteException ex) {
// ignore it
Log.d(TAG,"sendTextMessage() exception",ex);
}
}
从这里跳到了类IccSmaInterfaceMangerProxy中进行处理
public void sendText(String destAddr, String scAddr,
String text, PendingIntent sentIntent, PendingIntent deliveryIntent) {
mIccSmsInterfaceManager.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent);
}
一下不再赘述。。。