long contactId = Long.parseLong(str);
//Toast.makeText(this, “contactId:”+contactId, 2).show();
Intent intent = new Intent(Intent.ACTION_EDIT);
intent.setData(ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI,contactId));
startActivity(intent);
// zj:根据号码获取ContactId
public static String getContactId(Context context, String number) {
Cursor c = null;
try {
c = context.getContentResolver().query(Phone.CONTENT_URI,
new String[] { Phone.CONTACT_ID, Phone.NUMBER }, null,
null, null);
if (c != null && c.moveToFirst()) {
while (!c.isAfterLast()) {
if (PhoneNumberUtils.compare(number, c.getString(1))) {
return c.getString(0);
}
c.moveToNext();
}
}
} catch (Exception e) {
// Log.e(TAG, “getContactId error:”, e);
} finally {
if (c != null) {
c.close();
}
}
return null;
}
今天就到这儿吧,明天继续。
晚上出去逛了一下,刚刚回来,虽然时间有点晚了,还是得继续啊,嘿嘿~
23.根据number获取联系人名字(若存在)
// zj add for CachedName -->RealName start
public String getContactNameByPhoneNumber(String number) {
if (TextUtils.isEmpty(number)) {
return null;
}
final ContentResolver resolver = ctx.getContentResolver();
Uri lookupUri = null;
String[] projection = new String[] { PhoneLookup._ID,
PhoneLookup.DISPLAY_NAME };
Cursor cursor = null;
try {
lookupUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI,
Uri.encode(number));
cursor = resolver.query(lookupUri, projection, null, null, null);
} catch (Exception ex) {
ex.printStackTrace();
try {
lookupUri = Uri.withAppendedPath(
android.provider.Contacts.Phones.CONTENT_FILTER_URL,
Uri.encode(number));
cursor = resolver
.query(lookupUri, projection, null, null, null);
} catch (Exception e) {
e.printStackTrace();
}
}
String name = null;
if (cursor != null && cursor.getCount() > 0 && cursor.moveToFirst()) {
name = cursor
.getString(cursor
.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
}
cursor.close();
return name;
}
24.根据ContactId获取联系人头像
//Avatar start
public byte[] getPhoto(String people_id) {
String photo_id = null;
String selection1 = ContactsContract.Contacts._ID + " = " + people_id;
Cursor cur1 = getContentResolver().query(
ContactsContract.Contacts.CONTENT_URI, null, selection1, null,
null);
if (cur1.getCount() > 0) {
cur1.moveToFirst();
photo_id = cur1.getString(cur1
.getColumnIndex(ContactsContract.Contacts.PHOTO_ID));
// Log.i(TAG, “photo_id:” + photo_id); // 如果没有头像,这里为空值
}
String selection = null;
if (photo_id == null) {
return null;
} else {
selection = ContactsContract.Data._ID + " = " + photo_id;
}
String[] projection = new String[] { ContactsContract.Data.DATA15 };
Cursor cur = getContentResolver().query(
ContactsContract.Data.CONTENT_URI, projection, selection, null,
null);
cur.moveToFirst();
byte[] contactIcon = cur.getBlob(0);
// Log.i(TAG, “conTactIcon:” + contactIcon);
if (contactIcon == null) {
return null;
} else {
return contactIcon;
}
}
public void setPhoto(String contactId) {
// 以下代码将字节数组转化成Bitmap对象,然后再ImageView中显示出来
ImageButton ibAvatar = (ImageButton) this
.findViewById(com.android.dialer.R.id.zj_detail_avatar);
// String contactId = “1”; // 2
byte[] photo = getPhoto(contactId);
if (photo != null) {
Bitmap map = BitmapFactory.decodeByteArray(photo, 0, photo.length);
ibAvatar.setImageBitmap(map);}
}
//Avatar end
25.Monkey调试
指定应用程序,并向其发送1000个伪随机事件:
adb shell monkey -p com.android.dialer -v 1000
Monkey测试的停止条件
Monkey Test执行过程中在下列三种情况下会自动停止:
(1)如果限定了Monkey运行在一个或几个特定的包上,那么它会监测试图转到其它包的操作,并对其进行阻止。
(2)如果应用程序崩溃或接收到任何失控异常,Monkey将停止并报错。
(3)如果应用程序产生了应用程序不响应(application not responding)的错误,Monkey将会停止并报错。
通过多次并且不同设定下的Monkey测试才算它是一个稳定性足够的程序。
26.DDMS里面的Dump View Hierarchy for UI Automator
修改源码很痛苦的一件事就是分析每个界面的布局文件和代码文件分别是哪些。动则十几个package,分析起来很是头疼,这个工具可以小小的帮助我们一下。当然也可以用find命令查找资源在xml中的位置,然后在根据xml布局文件的名字在java中查找。以下是在网上找到的描述:
用来分析应用当前界面的View层次节点的,假设你现在是在用模拟器手机做调试,你用这个他就会构建一个你先在手机或模拟器显示界面的View的层次图,可以做一些性能的调优之类的。
27.putExtra获取到R.string中内容
it.putExtra(“sms_body”, this.getString(com.android.dialer.R.string.zj_name) + “:” + name + “\n” + this.getString(com.android.dialer.R.string.zj_number) + “:”
- number);
28.通话记录去除重复记录,即同一个联系人只显示一条
去除相同数据
Uri uri = android.provider.CallLog.Calls.CONTENT_URI;
String[] projection = { CallLog.Calls.DATE, CallLog.Calls.NUMBER,
CallLog.Calls.TYPE, CallLog.Calls.CACHED_NAME,
CallLog.Calls._ID, CallLog.Calls.DURATION, };
asyncQuery.startQuery(0, null, uri, projection, “_id in (select max(_id)from calls group by number)”, null,
CallLog.Calls.DEFAULT_SORT_ORDER);
29.打开短信列表
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.setType(“vnd.android-dir/mms-sms”);
startActivity(intent);
30.短信数据库位置
文件 /data/data/com.android.providers.telephony/databases/mmssms.db
这个数据库有13张表,sms表存了短信信息。
推荐一个查看真机里面数据库文件的方法,RE文件浏览器,很赞哦,不过要Root机子。
31.打开拨号界面
Intent intent = new Intent(Intent.ACTION_DIAL,Uri.parse(“tel:13850734494”));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
32.启动另外一个应用的Activity
ComponentName componetName = new ComponentName(
//这个是另外一个应用程序的包名
“com.android.dialer”,
//这个参数是要启动的Activity
“com.android.dialer.calllog.Record”);
try {
Intent intent = new Intent();
intent.setComponent(componetName);
startActivity(intent);
} catch (Exception e) {
}
33.使用ComponentName启动另一个应用的Activity时出现java.lang.SecurityException: Permission Denial的解决方案:
原因分析:
在SDK版本eclair中(Level 5-7?),如果activity没有设定intent-filter则无法被外部程序启动!
解决办法:
给对应的activity添加intent-filter字段,且必须带上action,即使为空也行:
总结到这里的时候,由于另外两个同事有其他的事情要忙,我接手了联系人模块和短信模块,做后续的修改。
时间不早了,今天就到这吧。
有不明白的地方,欢迎交流。
接手了同事的短信模块和联系人模块,他们完成了基础功能,我做后续修改和功能强化。
短信模块主要增加了了以下功能:
短信会话加密(九宫格手势密码和字符密保),短信收藏。
联系人模块,实现了以下功能:
联系人列表长按多选群发短信,联系人右侧快速字母定位联系人,并且把标星联系人(☆)显示在列表前,非字母开头(#)显示在列表后。
联系人模块有较多的Bug,解决这些问题的过程也学到了不少。
话不多说,继续总结……
34.Cursor先获得制