短彩信文档

来源:互联网 发布:windows http 编辑:程序博客网 时间:2024/05/02 01:24

 

 

 

 

 

 

SC1】短彩信功能设计修改说明

Version 0.1 (2013-01-22)

Author liuwei

 

 

 

 

 

 

 

  

目录

1.信息发送流程 3

1.1.发送短信流程 3

1.2.发送彩信流程 7

2.新增功能说明 12

2.1.对网址链接的保存与打开 12

2.2.对号码的保存与拨号、发短信 12

2.3.添加与插入联系人 13

2.4.添加Vcard附件功能 14

2.5.对任何一种文件的附件支持 16

2.6.合并转发 16

2.7.转发号码 17

2.8.复制彩信第一页文字 18

2.9.重新发送 18

2.10.复制短信到sim 18

2.11.单页查看彩信 19

2.12.彩信发送重试机制 20

3.箱体模式简介 22

3.1.MessageFolderActivity 22

3.2.MessageBoxActivity 22

3.3.MessageBoxDeleteActivity 24

 

 


1. 信息发送流程

点击发送按钮触发发送,短信是个ImageButton,彩信是个带图片的TextView

 

在confirmSendMessageIfNeeded方法中,粗略的判断了联系人号码合法性,有数字就是合法的。合法就调用了sendMessage(true)方法,在sendMessage方法中调用了mWorkingMessage.send(mDebugRecipients),在send方法中对短彩信发送做了区分。

发送前流程如下:

 

1.1. 发送短信流程

调用了preSendSmsWorker(conv, msgText, recipientsInUI);方法,在此方法中调用了sendSmsWorker(msgText, semiSepRecipients, threadId);方法。

 

接着调用了SmsMessageSender.java类的sendMessage方法发送信息,SmsMessageSender.java在构造时通过getOutgoingServiceCenter(mThreadId)方法试图从收件箱中获取服务中心号码,留给子类所用。sendMessage方法调用了queueMessage(token)方法,在此方法中把短信存到sms数据库中,每一个联系人存一条,type=0。接着发广播到SmsReceiver.class中,收到广播后启动SmsReceiverService服务。

SmsReceiverService中调用hander处理信息,发短信的Action为ACTION_SEND_MESSAGE,调用了handleSendMessage()方法,接着sendFirstQueuedMessage()被调用,在sendFirstQueuedMessage()方法中取出了Uri.parse("content://sms/queued")的待发送数据,构建了SmsMessageSender的子类SmsSingleRecipientSender并调用其的sendMessage方法发送消息。sendMessage方法主要是使用SmsManager对短信进行长短信拆分并一个个发送。

发送成功或者失败都要走SmsReceiverService的handleSmsSent(intent, error);方法。

framework流程:

在SmsManagger的sendMultipartTextMessage方法中判断messages的size,等于1为短信,大于1为长短信,分别走不同流程。

      sendTextMessage(destinationAddress, scAddress, parts.get(0),

                    sentIntent, deliveryIntent);

在此方法中调用

 

通过远程调用,被调用的类为IccSmsInterfaceManagerProxy.java,实际处理的类为IccSmsInterfaceManager.java。在IccSmsInterfaceManager的sendText方法中调用了

mDispatcher.sendText(destAddr, scAddr, text, sentIntent, deliveryIntent);

其中mDispatcher为类SMSDispatcher的对象。此处SMSDispatcher为子类GsmSMSDispatcher,IccSmsInterfaceManager为子类SimSmsInterfaceManager。

在GsmSMSDispatcher的sendText方法里调用了接着调用了sendSms(tracker)方法,最后调到了mCm是CommandsInterface接口的对象,在GsmSMSDispatcher构造时传进来了PhoneBase对象,PhoneBase对象构造时传进去了CommandsInterface对象。PhoneBase对象里的CommandsInterface接口其实就是Ril.java所实现的接口。也就是说Ril.java里的sendSMS方法最后会被调到。

短信发送流程图如下:

 

短信发送后的反馈流程图如下:

 

 

 

 

 

 

 

 

 

 

 

 

 

1.2. 发送彩信流程


调用了发送彩信,主要流程为:把一些基本信息存到发件箱内

接着查询彩信发件箱,所有发件箱内彩信的m_size字段的相加和如果大于4*300*1024,则unDiscard()使得mDiscarded为false,并调用mStatusListener.onMaxPendingMessagesReached()存草稿。

如果待发送的彩信没超出限制,则

获取uri,如果传进去的uri有id,则不变,否则返回带id的uri,主要通过

得到uri,persist方法把这个带id的uri进行数据更新,如果是不带id的uri,则是插入返回带id的uri。

 

获取uri后构建发送类,接着发送(sender.sendMessage(threadId))

 

在sendMessage方法里存了一条数据到pending_msgs数据表内。接着以id为键thread_id为值存到SendingProgressTokenManager中,然后启动TransactionService.class服务。如果发送的彩信是从草稿箱里去的,则通过触发器更新pending_msgs。

TransactionService.class服务中用hander处理消息

 

在onNewIntent方法里

判断了网络状态noNetwork,intent.getAction()得到的值是null,所以走if流程,以时间为条件获取pending_msgs表中所有时间(due_time)小于或等于当前时间并且err_type字段值小于等于10的数据。如果没网络,则给出提示、stopSelf(serviceId)并返回。

 

如果网络正常则构建TransactionBundle对象,此对象存储以msg_id与mms构成的uri及msg_type变换后的int值。调用launchTransaction(serviceId, transactionBundle, false);方法。接着又调用了hander的处理,key为EVENT_TRANSACTION_REQUEST。接着根据msg_type不同构建不同类型的Transaction子类对象。

 

开始发送彩信,先排除掉短信正在发送或者已发送的情况后再判断网络,如果网络良好则往下走,否则保存要发送的信息返回

如果没返回最后会走到开始发送:

 

正式开始处理发送,process()方法里启动一个线程,在线的run方法里构建了SendReq对象,调用

发送信息,每次发送不管成功与否都会更新data字段,根据response更新resp_st字段,如果发送成功了更新m_id(信息中心的?)字段,最后

 

把信息由发件箱移到 已发送。

发送彩信采用的是http的方式,sendPdu一直到最后调用了

发送。

对于发送前判断的网络没准备好而保存的数据,在onCreate中注册了广播接收者,当网络恢复时接收广播,最后调用

processPendingTransaction方法中取出未发送的数据,继续走processTransaction流程。

彩信发送结果

在SendTransaction中发送完彩信后返回结果数组 byte[] response ,解析返回值后更新mms数据,最后调用notifyObservers()方法,而在此类构建时 把observer类 RetryScheduler注册到此类中,最后在RetryScheduler的update方法中对返回结果处理(弹Toast)。

彩信发送流程图:

 

TransactionService内流程:

 

 

 

 

 

 

 

 

 

 

 

 

 

2. 新增功能说明

短彩信应用除了支持原有功能外,额外增加了一些功能。

2.1. 对网址链接的保存与打开

长按有网址的信息,在浮出来的列表中选择“加入书签”,选中要加入的网址后把内容交给browser处理,调用方法为:

     Intent i = new Intent(ACTION_SAVE_BOOKMARK);

     i.putExtra("url", items[which]);

     i.putExtra("retainIcon"false);

         startActivity(i);

长按有网址的信息,在浮出来的列表中选择“将http://XXX 添加到联系人”,则根据联系人提供的接口调用:

intent = ConversationList.createAddContactIntent(uriString);

intent.putExtra("phone_only"true);

String addContactString = getString(

R.string.menu_add_address_to_contacts, uriString);

menu.add(0, MENU_ADD_ADDRESS_TO_CONTACTS, 0, addContactString)

.setOnMenuItemClickListener(l).setIntent(intent);

单击有网址的信息,提示将会在浏览器中打开网址,如果确定则调用URLSpan的onClick方法打开网页,调用浏览器方法为:

        Uri uri = Uri.parse(getURL());

        Context context = widget.getContext();

        Intent intent = new Intent(Intent.ACTION_VIEW, uri);

        intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());

context.startActivity(intent);

 

 

2.2. 对号码的保存与拨号、发短信

长按有电话号码的信息,如果号码在联系人中不存在,则浮出来的列表中有“将XXX添加到联系人”选项,选择此项后将调用:

     Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT);

     intent.setType(Contacts.CONTENT_ITEM_TYPE);

     if (Mms.isEmailAddress(address)) {

        intent.putExtra(ContactsContract.Intents.Insert.EMAIL, address);

        } else {

            intent.putExtra(ContactsContract.Intents.Insert.PHONE, address);

            intent.putExtra(ContactsContract.Intents.Insert.PHONE_TYPE,

                    ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE);

        }

intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);

长按有电话号码的信息,选择“呼叫XXX”后将调用:

String callBackString = getString(R.string.menu_call_back,

uriString);

Intent intentCall = new Intent(Intent.ACTION_CALL,

Uri.parse("tel:" + uriString));

intentCall.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);

menu.add(0, MENU_CALL_BACK, 0, callBackString)

.setOnMenuItemClickListener(l)

    .setIntent(intentCall);

长按有电话号码的信息,选择“发送信息至XXX”后将调用:

Intent intentSend = new Intent(Intent.ACTION_SENDTO,

Uri.parse("smsto:" + uriString));

intentSend.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);

intentSend.putExtra(KEY_SMS_SENDTOtrue);

 

 

2.3. 添加与插入联系人

在信息中按menu键,选择插入联系人,则会把选择的联系人以文本方式插入到信息框,调用:

Intent intent = new Intent(UI.MULTI_PICK_ACTION).

                putExtra("cascading",new Intent(UI.MULTI_PICK_ACTION).setType(Phone.CONTENT_ITEM_TYPE).

                putExtra("cascading",new Intent(UI.MULTI_PICK_ACTION).setType(Email.CONTENT_ITEM_TYPE)));

    intent.putExtra("return_number"true);

startActivityForResult(intent,REQUESET_CODE_SELECT_CONTACTS_AS_TEXT);

新建信息,点击右上的联系人图标则会把选择的联系人添加到联系人框,调用:

     Intent intent = new Intent(UI.MULTI_PICK_ACTION).

putExtra("cascading",new Intent(UI.MULTI_PICK_ACTION).setType(Phone.CONTENT_ITEM_TYPE));

     ArrayList<Account> numbers = new ArrayList<Account>();

     ContactList contacts = mRecipientsEditor.constructContactsFromInput(true);

    for (Contact contact : contacts) {

       Account p = new Account(contact.getName().replace(" """), contact.getNumber().replace(" """));

       numbers.add(p);

    }

    intent.putExtra("exsit_contact", numbers);

startActivityForResult(intent, REQUESET_CODE_SELECT_CONTACTS);

 

 

2.4. 添加Vcard附件功能

点击信息中右上角的附件按钮,选择“联系人”,则从Contacts应用中选择一个联系人由Contacts应用把生成Vcard文件的联系人Uri返回给彩信,由彩信根据联系人uri转换成查询Vcard的Uri,调用如下代码请求选择联系人:

        Intent intent = new Intent(Intent.ACTION_PICK);

        intent.setType(ContactsContract.Contacts.CONTENT_TYPE);

   ((Activity)context).startActivityForResult(intent, requestCode);

当得到联系人的Uri后调用如下方法得到获取VcardUri

 

当得到Vcard的Uri后,保存附件到彩信本地时会根据此Uri调用openFileInputStream方法获取Vcard的数据流,此时Vcard还没生成文件,这样ContentProvider2中的openAssetFile方法将被调用,最后根据match id 值调用如下(生成Vcard采用google提供的库):

 

生成Vcard流程如下:

 

2.5. 对任何一种文件的附件支持

mms没有直接提供添加的功能,但用户可以在其他应用中通过分享文件方式调用此功能。对于不识别的文件接收后只能做保存操作,其中Vcalendar附件提供了载入日历功能但不提供直接添加Vcalender功能,需要去日历应用分享。

发送新增文件在smil中采用类型与标签如下:

文件类型

文件分类

 smil标签

Vcard

text/x-vCard

text

Vcalendar

text/x-vCalendar

text

不识别文件

text/file

text

 

 

2.6. 合并转发

进入一个至少有两封短信的会话,按menu键,选择“合并转发”,将会进入选择需合并的信息界面,选择完信息后,所选择的信息将会组合成一个新的正在编辑的信息。

选择“合并转发”后将会调用:

         Intent intent = new Intent(this, SmsMergeForwardActivity.class);

         long threadId = mConversation.getThreadId();

         intent.putExtra("thread_id", threadId);

         startActivity(intent);

此时将会进入SmsMergeForwardActivity这个Activity,如果,打开的会话不足两封短信,则

 

如果满足条件,用户选择要转发的信息后:

 

 

2.7. 转发号码

按menu进入设置,勾上“转发号码”后,转发短信时会在转发的信息开始部位添加“转发自:XXX”。转发最后都会调用handleForwardedMessage()方法,在此方法中获取设置并在message body中添加号码。

在handleForwardedMessage方法中获取被转发信息的发送者流程如下:

 

 

 

转发流程为:

 

 

2.8. 复制彩信第一页文字

长按彩信信息,选择“复制文字”,对于未接收的彩信,会复制彩信的下载地址,对于已经接收或者本地发送的彩信,会复制彩信第一页的文本。复制文字调用的方法为:

        ClipboardManager clipboard = (ClipboardManager)getSystemService(Context.CLIPBOARD_SERVICE);

 clipboard.setPrimaryClip(ClipData.newPlainText(null, str));

 

2.9. 重新发送

长按发送失败的信息,选择“重新发送”,失败的信息将会重新走发送流程。对于短信,先删除数据库中对应的数据,接着把长按短信的内容作为新信息的内容,调用sendMessage(true)发送信息。对于彩信,则把信息移到草稿箱,再调用sendMessage(true)发送信息。

 

 

2.10. 复制短信到sim

长按短信息,选择“复制到SIM卡”,则会将信息在SIM卡中保存一份。复制到SIM中的短信status主要分SmsManager.STATUS_ON_ICC_SENT、SmsManager.STATUS_ON_ICC_UNSENT、SmsManager.STATUS_ON_ICC_READ。对应短信中的发件箱信息、正在发送与发送失败信息、收件箱信息。

代码流程如下:

 

复制信息调用SmsManager的接口方法为:

此接口方法一直对应到ril.java中的copyMessageToIccEfWithResult(status, pdu, smsc)方法。

 

2.11. 单页查看彩信

点击彩信幻灯片附件,原本将进入幻灯片播放流程,新增加一个类ScrollSlideShowActivity,此类主要是提供单页浏览幻灯片功能,点击幻灯片后将进入此类,在menu菜单中选择播放能进入幻灯片播放流程。

通过Uri获取SlideshowModel对象:

mSlideshowModel = SlideshowModel.createFromMessageUri(this, mUri);

这是一个List容器,里面主要存储了SlideModel对象,而一个SlideModel对象代表着一页幻灯片,于是Uri对应的彩信附件信息就能得到了。

为了让一个窗口能显示所有附件,基层View用的是ScrollView,使显示的内容超出一屏幕时可以上下滑动。

在屏幕底部增加了一组ZoomControls控件,用于控制文字的缩放大小。

对于gif图片,用继承于ImageView的XImageView来显示,XImageView中实现了GifDecodeInterface接口。

 

 

2.12. 彩信发送重试机制

在发送彩信的service启动时注册了广播ConnectivityBroadcastReceiver,主要用于监听mms网络变化,action为ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE,在调用ConnectivityManager的startUsingNetworkFeature激活网络mms网络通道时,得到返回值为APN_REQUEST_STARTED时,将会返回,当通道准备好后ConnectivityBroadcastReceiver将收到广播,接着从新调用startUsingNetworkFeature,得到返回值为APN_ALREADY_ACTIVE时走发送流程,但是有时出现通道准备好了,但是一直未收到广播的情况,故而增加了ConnectivityTimer用于定时询问网络状态,防止彩信不走发送流程。

   SendTransaction.java主要负责彩信内容的发送,如果设置了彩信重试机制,则在此对象构建时attch到Observer实现类MmsSendRetry上,当发送彩信过程结束时,MmsSendRetry中的updata方法将被调用,如果发送不成功,调用scheduleRetry方法更新数据库内数据,再调用setRetryAlarm方法通过AlarmManager设置一个定时发送的广播,广播在RetryReceiver.java中接收,接到广播后如果有网络,则再走一次发送流程,没网络则继续设定下一个广播。

 

 

重试流程图如下:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

3. 箱体模式简介

箱体模式主要是依据sms的 type 与 mms的 msg_box 把信息分为发件箱、收件箱、草稿箱以及已发送信箱。其中对应类型为:收件箱(1)、已发送(2)、草稿箱(3)及发件箱(4)。其中短信的5为发送失败,6为正在发送,而彩信的状态需要判断另一组数据,发送中与发送失败的类型都为4

3.1. MessageFolderActivity

此类只要用于显示箱体模式的第一个界面,使用msg_folder_screen.xml 文件作为布局文件,布局以线性布局为最外层结构,内层以一个相对布局为一个单位,相对布局内有一个显示图片的view及两个显示文字的view,一个单位代表一个文件夹,总共四个文件夹加上SIM卡项。

在onCreate方法中,对每一个文件夹视图设置监听,当点击不同文件夹时对MessageBoxActivity传递不同参数。

 

 

3.2. MessageBoxActivity

此类主要用于列举选中文件夹内所有的信息,继承了ListActivity。在onCreate方法中构建异步查询数据库对象

 

 

在onStart方法里把此对象传递给BoxMsgListAdapter的startQuery静态方法,在此方法里根据上一个Activity传递过来的boxType来选择查询的uri。

 

当点击选中一条信息时,将会调用viewBoxMesssgeItem()方法打开信息内容

 

 

 

 

对于显示SIM卡内的信息时,点击信息不会打开查看,但是可以长按保存到本地,调用的方法如下:

 

查看SIM卡内短信时可以按menu键查看SIM卡当前容量,构建显示的Dialog方法如下:

 

3.3. MessageBoxDeleteActivity

此类主要用于批量删除箱体模式中的信息,支持多个删除与全部选中,其在onCreate放过中就构造异常线程开始查询

 

查询结束后根据查询结果来做不同显示行为

 

0 0
原创粉丝点击