短信的接收流程应用层
1、源文件
这部分代码在packages/apps/Mms下,涉及的主要类:
- com.android.mms.transaction.PrivilegedSmsReceiver
- com.android.mms.transaction.SmsReceiver
- com.android.mms.transaction.SmsReceiverService
- com.android.mms.transaction.MessagingNotification
2、图解
注意:SeviceHandler是SmsReceiverService的内部类,SmsReceiver是PrivlegedSmsReceiver的父类;
PrivilegedSmsReceiver是一个广播接收器并且继承自SmsReceiver,在AndroidManifest.xml 中有如下声明:
- <intent-filter>
- <action android:name="android.provider.Telephony.SMS_RECEIVED" />
- </intent-filter>
- protected void dispatchPdus(byte[][] pdus) {
- Intent intent = new Intent(Intents.SMS_RECEIVED_ACTION);
- intent.putExtra("pdus", pdus);
- intent.putExtra("encoding", getEncoding());
- intent.putExtra("sub_id", mPhone.getSubscription()); //Subscription information to be passed in an intent
- dispatch(intent, "android.permission.RECEIVE_SMS");
- }
- void dispatch(Intent intent, String permission) {
- mWakeLock.acquire(WAKE_LOCK_TIMEOUT);
- mContext.sendOrderedBroadcast(intent, permission, mResultReceiver,
- this, Activity.RESULT_OK, null, null);
- }
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String SMS_RECEIVED_ACTION =
- "android.provider.Telephony.SMS_RECEIVED";
到这大家应该明白PrivilegedSmsReceiver会接收到中间层的广播,并且该广播很不一般它承载了短信的内容,它从中间层接过接力棒继续向上传递。
2)PrivilegedSmsReceiver传递数据
PrivilegedSmsReceiver从中间层获取到短信的数据后会调用onReceiveWithPrivilege()方法,该方法定义在它的父类SmsReceiver中。该方法没有做太多的操作,仅仅是传递消息,一下是其核心代码:
- protected void onReceiveWithPrivilege(Context context, Intent intent, boolean privileged) {
- if (!privileged && (intent.getAction().equals(Intents.SMS_RECEIVED_ACTION)
- || intent.getAction().equals(Intents.SMS_CB_RECEIVED_ACTION))) {
- return;
- }
- intent.setClass(context, SmsReceiverService.class);
- intent.putExtra("result", getResultCode());
- beginStartingService(context, intent);
- }
3)SmsReceiverService处理
SmsReceiverService它是一个服务,当它开启的时候:首先是在onCreate中初始化,其中初始化最重要的工作就是实例化ServiceHandler对象,ServiceHandler该类是SmsReceiverService的一个内部类,继承自Handler,以下是它的定义代码:
走到这我们可以看出该对象的重要性,即是处理短信真正的苦力,我们继续看是怎么调用到这的。
- 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;
- 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 (SMS_CB_RECEIVED_ACTION.equals(action)) {
- handleCbSmsReceived(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(intent);
- }
- }
- // 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);
- }
- }
onCreate走完请看 onStartCommand方法:
- @Override
- 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;
- }
4)ServiceHandler处理接收到的短信
根据不同的action处理,由于这里是短信的接收SMS_RECEIVED_ACTION,所以调用 handleSmsReceived(intent, error)方法,该方法的处理逻辑如下所示:
说 明在insertMessage方法时会判断当前是替换还是插入,对于替换短信,笔者不是很清楚在什么情况下会走这条路。 blockingUpdateNewMessageIndicator方法会用notification提醒用户,并且在方法内会判断当前用户是否需要显 示发送报告。
3.2 刷新会话列表
走到上面的代码,短信已经入库,但界面的刷新是如何实现的了?
1)会话列表的初始化
ConversationList继承自ListActivity,用于显示短信的会话列表,在该类的onStart方法里有调用了一个重要的方法startAsyncQuery()方法:
- private void startAsyncQuery() {
- try {
- setTitle(getString(R.string.refreshing));
- setProgressBarIndeterminateVisibility(true);
- Conversation.startQueryForAll(mQueryHandler, THREAD_LIST_QUERY_TOKEN);
- } catch (SQLiteException e) {
- SqliteWrapper.checkSQLiteException(this, e);
- }
- }
startQueryForAll方法定义:
- public static void startQueryForAll(AsyncQueryHandler handler, int token) {
- handler.cancelOperation(token);
- handler.startQuery(token, null, sAllThreadsUri,
- ALL_THREADS_PROJECTION, null, null, Conversations.DEFAULT_SORT_ORDER);
- }
这里会使用mQueryHandler去查询数据库,查询完后会回调该对象的onQueryComplete方法,在该方法里填充了mListAdapter,使得会话列表得以显示到界面上。以下代码是其定义:
- private final class ThreadListQueryHandler extends AsyncQueryHandler {
- public ThreadListQueryHandler(ContentResolver contentResolver) {
- super(contentResolver);
- }
- @Override
- protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
- switch (token) {
- case THREAD_LIST_QUERY_TOKEN:
- mListAdapter.changeCursor(cursor);
- setTitle(mTitle);
- setProgressBarIndeterminateVisibility(false);
- if (mNeedToMarkAsSeen) {
- mNeedToMarkAsSeen = false;
- Conversation.markAllConversationsAsSeen(getApplicationContext());
- // Database will be update at this time in some conditions.
- // Wait 1s and ensure update complete.
- mQueryHandler.postDelayed(new Runnable() {
- public void run() {
- // Delete any obsolete threads. Obsolete threads are threads that aren't
- // referenced by at least one message in the pdu or sms tables.
- Conversation.asyncDeleteObsoleteThreads(mQueryHandler,
- DELETE_OBSOLETE_THREADS_TOKEN);
- }
- }, 1000);
- }
- break;
- default:
- Log.e(TAG, "onQueryComplete called with unknown token " + token);
- }
- }
- }
- private void initListAdapter() {
- mListAdapter = new ConversationListAdapter(this, null);
- mListAdapter.setOnContentChangedListener(mContentChangedListener);
- setListAdapter(mListAdapter);
- getListView().setRecyclerListener(mListAdapter);
- }
- private final ConversationListAdapter.OnContentChangedListener mContentChangedListener =
- new ConversationListAdapter.OnContentChangedListener() {
- public void onContentChanged(ConversationListAdapter adapter) {
- startAsyncQuery();
- }
- };
重新调用startAsyncQuery() 该方法刷新。
2)会话列表的更新
看到上面监听器所做的工作大家应该明白啦,会话列表的更新靠的就是这个监听器,当内容发生改变就会重新查询,界面进行刷新,到此为止 短信的界面刷新完成。
看到上面监听器所做的工作大家应该明白啦,会话列表的更新靠的就是这个监听器,当内容发生改变就会重新查询,界面进行刷新,到此为止 短信的界面刷新完成。
特 别注意:该情况是用户在短信会话列表这个界面,如果不在这个界面大概还有其他两种情况: 1、在某个会话中;2、没有进入mms程序。对于前一种情况会在下面继续分析,对于后一种情况我想也不用多说在这种情况下会走activity的声明周期 函数,在onstart方法里进行查询显示前面已经提到。那还有一种特殊的情况就是在从某个会话中返回到会话列表时的处理。下面请看ConversationList的声明:
- <activity android:name=".ui.ConversationList"
- android:label="@string/app_label"
- android:configChanges="orientation|keyboardHidden"
- android:launchMode="singleTop">
- @Override
- protected void onNewIntent(Intent intent) {
- // Handle intents that occur after the activity has already been created.
- startAsyncQuery();
- }
3.23刷新会话内容
刷新ui除了刷新会话列表之外,还有一种情况就是当用户在某个会话时,这时该会话接收到新的消息,这时需要刷新会话的内容,这是怎么实现的?
用于会话显示的activity:ComposeMessageActivity;用于显示会话的短信内容组件: MessageListView;填充listview的adapter是:MessageListAdapter
1)初始化
ComposeMessageActivity的onCreate方法调用initialize方法,initialize方法再调用initMessageList()完成初始化
- private void initMessageList() {
- if (mMsgListAdapter != null) {
- return;
- }
- String highlightString = getIntent().getStringExtra("highlight");
- Pattern highlight = highlightString == null
- ? null
- : Pattern.compile("\\b" + Pattern.quote(highlightString), Pattern.CASE_INSENSITIVE);
- // Initialize the list adapter with a null cursor.
- mMsgListAdapter = new MessageListAdapter(this, null, mMsgListView, true, highlight);
- mMsgListAdapter.setOnDataSetChangedListener(mDataSetChangedListener);
- mMsgListAdapter.setMsgListItemHandler(mMessageListItemHandler);
- mMsgListView.setAdapter(mMsgListAdapter);
- mMsgListView.setItemsCanFocus(false);
- mMsgListView.setVisibility(View.VISIBLE);
- mMsgListView.setOnCreateContextMenuListener(mMsgListMenuCreateListener);
- mMsgListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- if (view != null) {
- ((MessageListItem) view).onMessageListItemClick();
- }
- }
- });
- }
说明:MessageListAdapter定义了一个监听器当数据发生变化的时候回调监听器的onContentChanged的方法,该方法会重新查询该会话相关的内容并刷新显示,以下是其定义:
- private final MessageListAdapter.OnDataSetChangedListener
- mDataSetChangedListener = new MessageListAdapter.OnDataSetChangedListener() {
- public void onDataSetChanged(MessageListAdapter adapter) {
- mPossiblePendingNotification = true;
- }
- public void onContentChanged(MessageListAdapter adapter) {
- startMsgListQuery();
- }
- };
ComposeMessageActivity 的onStart函数里面调用一个重要的方法loadMessageContent();该方法会继续调用startMsgListQuery(),在上 面的adapter的监听器里当内容有变动时回调函数也会调用该方法,以下代码是该方法做的具体工作:
- private void startMsgListQuery() {
- Uri conversationUri = mConversation.getUri();
- if (conversationUri == null) {
- return;
- }
- if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
- log("for " + conversationUri);
- }
- // Cancel any pending queries
- mBackgroundQueryHandler.cancelOperation(MESSAGE_LIST_QUERY_TOKEN);
- try {
- // Kick off the new query
- mBackgroundQueryHandler.startQuery(
- MESSAGE_LIST_QUERY_TOKEN, null, conversationUri,
- PROJECTION, null, null, null);
- } catch (SQLiteException e) {
- SqliteWrapper.checkSQLiteException(this, e);
- }
- }
- @Override
- protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
- switch(token) {
- case MESSAGE_LIST_QUERY_TOKEN:
- // Set last sub used in this conversation thread.
- if (cursor.getCount() > 0) {
- cursor.moveToLast();
- mLastSubInConv = cursor.getInt(COLUMN_SUB_ID); //TODO: ADD SUBSCRIPION HERE
- cursor.moveToPosition(-1);
- } else {
- mLastSubInConv = SUBSCRIPTION_ID_INVALID;
- }
- int newSelectionPos = -1;
- long targetMsgId = getIntent().getLongExtra("select_id", -1);
- if (targetMsgId != -1) {
- cursor.moveToPosition(-1);
- while (cursor.moveToNext()) {
- long msgId = cursor.getLong(COLUMN_ID);
- if (msgId == targetMsgId) {
- newSelectionPos = cursor.getPosition();
- break;
- }
- }
- }
- mMsgListAdapter.changeCursor(cursor);
- if (newSelectionPos != -1) {
- mMsgListView.setSelection(newSelectionPos);
- }
- if (cursor.getCount() == 0 && !isRecipientsEditorVisible() && !mSentMessage) {
- initRecipientsEditor();
- }
- mTextEditor.requestFocus();
- mConversation.blockMarkAsRead(false);
- mConversation.setMessageCount(cursor.getCount());
- return;
- }
- }
3)刷新
刷新就很简单啦,当数据有变化的时候会触发OnDataSetChangedListener这个监听器,这个监听器会调用onContentChanged函数重新查询达到刷新的效果。
4、总结
短信的接收大致过程就是这样,对于上面提到的替换短信,该情况暂时不清楚,有些细节描述的很粗糙,希望大家多提意见,一起研究研究
相关推荐
在IT行业中,短信接收器和接码技术通常与移动应用开发、自动化测试和安全验证相关。短信接收器是一种能够监听并处理短信的应用程序,而接码则是指接收短信验证码的过程,这种验证码通常用于身份验证或防止欺诈行为。...
短信接收发送系统是一种基于C++开发的通信应用,主要用于与运营商接口进行交互,实现短信的收发功能。在本文中,我们将深入探讨该系统的组成部分、关键技术和实现细节。 首先,我们要理解短信系统的架构。通常,...
而且,短信接收方可以看到发送者的身份,增加了信息的安全性和可验证性。 在互联网上发送SMS消息涉及到一系列步骤。首先,消息内容需要限制在特定长度内,接着是接收方的移动电话号码。根据所使用的系统架构,底层...
在这个类中,系统会提供短信发送的基本功能,例如短信发送、短信接收等。 2. ISms 实现类 UiccSmsController UiccSmsController 是一个负责实现短信发送操作的类。在这个类中,系统会将短信发送到 SIM 卡中,并将...
二、短信接收流程 1. Android系统在接收到短信时,会触发广播`android.provider.Telephony.SMS_RECEIVED`。 2. 如果有注册监听此广播的BroadcastReceiver,系统会唤醒这些Receiver。 3. 在BroadcastReceiver的`...
- **短信API**:操作系统提供的接口,允许应用程序(如短信应用)发送和接收短信。 - **网络调制解调器**:连接移动网络,实际执行短信的发送和接收。 总的来说,移动终端发送短信是一个涉及多层协议、编码转换、...
- 收件人设备通过网络从SMSC接收短信。 - 在双向通信中,接收方设备可以回应短信,这个过程与发送类似,只是方向相反。 5. 短信协议的应用: 短信协议不仅用于手机用户之间的通信,还在许多嵌入式系统和物联网设备...
2. 手机号:接收短信手机号 3. 业务编码 4. 老师还是家长 5. 定时时间:时间格式为 2012-10-22 17:12:05,传入的参数为整点或 30 分 6. 短信内容 四、短信发送流程 短信发送流程如下: 1. 客户端将短信发送请求...
3. **丰富的命令集**:协议定义了多种命令,如“bind”(绑定)、“submit_sm”(提交短信)、“deliver_sm”(接收短信)等,覆盖了短信服务的全部生命周期。 4. **扩展性**:SMPP协议设计时考虑了可扩展性,允许...
总之,Android 4.4中的RIL短信接收流程是一个复杂且精细的过程,包括Modem的AT命令交互、RIL的解析处理、系统的广播分发以及应用程序的接收反馈。通过对日志的分析,可以了解每个步骤的功能和作用,这对于排查短信...
Android MMS 彩信发送代码流程是 Android 操作系统中一个复杂的过程,涉及到多个应用层和系统服务的交互。下面将对该过程进行详细解释,从 Messaging 应用层到 framework 应用层的实现细节。 一、Messaging 应用层 ...
- 接收短信:系统能接收并显示来自其他用户的短信。 - 短信存储:提供足够的存储空间,保存用户的短信记录。 - 管理功能:包括搜索、排序、删除和备份短信。 - 安全性:保护用户的隐私,防止未经授权的访问。 2.3. ...
2. **业务逻辑层**:接收到请求后,业务逻辑层会验证输入(如检查短信内容是否合法,是否超过字符限制,接收者是否存在等),执行发送短信的业务流程(如处理短信模板、计费、发送队列等),并可能返回发送状态...
这需要对接收短信网关的返回码进行解析,以判断短信发送结果。 - 同时,平台还应提供发送失败的重试机制,确保短信能成功送达。 6. **安全与隐私** - 在处理用户敏感信息(如手机号码)时,平台必须遵循数据保护...
提供的测试和Demo可以帮助开发者验证CMPP接口的正确性,包括发送短信、接收短信、查询状态和取消发送等操作。这些测试用例可以帮助调试代码,确保在实际环境中能够正常工作。 综上所述,"cmpp短信网关协议实现...
- **软件层面**:操作系统内核中的短信服务模块、应用程序接口(API)以及用户界面应用程序,共同协作完成短信的生成、发送和接收。 4. **短信发送流程**: - 用户触发发送操作后,短信应用通过API调用底层服务,...
Java编程语言在IT行业中广泛应用,其中一个实用场景是与外部服务接口进行交互,比如发送手机短信。本篇将详细讲解如何利用Java实现通过中国网建SMS短信通平台来发送短信,这个过程涉及到网络通信、HTTP请求以及第三...
2. 短信接收:记录接收到的短信,支持短信查询和回复。 3. 用户管理:管理用户账户,分配发送权限,记录用户操作日志。 4. 短信模板:预设各种短信模板,方便快速发送。 5. 条件筛选:根据不同的条件(如时间、号码...
7. **状态回调**: 在短信发送过程中,`sentIntent`和`deliveryIntent`两个意图会被用来通知应用程序短信是否成功发送,以及接收方是否已经收到短信。这些回调通常用于更新用户界面或进行其他业务逻辑处理。 总结来...