最近接到的任务其实只是修改这个功能,原功能是:
点击到短信,系统根据识别出的数字段和链接段弹出ListView的选择菜单,用户可以对这些号码和链接进行拨号发短信或者打开网页的操作。
修改后的需求是:
点击短信中相应的号码或链接,只针对该号码或链接产生菜单。
我们先看看某的实现方法:
(1)首先利用我查找代码一贯的高效低智商的找到这个短信会话相关的类:ComposeMessageActivity.java
其中涉及到短信会话列表的是这样一个类
private MessageListView mMsgListView;
初始化的方法是
initMessageList()
(2)进入这个方法就可以看到mMsgListView的onItemClick方法,继续追踪方法里面调用的((MessageListItem) view).onMessageListItemClick();
当然也不要忽略一段重要代码,那就是mMsgListView的adapter,
mMsgListView.setAdapter(mMsgListAdapter);这个会在下章关于修改后需求的实现中介绍。
还有mMsgListView.setItemsCanFocus(false);关于这个设置的意义,主要是因为这个短信会话ListView中隐藏了多选的CheckBox,如果不设置这个属性,焦点将被item获取而使得CheckBox无法获得焦点而不能勾选。
(3)继续下面,看来要接触到真相了!
onMessageListItemClick()中可以清晰的看到点击事件到菜单的产生:
方法前面都是些关于item中元素的判断就忽略了,看到关键数组:final URLSpan[] spans = mBodyTextView.getUrls();
mBodyTextView肯定就是短信主体内容无疑了,那这个getUrls()方法是什么呢?
先转到配置文件中,来理解这个urls:
<TextView android:id="@+id/text_view" android:layout_width="wrap_content" android:layout_height="wrap_content" android:autoLink="all" android:linksClickable="false" />
TextView中这个autoLink属性就是这个getUrls()的来源了。系统会自动将超过定长的数字和带有特殊后缀的字符识别成号码和链接。getUrls()就是获取到这些被系统识别的对象,这些对象可以转换成String类型,并且会自动添加tel:或url:来区分。
(4)下面继续分析这个方法。
ArrayAdapter<String> adapter = new ArrayAdapter<String>(mContext, android.R.layout.select_dialog_item, urls) { @Override public View getView(int position, View convertView, ViewGroup parent) { View v = super.getView(position, convertView, parent); TextView tv = (TextView) v; String url = getItem(position).toString(); Uri uri = Uri.parse(url);
final String telPrefix = "tel:"; Drawable d = null; try { d = mContext.getPackageManager().getActivityIcon( new Intent(Intent.ACTION_VIEW, uri)); } catch(android.content.pm.PackageManager.NameNotFoundException ex) { } if (d != null) { d.setBounds(0, 0, d.getIntrinsicHeight(), d.getIntrinsicHeight()); tv.setCompoundDrawablePadding(10); tv.setCompoundDrawables(d, null, null, null); } else { if (url.startsWith(telPrefix)) { d = mContext.getResources().getDrawable(R.drawable.ic_launcher_phone); d.setBounds(0, 0, d.getIntrinsicHeight(), d.getIntrinsicHeight()); tv.setCompoundDrawablePadding(10); tv.setCompoundDrawables(d, null, null, null); } else { tv.setCompoundDrawables(null, null, null, null); } }
final String smsPrefix = "smsto:"; if (url.startsWith(telPrefix)) { url = PhoneNumberUtils.formatNumber( url.substring(telPrefix.length()), mDefaultCountryIso); if (url == null) { url = getItem(position).toString().substring(telPrefix.length()); } } else if (url.startsWith(smsPrefix)) {
url = PhoneNumberUtils.formatNumber( url.substring(smsPrefix.length()), mDefaultCountryIso); if (url == null) { url = getItem(position).toString().substring(smsPrefix.length()); } } else if (url.startsWith(mailPrefix)) { MailTo mt = MailTo.parse(url); url = mt.getTo(); } tv.setText(url);
return v; } };
适配器出现了,这就是产生菜单的关键方法。用过ListView的同学都会知道适配器的作用这里就不赘述。
(5)方法最后就是ListView的点击事件和对话框的生成。
AlertDialog.Builder b = new AlertDialog.Builder(mContext); DialogInterface.OnClickListener click = new DialogInterface.OnClickListener() { @Override public final void onClick(DialogInterface dialog, int which) { if (which >= 0) { Uri uri = Uri.parse(urls.get(which)); Intent intent = new Intent(Intent.ACTION_VIEW, uri); intent.putExtra(Browser.EXTRA_APPLICATION_ID, mContext.getPackageName()); if (urls.get(which).startsWith("smsto:")) { intent.setClassName(mContext, "com.android.mms.ui.SendMessageToActivity"); } intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); mContext.startActivity(intent); if (urls.get(which).startsWith("smsto:")) { intent.setClassName(mContext, "com.android.mms.ui.SendMessageToActivity"); } } dialog.dismiss(); } }; b.setTitle(R.string.select_link_title); b.setCancelable(true); b.setAdapter(adapter, click); b.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { @Override public final void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }); b.show();
这些做完只是分析了原来功能的实现主体方式,对于怎样修改产生之后的效果,这还要回到对mMsgListAdapter即MessageListAdapter类的分析。