Android Dialer,Mms,Contacts源码修改笔记

33 篇文章 0 订阅
30 篇文章 1 订阅

转载请注明出处:周木水的CSDN博客 http://blog.csdn.net/zhoumushui


最近部门没什么大的需求要改,就让我们改一下Android 4.4的拨号器,联系人以及短信源码。以微信电话本为蓝本,进行布局定制和功能完善。我主要负责拨号模块,涉及拨号面板,通话记录和通话详情这几个修改点。到今天差不多已经完成,下面总结一下过程中遇到的一些问题以及解决步骤:

相应模块实现功能:

①通话记录:运营商显示,ListView条目向右滑动拨号、向左滑动发短信,相同联系人记录合并,

②通话详情:号码归属地显示,联系人标星收藏,加入黑名单来电拦截,显示联系人头像,发送名片,通话记录显示最近5条,超过5条显示More按钮,点击可查看全部记录

======================================================================================================

1.将服务器目录挂载到本地:

[plain]  view plain  copy
  1. sshfs zhoumushui@168.168.0.55:../zhoumushui  localcode/  


2.源码布局分析
res/layout/diapad.xml
包括数字1-9,0,*,#以及对应英文字母。
res/layout/diapad_key.xml
数字0-9的,*,#,字母的属性,大小和颜色
res/layout/dialpad_fragment.xml
包括拨号面板的号码输入框,退格。下面链接dialpad.xml。下面是通话记录,拨号键,overflow menu
res/layout/dialtacts_activity.xml
打开拨号的默认界面,未呼出dialpad
res/layout/phone_no_favorites.xml
文字提示“您收藏的联系人和经常通话的……”,“所有联系人”按钮
res/layout/call_log_fragment.xml
通话记录的过滤查看(全部,来电,去电,未接)按钮
res/layout/call_log_list_item.xml
(拨号首页)通话记录具体条目内容:头像QuickPhoto,名字Name,标签Label,通话类型call_type,通话时长和日期call_count_and_date,secondary_action_icon,
res/layout/call_detail.xml
通话详情界面,包括main_action_push_layer,header_text,main_action,call_and_sms_action等。
res/layout/mtk_dialer_search_item_view.xml
拨号界面输入号码后,页面上端匹配联系人条目的布局文件,包括qucik_contact_photo, name, labelAndNumber等。
res/menu/call_log_options.xml
通话记录列表actionBar上的操作按钮:选择资源,删除。
com/android/dialer/PhoneCallDetailsView.java
显示通话记录条目的具体内容:包括name,callTyepe,callTypeIcons,call_count_and_date,label

3.编译命令
整体编译:

[plain]  view plain  copy
  1. ./mk -t -l=*** -o=TARGET_BUILD_VARIANT=*** n  

-t表示打印出编译log信息
模块编译:
[plain]  view plain  copy
  1. ./mk -t mm packages/apps/Dialer  

输出文件夹:
[plain]  view plain  copy
  1. out/target/product/***/system/priv-app/Dialer.apk  


4.adb的一些操作

[java]  view plain  copy
  1. adb push xxxx.apk /system/app     将应用程序的apk文件push到手机中  
  2. adb install xxxx.apk    安装app  
  3. adb install -r ~/Dialer.apk      //-r 表示强制安装  


5.".9.png"图片原理和制作
左侧和上方的黑线交叉的部分即可扩展区域
右侧和下方的黑线交叉的部分即内容显示区域(如做button背景图时,button上文字的显示区域)

6.让Android4.0以上机器的虚拟按键中显示menu键 
在Activity的onCreate中设置flag:

[java]  view plain  copy
  1. getWindow().setFlags(WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY,WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY);   

7.Visibility的三种属性
1) 可见(visible)
XML文件:android:visibility="visible"
Java代码:view.setVisibility(View.VISIBLE);
2) 不可见(invisible)
XML文件:android:visibility="invisible"
Java代码:view.setVisibility(View.INVISIBLE);
3) 隐藏(GONE)
XML文件:android:visibility="gone"
Java代码:view.setVisibility(View.GONE);


8.去掉ListView的分割线
去掉分割线,把divider的颜色设为透明就行:android:divider="#00000000"
点击之后不让被点击项变成橘黄色:android:listSelector="#00000000"


9.setClickable,setFocusable
setClickable()控制按钮是否可以被点击和点击之后触发监听器事件。
setFocusable()控制键盘是否可以获得这个按钮的焦点。


10.寻找文件中关键字

[java]  view plain  copy
  1. find -name "*.java" | xargs grep -n "ic_phone_dk"// 寻找代码文件中的关键字  
  2. find -name "*.xml"  | xargs grep -n "ic-phone_dk"// 寻找布局文件中的关键字  



11.去掉Activity间的跳转动画
①在values文件夹的styles.xml文件里面新建一个style

[html]  view plain  copy
  1. <style name="AlexNoAniTheme" parent="android:Theme">  
  2. <item name="android:windowAnimationStyle">@style/noAnimation</item>  
  3. <item name="android:windowNoTitle">true</item></style>  
  4. <style name="noAnimation">  
  5. <item name="android:activityOpenEnterAnimation">@null</item>  
  6. <item name="android:activityOpenExitAnimation">@null</item>  
  7. <item name="android:activityCloseEnterAnimation">@null</item>  
  8. <item name="android:activityCloseExitAnimation">@null</item>  
  9. <item name="android:taskOpenEnterAnimation">@null</item>  
  10. <item name="android:taskOpenExitAnimation">@null</item>  
  11. <item name="android:taskCloseEnterAnimation">@null</item>  
  12. <item name="android:taskCloseExitAnimation">@null</item>  
  13. <item name="android:taskToFrontEnterAnimation">@null</item>  
  14. <item name="android:taskToFrontExitAnimation">@null</item>  
  15. <item name="android:taskToBackEnterAnimation">@null</item>  
  16. <item name="android:taskToBackExitAnimation">@null</item></style>  


②在AndroidManifest.xml中修改相应Activity的theme
[html]  view plain  copy
  1. <activity android:name=".HomeActivity"   
  2. android:label="@string/app_name"   
  3. android:theme="@style/AlexNoAniTheme">   


或者将 <item name="android:windowAnimationStyle">@style/noAnimation</item>加入Activity原来的theme

源码修改过程中遇到不少或大或小的问题,接着昨天总结吧。


12.设置分割线
横线:

[html]  view plain  copy
  1. <View   
  2. android:layout_width="fill_parent"   
  3. android:layout_height="1px"   
  4. android:background="?android:attr/listDivider"   
  5. />  


竖线:
[java]  view plain  copy
  1. <View  
  2. android:layout_width="1px"  
  3. android:layout_height="fill_parent"  
  4. android:background="?android:attr/listDivider" />  



13.调用系统发短信界面

[java]  view plain  copy
  1. Uri uri = Uri.parse("smsto:" + callLog.getNumber());      // callLog.getNumber()为手机号码  
  2. Intent it = new Intent(Intent.ACTION_SENDTO, uri);   
  3. //it.putExtra("sms_body", "这是填充短信内容");   
  4. ctx.startActivity(it);  


14.adb查看真机log

[plain]  view plain  copy
  1. adb logcat *:E  // Error级别,其他可类比  


15.锁定Activity的屏幕方向
在Manifest文件中对应Activity属性中添加:     //在application中添加是不是整个应用都有效?不是

[html]  view plain  copy
  1. android:screenOrientation="nosensor"    <!--ES706为竖屏显示-->  


16.Toast常犯错误
 Toast.makeText(this, text, Toast.LENGTH_SHORT).show();  // 常犯错误:忘了调用 show 方法,调试的时候死活不见吐司,搞的晕头转向,生生没有看见ADT的高亮显示,结果是这么明显的错误


17. LinearLayout
也可以有onClick属性,也可以findById,哈哈。这个很好用啊。


18.ActionBar返回上一层

[java]  view plain  copy
  1. import android.app.ActionBar;  


Activity onCreate()中:
[java]  view plain  copy
  1. ActionBar actionBar = getActionBar();  
  2. actionBar.setHomeButtonEnabled(true);  
  3. actionBar.setDisplayHomeAsUpEnabled(true);  
  4. actionBar.setDisplayShowHomeEnabled(true);  



public boolean onOptionsItemSelected(MenuItem item) 中添加一个case:
[java]  view plain  copy
  1. case android.R.id.home:  
  2. finish();       
  3. break;  


19.在Adapter中进行跳转Activity

不同于Activity,Adapter中的跳转用上Context就可以了。


[java]  view plain  copy
  1. <p><span style="font-size: 14px;">/* </span></p><p><span style="font-size: 14px;">*Everything needs a context :(</span></p><p><span style="font-size: 14px;">*/</span></p>// RecordAdapter.java  
  2. private Context ctx;  
  3. 对应跳转代码:  
  4. Intent intent = new Intent(ctx,  
  5. com.android.dialer.calllog.RecordDetail.class);  
  6. intent.putExtra("mNum", callLog.getNumber());  
  7. ctx.startActivity(intent);  
  8. //以下代码是Activity跳转动画,可忽略:  
  9. // add for animation START  
  10. int version = Integer.valueOf(android.os.Build.VERSION.SDK);  
  11. if (version > 5) {  
  12. ((Activity)ctx).overridePendingTransition(  
  13. com.android.dialer.R.anim.push_left_in,  
  14. com.android.dialer.R.anim.push_left_out);  
  15. }  
  16. // add for animation END  


20.overflow menu内容显示图标
其实,overflow中的Action按钮应不应该显示图标,是由MenuBuilder这个类的setOptionalIconsVisible变量来决定的,如果我们在overflow被展开的时候将这个变量赋值为true,那么里面的每一个Action按钮对应的图标就都会显示出来了。赋值的方法仍然是用反射了,代码如下:

[java]  view plain  copy
  1. @Override    
  2. public boolean onMenuOpened(int featureId, Menu menu) {    
  3.     if (featureId == Window.FEATURE_ACTION_BAR && menu != null) {    
  4.         if (menu.getClass().getSimpleName().equals("MenuBuilder")) {    
  5.             try {    
  6.                 Method m = menu.getClass().getDeclaredMethod("setOptionalIconsVisible", Boolean.TYPE);    
  7.                 m.setAccessible(true);    
  8.                 m.invoke(menu, true);    
  9.             } catch (Exception e) {    
  10.             }    
  11.         }    
  12.     }    
  13.     return super.onMenuOpened(featureId, menu);    
  14. }   

 

21.View的setVisibiility()
android view setVisibility():
有三个参数:Parameters:visibility One of VISIBLE, INVISIBLE, or GONE,想对应的三个常量值:0、4、8
VISIBLE:0  意思是可见的
INVISIBILITY:4 意思是不可见的,但还占着原来的空间
GONE:8  意思是不可见的,不占用原来的布局空间


22.联系人接口
添加号码到联系人或新建联系人:

[java]  view plain  copy
  1. Intent intent = new Intent(Intent.ACTION_INSERT_OR_EDIT);   
  2. intent.setType("vnd.android.cursor.item/contact");   
  3. intent.putExtra(Intents.Insert.PHONE, number);   
  4. startActivity(intent);  



直接添加联系人:
[java]  view plain  copy
  1. Intent intent = new Intent(Contacts.Intents.Insert.ACTION);  
  2. intent.setType(Contacts.People.CONTENT_TYPE);  
  3. intent.putExtra(Contacts.Intents.Insert.NAME, "zhangsan");  
  4. intent.putExtra(Contacts.Intents.Insert.PHONE, number);  
  5. intent.putExtra(Contacts.Intents.Insert.PHONE_TYPE,Contacts.PhonesColumns.TYPE_MOBILE);  
  6. intent.putExtra(Contacts.Intents.Insert.EMAIL, "");  
  7. intent.putExtra(Contacts.Intents.Insert.COMPANY,"http://orgcent.com");  
  8. startActivity(intent);  


=====
根据number获取ContactId,然后编辑指定联系人:
[java]  view plain  copy
  1. String str = getContactId(this, number);  
  2. long contactId = Long.parseLong(str);  
  3. //Toast.makeText(this, "contactId:"+contactId, 2).show();  
  4. Intent intent = new Intent(Intent.ACTION_EDIT);   
  5. intent.setData(ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI,contactId));   
  6. startActivity(intent);  
  7. // zj:根据号码获取ContactId  
  8. public static String getContactId(Context context, String number) {  
  9. Cursor c = null;  
  10. try {  
  11. c = context.getContentResolver().query(Phone.CONTENT_URI,  
  12. new String[] { Phone.CONTACT_ID, Phone.NUMBER }, null,  
  13. nullnull);  
  14. if (c != null && c.moveToFirst()) {  
  15. while (!c.isAfterLast()) {  
  16. if (PhoneNumberUtils.compare(number, c.getString(1))) {  
  17. return c.getString(0);  
  18. }  
  19. c.moveToNext();  
  20. }  
  21. }  
  22. catch (Exception e) {  
  23. // Log.e(TAG, "getContactId error:", e);  
  24. finally {  
  25. if (c != null) {  
  26. c.close();  
  27. }  
  28. }  
  29. return null;  
  30. }  


今天就到这儿吧,明天继续。

晚上出去逛了一下,刚刚回来,虽然时间有点晚了,还是得继续啊,嘿嘿~


23.根据number获取联系人名字(若存在)

[java]  view plain  copy
  1. // zj add for CachedName -->RealName start  
  2. public String getContactNameByPhoneNumber(String number) {  
  3. if (TextUtils.isEmpty(number)) {  
  4. return null;  
  5. }  
  6. final ContentResolver resolver = ctx.getContentResolver();  
  7. Uri lookupUri = null;  
  8. String[] projection = new String[] { PhoneLookup._ID,  
  9. PhoneLookup.DISPLAY_NAME };  
  10. Cursor cursor = null;  
  11. try {  
  12. lookupUri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI,  
  13. Uri.encode(number));  
  14. cursor = resolver.query(lookupUri, projection, nullnullnull);  
  15. catch (Exception ex) {  
  16. ex.printStackTrace();  
  17. try {  
  18. lookupUri = Uri.withAppendedPath(  
  19. android.provider.Contacts.Phones.CONTENT_FILTER_URL,  
  20. Uri.encode(number));  
  21. cursor = resolver  
  22. .query(lookupUri, projection, nullnullnull);  
  23. catch (Exception e) {  
  24. e.printStackTrace();  
  25. }  
  26. }  
  27. String name = null;  
  28. if (cursor != null && cursor.getCount() > 0 && cursor.moveToFirst()) {  
  29. name = cursor  
  30. .getString(cursor  
  31. .getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));  
  32. }  
  33. cursor.close();  
  34. return name;  
  35. }  


24.根据ContactId获取联系人头像

[java]  view plain  copy
  1. //Avatar start  
  2. public byte[] getPhoto(String people_id) {  
  3. String photo_id = null;  
  4. String selection1 = ContactsContract.Contacts._ID + " = " + people_id;  
  5. Cursor cur1 = getContentResolver().query(  
  6. ContactsContract.Contacts.CONTENT_URI, null, selection1, null,  
  7. null);  
  8. if (cur1.getCount() > 0) {  
  9. cur1.moveToFirst();  
  10. photo_id = cur1.getString(cur1  
  11. .getColumnIndex(ContactsContract.Contacts.PHOTO_ID));  
  12. // Log.i(TAG, "photo_id:" + photo_id); // 如果没有头像,这里为空值  
  13. }  
  14. String selection = null;  
  15. if (photo_id == null) {  
  16. return null;  
  17. else {  
  18. selection = ContactsContract.Data._ID + " = " + photo_id;  
  19. }  
  20. String[] projection = new String[] { ContactsContract.Data.DATA15 };  
  21. Cursor cur = getContentResolver().query(  
  22. ContactsContract.Data.CONTENT_URI, projection, selection, null,  
  23. null);  
  24. cur.moveToFirst();  
  25. byte[] contactIcon = cur.getBlob(0);  
  26. // Log.i(TAG, "conTactIcon:" + contactIcon);  
  27. if (contactIcon == null) {  
  28. return null;  
  29. else {  
  30. return contactIcon;  
  31. }  
  32. }  
  33.   
  34.   
  35. public void setPhoto(String contactId) {  
  36. // 以下代码将字节数组转化成Bitmap对象,然后再ImageView中显示出来  
  37. ImageButton ibAvatar = (ImageButton) this  
  38. .findViewById(com.android.dialer.R.id.zj_detail_avatar);  
  39. // String contactId = "1"; // 2  
  40. byte[] photo = getPhoto(contactId);  
  41. if (photo != null) {  
  42. Bitmap map = BitmapFactory.decodeByteArray(photo, 0, photo.length);  
  43. ibAvatar.setImageBitmap(map);}  
  44. }  
  45. //Avatar end  


25.Monkey调试
指定应用程序,并向其发送1000个伪随机事件:

[plain]  view plain  copy
  1. 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中内容

[java]  view plain  copy
  1. it.putExtra("sms_body"this.getString(com.android.dialer.R.string.zj_name) + ":" + name + "\n" + this.getString(com.android.dialer.R.string.zj_number) + ":"  
  2.  + number);  


28.通话记录去除重复记录,即同一个联系人只显示一条

去除相同数据

[java]  view plain  copy
  1. Uri uri = android.provider.CallLog.Calls.CONTENT_URI;  
  2. String[] projection = { CallLog.Calls.DATE, CallLog.Calls.NUMBER,  
  3. CallLog.Calls.TYPE, CallLog.Calls.CACHED_NAME,  
  4. CallLog.Calls._ID, CallLog.Calls.DURATION, };  
  5. asyncQuery.startQuery(0null, uri, projection, "_id in (select max(_id)from calls group by number)"null,  
  6. CallLog.Calls.DEFAULT_SORT_ORDER);  


29.打开短信列表

[java]  view plain  copy
  1. Intent intent = new Intent(Intent.ACTION_MAIN);  
  2. intent.addCategory(Intent.CATEGORY_DEFAULT);  
  3. intent.setType("vnd.android-dir/mms-sms");  
  4. startActivity(intent);  


30.短信数据库位置
文件 /data/data/com.android.providers.telephony/databases/mmssms.db 
这个数据库有13张表,sms表存了短信信息。

推荐一个查看真机里面数据库文件的方法,RE文件浏览器,很赞哦,不过要Root机子。


31.打开拨号界面

[java]  view plain  copy
  1. Intent intent = new Intent(Intent.ACTION_DIAL,Uri.parse("tel:13850734494"));   
  2.  intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);   
  3.  startActivity(intent);  


32.启动另外一个应用的Activity

[java]  view plain  copy
  1. ComponentName componetName = new ComponentName(   
  2. //这个是另外一个应用程序的包名   
  3. "com.android.dialer",   
  4. //这个参数是要启动的Activity   
  5. "com.android.dialer.calllog.Record");   
  6. try {   
  7. Intent intent = new Intent();   
  8. intent.setComponent(componetName);   
  9. startActivity(intent);   
  10. catch (Exception e) {   
  11. }  


33.使用ComponentName启动另一个应用的Activity时出现java.lang.SecurityException: Permission Denial的解决方案:
原因分析:
在SDK版本eclair中(Level 5-7?),如果activity没有设定intent-filter则无法被外部程序启动!
解决办法:
给对应的activity添加intent-filter字段,且必须带上action,即使为空也行:

[html]  view plain  copy
  1. <intent-filter>  
  2. <action android:name=""/>  
  3. </intent-filter>  


总结到这里的时候,由于另外两个同事有其他的事情要忙,我接手了联系人模块和短信模块,做后续的修改。

时间不早了,今天就到这吧。

有不明白的地方,欢迎交流。


接手了同事的短信模块和联系人模块,他们完成了基础功能,我做后续修改和功能强化。

短信模块主要增加了了以下功能:

短信会话加密(九宫格手势密码和字符密保),短信收藏。

联系人模块,实现了以下功能:

联系人列表长按多选群发短信,联系人右侧快速字母定位联系人,并且把标星联系人(☆)显示在列表前,非字母开头(#)显示在列表后。

联系人模块有较多的Bug,解决这些问题的过程也学到了不少。

话不多说,继续总结……


34.Cursor先获得制定列的下标,然后根据下标获得数据(不同系统的mmssms.db/sms标的列可能不同,i9250的原生4.3系统有17列,下标0-16.MTK的4.4.2有23列,下标0-22,多出几个自定义列)

[java]  view plain  copy
  1. int addressIndex = cur.getColumnIndex(“address”);  
  2. int dateIndex = cur.getColumnIndex(“date”);  
  3. int typeIndex = cur.getColumnIndex(“type”);  
  4. int bodyIndex = cur.getColumnIndex(“body”);  
  5. long address = Long.parseLong(cur.getString(addressIndex));  
  6. long date = Long.parseLong(cur.getString(dateIndex));  
  7. int type = Integer.parseInt(cur.getString(typeIndex));  
  8. String body = cur.getString(bodyIndex);  
  9. ZjLockMsg newMsg = new ZjLockMsg(threadId,address,date,type,body);  


35.DATABASE_VERSION的问题
注意DATABASE_VERSION 值的问题,在程序运行时,如果改变了表的个数,再次运行时会出错.这是因为数据库改变时,会调用DatabaseHelper类.执行

[java]  view plain  copy
  1. super(context, DATABASE_NAME,null, DATABASE_VERSION )   

这个方法,此时DATABASE_VERSION所对应的表的个数或者内容都是改变之前的, 这就造成异常的出现


36.使用Cursor使,读取里面的数据用到getColumnIndex()时报错:Index -1 requested, with a size of 1
仔细阅读过Cursor的文档,发现关于getColumnIndex()这个方法的说明如下:
public abstract int getColumnIndex (String columnName)
Since: API Level 1
Returns the zero-based index for the given column name, or -1 if the column doesn't exist. If you expect the column to exist use getColumnIndexOrThrow(String) instead, which will make the error more clear.
文档里清楚的表明:在要读取的列不存在的时候该方法会返回值“-1”。所以可知,以上报错可能是因为要get的列不存在,也可能是因为游标位置不对。后来发现,因为我在执行这个语句前没有执行“Cursor.moveToNext();”这个函数,导致游标还位于第一位置的前面,所以索引显示为“-1”,前面加上这句就没错了。
网上另有一种情况是用完Cursor没有关闭导致报此错误,所以也提醒各位用完Cursor要记得执行Cursor.close();


37.Your content must have a ListView whose id attribute is 'android.R.id.list'错误的解决办法

[html]  view plain  copy
  1. <ListView     
  2. android:id="@android:id/list" 或android:id="@id/android:list"    
  3. android:layout_width="fill_parent"    
  4. android:layout_height="wrap_content">    
  5. </ListView>    


38.模糊查找历史命令

[plain]  view plain  copy
  1. history | grep -n "adb pull"  


39.adb pull取设备中的数据库

[plain]  view plain  copy
  1. adb pull /data/data/com.android.mms/databases/zj_msg ~/  
  2. adb pull /data/data/com.android.providers.telephony/databases/mmssms.db  


40.多个设备时adb操作
在adb的指令后面加上参数 -s <serialNumber> 比如 -s emulator-5554
就可以指定adb指令的目标。
在多个模拟器或者设备存在时很实用。

[plain]  view plain  copy
  1. alex@alex-pc:~$ adb devices  
  2. List of devices attached   
  3. 0123456789ABCDEF device  
  4. 016B7EB20100B003 device  
  5. alex@alex-pc:~$ adb -s 0123456789ABCDEF install -r mtk/zj/8382/out/target/product/esky82_tb_cn_kk/system/priv-app/Mms.apk  


41.setBackgroundDrawable和setBackgroundColor的用法
设置背景图片,图片来源于drawable;

[java]  view plain  copy
  1. flightInfoPanel.setBackgroundDrawable(getResources().getDrawable(R.drawable.search_label_click));  

转换字符串为int(颜色);
[java]  view plain  copy
  1. listItemView.deleteFilghtBg.setBackgroundColor(Color.parseColor("#F5F5DC"));  


42.联系人标星收藏,即更改数据库starred字段值为1

[java]  view plain  copy
  1. ContentValues values = new ContentValues();  
  2. values.put("starred"1);  
  3. this.getContentResolver().update(  
  4. ContactsContract.RawContacts.CONTENT_URI, values,  
  5. "contact_id = ?"new String[] { contactIdStr });  


43.布局元素越界时,页面滚动
在LinearLayout外面包一层ScrollView即可,如下代码

ApiDemo 中关于如何使用ScrollView说明,请参考:

[html]  view plain  copy
  1. <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"  
  2. android:layout_width="fill_parent"  
  3. android:layout_height="wrap_content"  
  4. android:scrollbars="none">  
  5. </ScrollView>  


44.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES

这样的问题主要是签名冲突造成的,比如你使用了ADB的debug权限签名,但后来使用标准sign签名后再安装同一个文件会出现这样的错误提示,解决的方法除了只有先老老实实从手机上卸载原有版本再进行安装,而adb install -r参数也无法解决这个问题。


45.cp命令移动隐藏文件

-a参数 所有文件,包括隐藏文件

-r参数 移动目录

所以备份时,直接cp -a -r 一步到位,省得一些点文件漏操作。


46.去除应用图标
去掉Manifest中Activity的对应标签:

[html]  view plain  copy
  1. <category android:name="android.intent.category.LAUNCHER" />  


47.修改framework内容后编译推入设备

[plain]  view plain  copy
  1. ./mk -t mm frameworks/base/  
  2. adb push ***/out/target/product/***/system/framework/framework.jar /system/framework  
  3. adb push ***/out/target/product/***/system/framework/framework2.jar /system/framework  

48.根据RawContactId获取contacts表中的lookup字段
[java]  view plain  copy
  1. public String getLookupKey(long contactId) {  
  2. // Cursor cur = getContentResolver().query( // Raw Contacts表  
  3. // ContactsContract.RawContacts.CONTENT_URI, null,  
  4. // "contact_id = ?", new String[] { ""+contactId }, null);  
  5. String lookupkey = "";  
  6. // final Uri dataUri = Uri.withAppendedPath(  
  7. // ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId),  
  8. // Contacts.Data.CONTENT_DIRECTORY);  
  9. Cursor cursor = getContentResolver().query(Contacts.CONTENT_URI, null,  
  10. "name_raw_contact_id = ?"new String[] { "" + contactId },  
  11. null);  
  12. if (cursor.moveToFirst()) {  
  13. do {  
  14. int starIndex = cursor.getColumnIndex(Contacts.LOOKUP_KEY);  
  15. Log.e("LookupKey Index:""" + starIndex);  
  16. lookupkey = cursor.getString(starIndex);  
  17.   
  18.  } while (cursor.moveToNext());  
  19.   
  20. }  
  21. cursor.close();  
  22. return lookupkey;  
  23. }  


这些内容多是我工作时,总结到Evernote的,可能不够详细,有什么不明白的欢迎交流。

今天就到这儿了,去洗个澡,明天又是新的一周,加油~


台风要来了,滴了些雨,顿时凉爽了很多。源码修改,继续。

有些Bug让人摸不着头脑,等发现了触发条件,就大致有了个分析方向,最后自然也可以找到原因。程序就是这么实在,什么反馈都是有原因的,真好。


49.解决ListView条目在应用初次启动时只能点击一次的情况,注释addFlags代码:

[java]  view plain  copy
  1. final Intent intent = new Intent(mPeopleActivity.this,  
  2. ViewContactActivity.class);  
  3. intent.setData(uri);  
  4. //intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  
  5. startActivity(intent);  

50.在Adapter的onTouch监听中设置View的Down和Up事件:
[java]  view plain  copy
  1. if (event.getAction() == MotionEvent.ACTION_DOWN) {  
  2. view.setBackgroundColor(Color.parseColor("#EBEBEB"));  
  3. return false;  
  4. else if (event.getAction() == MotionEvent.ACTION_UP) {  
  5. view.setBackgroundColor(Color.parseColor("#ffffff"));  
  6. }  

51.调整Bitmap对象的大小:

[java]  view plain  copy
  1. public void setPhoto(String contactId) {  
  2. // 以下代码将字节数组转化成Bitmap对象,然后再ImageView中显示出来  
  3. ImageButton ibAvatar = (ImageButton) this  
  4. .findViewById(com.android.dialer.R.id.zj_detail_avatar);  
  5. byte[] photo = getPhoto(contactId);  
  6. if (photo != null) {  
  7. Bitmap map = BitmapFactory.decodeByteArray(photo, 0, photo.length);  
  8. // 调整大小 START  
  9. int scaleWidth = 110;  
  10. int scaleHeight = 110;  
  11. Bitmap bitmap = Bitmap.createScaledBitmap(map, scaleWidth,  
  12. scaleHeight, true);  
  13. // 调整大小 END  
  14. ibAvatar.setImageBitmap(bitmap);      // 参数由原来的map换成转换过的bitmap  
  15. }  
  16. }  

52.调整Activity跳转动画的速度
改一下duration,500到300
[html]  view plain  copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <set xmlns:android="http://schemas.android.com/apk/res/android" >  
  3. <translate  
  4. android:duration="300"  
  5. android:fromXDelta="0"  
  6. android:toXDelta="100%p" />  
  7. </set>  


53.联系人列表标星Tag显示★而不是字母逻辑:
[java]  view plain  copy
  1. // 获得当前姓名的拼音首字母  
  2. String mfirstLetter = PinyinUtils  
  3. .getPingYin(Utils.mPersons.get(position).mName).substring(01)  
  4. .toUpperCase();  
  5. String zjContactIdStr = Utils.mPersons.get(position).mID;  
  6. boolean isStar = isStarred(zjContactIdStr);  
  7. String firstLetter;  
  8. Log.e("zjStar",  
  9. "position" + position + "\tcontactId"  
  10. + Utils.mPersons.get(position).mContactId + "\tName:"  
  11. + Utils.mPersons.get(position).mName + "\tisStar:"  
  12. + isStar);  
  13. if (isStar) {  
  14. firstLetter = "☆";  
  15. else {  
  16. firstLetter = notAlpha(mfirstLetter);  
  17. }  

54.联系人标星Tag去重(多个标星归档只显示一个Tag)逻辑
[java]  view plain  copy
  1. // 如果是第1个联系人 那么letterTag始终要显示  
  2. if (position == 0) {  
  3. myViews.letterTag.setVisibility(View.VISIBLE);  
  4. myViews.letterTag.setText(firstLetter);  
  5. else {  
  6. if (isStar) {  
  7. myViews.letterTag.setVisibility(View.GONE);  
  8. else {  
  9. // 获得上一个姓名的拼音首字母  
  10. String mfirstLetterPre = PinyinUtils  
  11. .getPingYin(Utils.mPersons.get(position - 1).mName)  
  12. .substring(01).toUpperCase();  
  13. String firstLetterPre = notAlpha(mfirstLetterPre);   
  14. // 比较一下两者是否相同  
  15. if (firstLetter.equals(firstLetterPre)) {  
  16. myViews.letterTag.setVisibility(View.GONE);  
  17. else {  
  18. myViews.letterTag.setVisibility(View.VISIBLE);  
  19. myViews.letterTag.setText(firstLetter);  
  20. }  
  21. }  
  22. }  

55.获得汉语拼音首字母
[java]  view plain  copy
  1. private String notAlpha(String str) {  
  2. if (str == null) {  
  3. return "#";  
  4. }  
  5. if (str.trim().length() == 0) {  
  6. return "#";  
  7. }  
  8. // 正则表达式,判断首字母是否是英文字母  
  9. Pattern pattern = Pattern.compile("^[A-Za-z]+$");  
  10. if (pattern.matcher(str).matches()) {  
  11. return (str).toUpperCase();  
  12. else {  
  13. return "#";  
  14. }  
  15. }  

56. 联系人列表右侧快速定位字母条监听
[java]  view plain  copy
  1. // 字母列触摸的监听器  
  2. private class ScrollBarListener implements  
  3. AlphabetScrollBar.OnTouchBarListener {  
  4. @Override  
  5. public void onTouch(String letter) {  
  6. if (letter.compareTo("☆") == 0) {  
  7. m_contactslist.setSelection(0); // 跳转到列表开始  
  8. else if (letter.compareTo("#") == 0) {  
  9. int zjCount = m_contactslist.getChildCount();  
  10. m_contactslist.setSelection(zjCount); // 跳转到列表最后位置  
  11. else {  
  12. // 触摸字母列时,将联系人列表更新到首字母出现的位置  
  13. int idx = Utils.binarySearch(letter);  
  14. if (idx != -1) {  
  15. m_contactslist.setSelection(idx);  
  16. }  
  17. }  
  18. }  
  19. }  

57.搜索联系人过滤器
[java]  view plain  copy
  1. public void FilterSearch(String keyword) {  
  2. mFilterList.clear();  
  3. // 遍历mArrayList  
  4. for (int i = 0; i < Utils.mPersons.size(); i++) {  
  5. // 如果遍历到List包含所输入字符串  
  6. boolean isSearchNum = Utils.mPersons.get(i).mNum == null ? false  
  7. : (Utils.mPersons.get(i).mNum.indexOf(keyword) > 0);  
  8. if (isSearchNum// 为空时 报错  
  9. || isStrInString(Utils.mPersons.get(i).mPY, keyword)  
  10. || Utils.mPersons.get(i).mName.contains(keyword)  
  11. || isStrInString(Utils.mPersons.get(i).mFisrtSpell, keyword)) {  
  12. // 将遍历到的元素重新组成一个list  
  13. SortEntry entry = new SortEntry();  
  14. entry.mName = Utils.mPersons.get(i).mName;  
  15. entry.mID = Utils.mPersons.get(i).mID;  
  16. entry.mOrder = i; // 在原Cursor中的位置  
  17. entry.mPY = Utils.mPersons.get(i).mPY;  
  18. entry.mNum = Utils.mPersons.get(i).mNum;  
  19. mFilterList.add(entry);  
  20. }  
  21. }  
  22. }  

58.长按多选联系人群发短信逻辑

[java]  view plain  copy
  1. private class MultiSmsTask extends AsyncTask<Void, Integer, Void> {  
  2.   
  3. @Override  
  4. protected Void doInBackground(Void... params) {  
  5. ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();  
  6. for (int i = 0; i < ChooseContactsID.size(); i++) {  
  7. // ops.add(ContentProviderOperation.newDelete(Uri.withAppendedPath(RawContacts.CONTENT_URI,  
  8. // ChooseContactsID.get(i))).build());  
  9. String contactId = ChooseContactsID.get(i);  
  10. zjSmsNum = zjSmsNum + getNumByContactId(contactId)+";";  
  11. }  
  12. Log.e("zj""zjSmsNum:" + zjSmsNum + " ZJSmsCount:"  
  13. + ChooseContactsID.size());  
  14. //   
  15. Uri uri = Uri.parse("smsto:" + zjSmsNum);  
  16. Intent it = new Intent(Intent.ACTION_SENDTO, uri);  
  17. startActivity(it);  
  18. /* 
  19. * try { getContentResolver() 
  20. * .applyBatch(ContactsContract.AUTHORITY, ops); 
  21. * //Log.e("ZJSmsCount", "" + ChooseContactsID.size()); } catch 
  22. * (RemoteException e) { // TODO Auto-generated catch block 
  23. * e.printStackTrace(); } catch (OperationApplicationException e) { 
  24. * // TODO Auto-generated catch block e.printStackTrace(); } 
  25. */  
  26. return null;  
  27. }  
  28.   
  29.   
  30. @Override  
  31. protected void onPostExecute(Void result) {  
  32. if (m_dialogLoading != null) {  
  33. m_dialogLoading.dismiss();  
  34. finish();  
  35. }  
  36. }  
  37.   
  38.   
  39. @Override  
  40. protected void onPreExecute() {  
  41. m_dialogLoading = new ProgressDialog(MultiDeleteActivity.this);  
  42. m_dialogLoading.setProgressStyle(ProgressDialog.STYLE_SPINNER);// 设置风格为圆形进度条  
  43. m_dialogLoading.setMessage("正在发送");  
  44. m_dialogLoading.setCancelable(false);  
  45. m_dialogLoading.show();  
  46. }  
  47.   
  48.   
  49. @Override  
  50. protected void onProgressUpdate(Integer... values) {  
  51. }  
  52. }  

到此问题解决的差不多了,明天再写一篇估计就可以完结这个系列。以后遇到问题再补充,有不明白的地方欢迎交流。

今天就到这儿吧,学习的脚步不能停止,加油。


完结篇~

今天工作感觉挺累的,就没有加班在,早早的溜回来,看了会儿蓝牙的资料。不知不觉都9点了,开始~


59.B应用要用A应用的Activity2,但Activity2依赖于A应用的Activity1,也就是说Activity2要使用Activity1处理后的数据,这时候可以让B应用跳转到一个Activity3,Activity3和Activity1内容相同,但是在onResume中写下跳转到Activity2的逻辑:

[java]  view plain  copy
  1. protected void onResume() {  
  2. // TODO Auto-generated method stub  
  3. super.onResume();  
  4. Intent intent = new Intent(this, MultiChoiseSecond.class);  
  5. startActivity(intent);  
  6. finish();  
  7. }  

60.加快拨号面板号码匹配响应时间

[java]  view plain  copy
  1. // at com.android.dialer.dialpad.DialpadFragment.java  
  2.   
  3. public void afterTextChanged(Editable input) {  
  4. // When DTMF dialpad buttons are being pressed, we delay  
  5. // SpecialCharSequencMgr sequence,  
  6. // since some of SpecialCharSequenceMgr's behavior is too abrupt for the  
  7. // "touch-down"  
  8. // behavior.  
  9. inputstring = input.toString();  
  10. // mHandler.postDelayed(mrunnable, 2000);//czq  
  11. mHandler.postDelayed(mrunnable, 100); // zj  
  12. }  

61.加快三个应用间Activity的跳转速度

[html]  view plain  copy
  1. android:launchMode="singleTask"  


62.让应用不显示在最近运行程序列表中
在主activity处设置属性:

[html]  view plain  copy
  1. android:excludeFromRecents=“true”  


63.解决页面之间跳转时的短暂黑屏问题

[html]  view plain  copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <resources>   
  3. <style name="activityTheme" parent="@android:style/Theme">   
  4. <item name="android:windowIsTranslucent">true</item> (zj:这一个item就够了)  
  5. </style>   
  6. </resources>  

64.最小化应用(注释代码为杀死应用)

[java]  view plain  copy
  1. // Intent intent = new Intent(Intent.ACTION_MAIN);  
  2. // intent.addCategory(Intent.CATEGORY_HOME);  
  3. // intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);  
  4. // startActivity(intent);  
  5. // android.os.Process.killProcess(android.os.Process.myPid());  
  6. Intent intent = new Intent(Intent.ACTION_MAIN);  
  7. intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  
  8. intent.addCategory(Intent.CATEGORY_HOME);  
  9. startActivity(intent);  


65.获取Log
权限:

[html]  view plain  copy
  1. <uses-permission android:name=”android.permission.READ_LOGS” />  

[java]  view plain  copy
  1. new Thread(new Runnable()  
  2. {  
  3. @Override  
  4. public void run()  
  5. {  
  6. Process logcatProcess = null;  
  7. BufferedReader bufferedReader = null;  
  8. try  
  9. {  
  10. /** 获取系统logcat日志信息 */  
  11. logcatProcess = Runtime.getRuntime().exec(new String[] {“logcat”, “ActivityManager:I *:S”});  
  12. bufferedReader = new BufferedReader(new InputStreamReader(logcatProcess.getInputStream()));  
  13.   
  14. String line;  
  15.   
  16. while ((line = bufferedReader.readLine()) != null)  
  17. {  
  18. if (line.indexOf(“cat=[android.intent.category.HOME]“) > 0)  
  19. {  
  20. Session.exit();  
  21. }  
  22. }  
  23.   
  24. }  
  25. catch (Exception e)  
  26. {  
  27. e.printStackTrace();  
  28. }  
  29. }  
  30. }).start();  

今天的内容相对较少,目前项目还存在一些待优化的问题,以后再跟进补充。


66.通话记录ListView实现左滑发短信和右滑打电话

下午公司篮球赛最后一场,超神队一分憾败。可惜,不过比赛归比赛,重要的是过程中的精彩。

通话记录向左滑动发短信,向右滑动打电话,微信电话本上有这个很便捷的操作,在项目的修改过程中,就仿造微信的交互方式,实现了ListView左右滑动,今天总结一下:

同样由于是在源码环境下编译,所以代码中的资源引用之类地方的可能和常规的稍微不同。

[java]  view plain  copy
  1. // 滑动之后的回调方法  
  2.     @Override  
  3.     public void removeItem(RemoveDirection direction, int position) {  
  4.         String sildeNum = callLogs.get(position).getNumber(); // zj:获取滑动Item的号码  
  5.   
  6.         switch (direction) {  
  7.         case RIGHT:  
  8.   
  9.             tvTopBar.setBackgroundColor(Color.parseColor("#454545"));  
  10.             tvTopBar.setText(com.android.dialer.R.string.call_log_activity_title);  
  11.             RecordSlideListView.itemView.setBackgroundColor(Color  
  12.                     .parseColor("#ffffff"));  
  13.             Uri uri = Uri.parse("tel:" + sildeNum);  
  14.             Intent intent = new Intent(Intent.ACTION_CALL, uri);  
  15.             startActivity(intent);  
  16.             break;  
  17.         case LEFT:  
  18.             // Toast.makeText(this, "向左短信  "+ position,  
  19.             // Toast.LENGTH_SHORT).show();  
  20.             // rlRecordBack.setBackgroundColor(Color.parseColor("#1C86EE"));  
  21.             tvTopBar.setBackgroundColor(Color.parseColor("#454545"));  
  22.             tvTopBar.setText(com.android.dialer.R.string.call_log_activity_title);  
  23.             RecordSlideListView.itemView.setBackgroundColor(Color  
  24.                     .parseColor("#ffffff"));  
  25.             Uri uri2 = Uri.parse("smsto:" + sildeNum);  
  26.             Intent intent2 = new Intent(Intent.ACTION_SENDTO, uri2);  
  27.             startActivity(intent2);  
  28.             break;  
  29.   
  30.         default:  
  31.             break;  
  32.         }  
  33.     }  


自定义组件SlideListView:

[java]  view plain  copy
  1. package com.android.dialer.calllog;  
  2.   
  3. import android.content.Context;  
  4. import android.graphics.Color;  
  5. import android.util.AttributeSet;  
  6. import android.view.MotionEvent;  
  7. import android.view.VelocityTracker;  
  8. import android.view.View;  
  9. import android.view.ViewConfiguration;  
  10. import android.view.WindowManager;  
  11. import android.widget.AdapterView;  
  12. import android.widget.ListView;  
  13. import android.widget.Scroller;  
  14. import android.widget.TextView;  
  15.   
  16. public class RecordSlideListView extends ListView {  
  17.   
  18.   
  19.     private int slidePosition;  
  20.     private int downY;  
  21.     private int downX;  
  22.     private int screenWidth;  
  23.     public static View itemView;  
  24.     private Scroller scroller;  
  25.     private static final int SNAP_VELOCITY = 300;  
  26.     private VelocityTracker velocityTracker;  
  27.     private boolean isSlide = false;  
  28.     private int mTouchSlop;  
  29.     private RemoveListener mRemoveListener;  
  30.     private RemoveDirection removeDirection;  
  31.   
  32.     public enum RemoveDirection {  
  33.         RIGHT, LEFT;  
  34.     }  
  35.   
  36.     public RecordSlideListView(Context context) {  
  37.         this(context, null);  
  38.     }  
  39.   
  40.     public RecordSlideListView(Context context, AttributeSet attrs) {  
  41.         this(context, attrs, 0);  
  42.     }  
  43.   
  44.     public RecordSlideListView(Context context, AttributeSet attrs, int defStyle) {  
  45.         super(context, attrs, defStyle);  
  46.         screenWidth = ((WindowManager) context  
  47.                 .getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay()  
  48.                 .getWidth();  
  49.         scroller = new Scroller(context);  
  50.         mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();  
  51.     }  
  52.   
  53.     public void setRemoveListener(RemoveListener removeListener) {  
  54.         this.mRemoveListener = removeListener;  
  55.     }  
  56.   
  57.     @Override  
  58.     public boolean dispatchTouchEvent(MotionEvent event) {  
  59.         switch (event.getAction()) {  
  60.         case MotionEvent.ACTION_DOWN: {  
  61.             addVelocityTracker(event);  
  62.   
  63.             if (!scroller.isFinished()) {  
  64.                 return super.dispatchTouchEvent(event);  
  65.             }  
  66.             downX = (int) event.getX();  
  67.             downY = (int) event.getY();  
  68.   
  69.             slidePosition = pointToPosition(downX, downY);  
  70.   
  71.             if (slidePosition == AdapterView.INVALID_POSITION) {  
  72.                 return super.dispatchTouchEvent(event);  
  73.             }  
  74.   
  75.             itemView = getChildAt(slidePosition - getFirstVisiblePosition());  
  76.             break;  
  77.         }  
  78.         case MotionEvent.ACTION_MOVE: {  
  79.             if (Math.abs(getScrollVelocity()) > SNAP_VELOCITY  
  80.                     || (Math.abs(event.getX() - downX) > mTouchSlop && Math  
  81.                             .abs(event.getY() - downY) < mTouchSlop)) {  
  82.                 isSlide = true;  
  83.             }  
  84.             break;  
  85.         }  
  86.         case MotionEvent.ACTION_UP:  
  87.             recycleVelocityTracker();  
  88.             break;  
  89.         }  
  90.   
  91.         return super.dispatchTouchEvent(event);  
  92.     }  
  93.   
  94.     private void scrollRight() {  
  95.   
  96.         // tvTopBar =  
  97.         // (TextView)findViewById(com.android.dialer.R.id.textViewRecord);  
  98.         // tvTopBar.setBackgroundColor(Color.parseColor("#32CD32"));  
  99.         // tvTopBar.setText(com.android.dialer.R.string.zj_slide_right_to_call);  
  100.   
  101.         removeDirection = RemoveDirection.RIGHT;  
  102.         final int delta = (screenWidth + itemView.getScrollX());  
  103.         scroller.startScroll(itemView.getScrollX(), 0, -delta, 0,  
  104.                 Math.abs(delta));  
  105.         postInvalidate();  
  106.     }  
  107.   
  108.   
  109.     private void scrollLeft() {  
  110.   
  111.         removeDirection = RemoveDirection.LEFT;  
  112.         final int delta = (screenWidth - itemView.getScrollX());  
  113.         scroller.startScroll(itemView.getScrollX(), 0, delta, 0,  
  114.                 Math.abs(delta));  
  115.         postInvalidate();  
  116.     }  
  117.   
  118.     private void scrollByDistanceX() {  
  119.         if (itemView.getScrollX() >= screenWidth / 3) {  
  120.             scrollLeft();  
  121.         } else if (itemView.getScrollX() <= -screenWidth / 3) {  
  122.             scrollRight();  
  123.         } else {  
  124.             itemView.scrollTo(00);  
  125.             // zj:恢复Topbar的字和背景颜色  
  126.             itemView.setBackgroundColor(Color.parseColor("#ffffff"));  
  127.             Record.tvTopBar.setBackgroundColor(Color.parseColor("#454545"));  
  128.             Record.tvTopBar  
  129.                     .setText(com.android.dialer.R.string.call_log_activity_title);  
  130.         }  
  131.     }  
  132.   
  133.     @Override  
  134.     public boolean onTouchEvent(MotionEvent ev) {  
  135.         if (isSlide && slidePosition != AdapterView.INVALID_POSITION) {  
  136.   
  137.             addVelocityTracker(ev);  
  138.             final int action = ev.getAction();  
  139.             int x = (int) ev.getX();  
  140.             switch (action) {  
  141.             case MotionEvent.ACTION_MOVE:  
  142.                 int deltaX = downX - x;  
  143.                 downX = x;  
  144.   
  145.                 if (deltaX > 20) { // 向左sms #D1EEEE  
  146.                     itemView.setBackgroundColor(Color.parseColor("#D1EEEE"));  
  147.                     Record.tvTopBar.setBackgroundColor(Color  
  148.                             .parseColor("#1C86EE"));  
  149.                     Record.tvTopBar  
  150.                             .setText(com.android.dialer.R.string.zj_slide_left_to_sms);  
  151.   
  152.                 } else if (deltaX < -20) { // 向右call  
  153.                     itemView.setBackgroundColor(Color.parseColor("#D1EEEE"));  
  154.                     Record.tvTopBar.setBackgroundColor(Color  
  155.                             .parseColor("#32CD32"));  
  156.                     Record.tvTopBar  
  157.                             .setText(com.android.dialer.R.string.zj_slide_right_to_call);  
  158.   
  159.                 }  
  160.           
  161.                 itemView.scrollBy(deltaX, 0);  
  162.                 return true// 拖动的时候ListView不滚动  
  163.                 // break;  
  164.             case MotionEvent.ACTION_UP:  
  165.                 int velocityX = getScrollVelocity();  
  166.                 if (velocityX > SNAP_VELOCITY) {  
  167.                     scrollRight();  
  168.                 } else if (velocityX < -SNAP_VELOCITY) {  
  169.                     scrollLeft();  
  170.                 } else {  
  171.                     scrollByDistanceX();  
  172.                 }  
  173.   
  174.                 recycleVelocityTracker();  
  175.                 isSlide = false;  
  176.                 break;  
  177.             }  
  178.   
  179.             return true;  
  180.         }  
  181.         return super.onTouchEvent(ev);  
  182.     }  
  183.   
  184.     @Override  
  185.     public void computeScroll() {  
  186.         if (scroller.computeScrollOffset()) {  
  187.             itemView.scrollTo(scroller.getCurrX(), scroller.getCurrY());  
  188.   
  189.             postInvalidate();  
  190.   
  191.             if (scroller.isFinished()) {  
  192.                 if (mRemoveListener == null) {  
  193.                     throw new NullPointerException(  
  194.                             "RemoveListener is null, we should called setRemoveListener()");  
  195.                 }  
  196.   
  197.                 itemView.scrollTo(00);  
  198.                 mRemoveListener.removeItem(removeDirection, slidePosition);  
  199.             }  
  200.         }  
  201.     }  
  202.   
  203.   
  204.     private void addVelocityTracker(MotionEvent event) {  
  205.         if (velocityTracker == null) {  
  206.             velocityTracker = VelocityTracker.obtain();  
  207.         }  
  208.   
  209.         velocityTracker.addMovement(event);  
  210.     }  
  211.   
  212.   
  213.     private void recycleVelocityTracker() {  
  214.         if (velocityTracker != null) {  
  215.             velocityTracker.recycle();  
  216.             velocityTracker = null;  
  217.         }  
  218.     }  
  219.   
  220.   
  221.     private int getScrollVelocity() {  
  222.         velocityTracker.computeCurrentVelocity(1000);  
  223.         int velocity = (int) velocityTracker.getXVelocity();  
  224.         return velocity;  
  225.     }  
  226.   
  227.   
  228.     public interface RemoveListener {  
  229.         public void removeItem(RemoveDirection direction, int position);  
  230.     }  
  231.   
  232. }  


代码有点长,Adapter的就先不贴了。


67.黑名单来电拦截自动挂断

准备工作:

添加一个名为android.telephony的包,里面有个NeighboringCellInfo.aidl,内容如下:

[java]  view plain  copy
  1. /* //device/java/android/android/content/Intent.aidl 
  2. ** 
  3. ** Copyright 2007, The Android Open Source Project 
  4. ** 
  5. ** Licensed under the Apache License, Version 2.0 (the "License"); 
  6. ** you may not use this file except in compliance with the License. 
  7. ** You may obtain a copy of the License at 
  8. ** 
  9. **     http://www.apache.org/licenses/LICENSE-2.0 
  10. ** 
  11. ** Unless required by applicable law or agreed to in writing, software 
  12. ** distributed under the License is distributed on an "AS IS" BASIS, 
  13. ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  14. ** See the License for the specific language governing permissions and 
  15. ** limitations under the License. 
  16. */  
  17.   
  18. package android.telephony;  
  19.   
  20. parcelable NeighboringCellInfo;  

新建包名为com.android.internal.telephony的包,新建文件ITelephony.aidl,文件内容如下:

[java]  view plain  copy
  1. /* 
  2.  * Copyright (C) 2007 The Android Open Source Project 
  3.  * 
  4.  * Licensed under the Apache License, Version 2.0 (the "License"); 
  5.  * you may not use this file except in compliance with the License. 
  6.  * You may obtain a copy of the License at 
  7.  * 
  8.  *      http://www.apache.org/licenses/LICENSE-2.0 
  9.  * 
  10.  * Unless required by applicable law or agreed to in writing, software 
  11.  * distributed under the License is distributed on an "AS IS" BASIS, 
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  13.  * See the License for the specific language governing permissions and 
  14.  * limitations under the License. 
  15.  */  
  16.   
  17. package com.android.internal.telephony;  
  18.   
  19. import android.os.Bundle;  
  20. import java.util.List;  
  21. import android.telephony.NeighboringCellInfo;  
  22.   
  23. /** 
  24.  * Interface used to interact with the phone.  Mostly this is used by the  
  25.  * TelephonyManager class.  A few places are still using this directly. 
  26.  * Please clean them up if possible and use TelephonyManager insteadl. 
  27.  * 
  28.  * {@hide} 
  29.  */  
  30. interface ITelephony {  
  31.   
  32.     /** 
  33.      * Dial a number. This doesn't place the call. It displays 
  34.      * the Dialer screen. 
  35.      * @param number the number to be dialed. If null, this 
  36.      * would display the Dialer screen with no number pre-filled. 
  37.      */  
  38.     void dial(String number);  
  39.   
  40.     /** 
  41.      * Place a call to the specified number. 
  42.      * @param number the number to be called. 
  43.      */  
  44.     void call(String number);  
  45.   
  46.     /** 
  47.      * If there is currently a call in progress, show the call screen. 
  48.      * The DTMF dialpad may or may not be visible initially, depending on 
  49.      * whether it was up when the user last exited the InCallScreen. 
  50.      * 
  51.      * @return true if the call screen was shown. 
  52.      */  
  53.     boolean showCallScreen();  
  54.   
  55.     /** 
  56.      * Variation of showCallScreen() that also specifies whether the 
  57.      * DTMF dialpad should be initially visible when the InCallScreen 
  58.      * comes up. 
  59.      * 
  60.      * @param showDialpad if true, make the dialpad visible initially, 
  61.      *                    otherwise hide the dialpad initially. 
  62.      * @return true if the call screen was shown. 
  63.      * 
  64.      * @see showCallScreen 
  65.      */  
  66.     boolean showCallScreenWithDialpad(boolean showDialpad);  
  67.   
  68.     /** 
  69.      * End call or go to the Home screen 
  70.      * 
  71.      * @return whether it hung up 
  72.      */  
  73.     boolean endCall();  
  74.   
  75.     /** 
  76.      * Answer the currently-ringing call. 
  77.      * 
  78.      * If there's already a current active call, that call will be 
  79.      * automatically put on hold.  If both lines are currently in use, the 
  80.      * current active call will be ended. 
  81.      * 
  82.      * TODO: provide a flag to let the caller specify what policy to use 
  83.      * if both lines are in use.  (The current behavior is hardwired to 
  84.      * "answer incoming, end ongoing", which is how the CALL button 
  85.      * is specced to behave.) 
  86.      * 
  87.      * TODO: this should be a oneway call (especially since it's called 
  88.      * directly from the key queue thread). 
  89.      */  
  90.     void answerRingingCall();  
  91.   
  92.     /** 
  93.      * Silence the ringer if an incoming call is currently ringing. 
  94.      * (If vibrating, stop the vibrator also.) 
  95.      * 
  96.      * It's safe to call this if the ringer has already been silenced, or 
  97.      * even if there's no incoming call.  (If so, this method will do nothing.) 
  98.      * 
  99.      * TODO: this should be a oneway call too (see above). 
  100.      *       (Actually *all* the methods here that return void can 
  101.      *       probably be oneway.) 
  102.      */  
  103.     void silenceRinger();  
  104.   
  105.     /** 
  106.      * Check if we are in either an active or holding call 
  107.      * @return true if the phone state is OFFHOOK. 
  108.      */  
  109.     boolean isOffhook();  
  110.   
  111.     /** 
  112.      * Check if an incoming phone call is ringing or call waiting. 
  113.      * @return true if the phone state is RINGING. 
  114.      */  
  115.     boolean isRinging();  
  116.   
  117.     /** 
  118.      * Check if the phone is idle. 
  119.      * @return true if the phone state is IDLE. 
  120.      */  
  121.     boolean isIdle();  
  122.   
  123.     /** 
  124.      * Check to see if the radio is on or not. 
  125.      * @return returns true if the radio is on. 
  126.      */  
  127.     boolean isRadioOn();  
  128.   
  129.     /** 
  130.      * Check if the SIM pin lock is enabled. 
  131.      * @return true if the SIM pin lock is enabled. 
  132.      */  
  133.     boolean isSimPinEnabled();  
  134.   
  135.     /** 
  136.      * Cancels the missed calls notification. 
  137.      */  
  138.     void cancelMissedCallsNotification();   
  139.   
  140.     /** 
  141.      * Supply a pin to unlock the SIM.  Blocks until a result is determined. 
  142.      * @param pin The pin to check. 
  143.      * @return whether the operation was a success. 
  144.      */  
  145.     boolean supplyPin(String pin);  
  146.   
  147.     /** 
  148.      * Handles PIN MMI commands (PIN/PIN2/PUK/PUK2), which are initiated 
  149.      * without SEND (so <code>dial</code> is not appropriate). 
  150.      *  
  151.      * @param dialString the MMI command to be executed. 
  152.      * @return true if MMI command is executed. 
  153.      */  
  154.     boolean handlePinMmi(String dialString);  
  155.   
  156.     /** 
  157.      * Toggles the radio on or off. 
  158.      */  
  159.     void toggleRadioOnOff();  
  160.   
  161.     /** 
  162.      * Set the radio to on or off 
  163.      */  
  164.     boolean setRadio(boolean turnOn);  
  165.   
  166.     /** 
  167.      * Request to update location information in service state 
  168.      */  
  169.     void updateServiceLocation();  
  170.   
  171.     /** 
  172.      * Enable location update notifications. 
  173.      */  
  174.     void enableLocationUpdates();  
  175.   
  176.     /** 
  177.      * Disable location update notifications. 
  178.      */  
  179.     void disableLocationUpdates();  
  180.   
  181.     /** 
  182.      * Enable a specific APN type. 
  183.      */  
  184.     int enableApnType(String type);  
  185.   
  186.     /** 
  187.      * Disable a specific APN type. 
  188.      */  
  189.     int disableApnType(String type);  
  190.   
  191.     /** 
  192.      * Allow mobile data connections. 
  193.      */  
  194.     boolean enableDataConnectivity();  
  195.   
  196.     /** 
  197.      * Disallow mobile data connections. 
  198.      */  
  199.     boolean disableDataConnectivity();  
  200.   
  201.     /** 
  202.      * Report whether data connectivity is possible. 
  203.      */  
  204.     boolean isDataConnectivityPossible();  
  205.   
  206.     Bundle getCellLocation();  
  207.   
  208.     /** 
  209.      * Returns the neighboring cell information of the device. 
  210.      */  
  211.     List<NeighboringCellInfo> getNeighboringCellInfo();  
  212.   
  213.      int getCallState();  
  214.      int getDataActivity();  
  215.      int getDataState();  
  216. }  

广播:

[java]  view plain  copy
  1. /* 
  2.  * Add By ZJ For Blacklist 
  3.  */  
  4. package com.android.dialer.calllog;  
  5.   
  6. import android.content.BroadcastReceiver;  
  7. import android.content.Context;  
  8. import android.content.Intent;  
  9.   
  10. public class BlacklistBroadcast extends BroadcastReceiver{  
  11.       
  12.     @Override  
  13.     public void onReceive(Context context, Intent intent) {  
  14.           
  15.         // TODO Auto-generated method stub  
  16.         if (intent.getAction().equals(  
  17.                 Intent.ACTION_NEW_OUTGOING_CALL)){  
  18.         }  
  19.         else{  
  20.             Intent Sbintent = new Intent(context,com.android.dialer.calllog.BlacklistService.class);  
  21.             context.startService(Sbintent);  
  22.         }  
  23.     }  
  24.   
  25. }  

DbHelper:

[java]  view plain  copy
  1. /* 
  2.  * Add By ZJ For Blacklist 
  3.  */  
  4. package com.android.dialer.calllog;  
  5.   
  6. import android.content.Context;  
  7. import android.database.Cursor;  
  8. import android.database.sqlite.SQLiteDatabase.CursorFactory;  
  9. import android.database.sqlite.SQLiteDatabase;  
  10. import android.database.sqlite.SQLiteOpenHelper;  
  11.   
  12. public class BlacklistDbHelper extends SQLiteOpenHelper{  
  13.     final String CREATE_TABLE_SQL =  
  14.             "create table blacklist(_id integer primary key autoincrement , number text)";  
  15.     public BlacklistDbHelper(Context context, String name,  
  16.             CursorFactory factory, int version) {  
  17.         super(context, name, factory, version);  
  18.         // TODO Auto-generated constructor stub  
  19.     }@Override  
  20.     public void onCreate(SQLiteDatabase db) {  
  21.         // TODO Auto-generated method stub  
  22.         db.execSQL(CREATE_TABLE_SQL);  
  23.     }  
  24.     @Override  
  25.     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {  
  26.         // TODO Auto-generated method stub  
  27.           
  28.     }  
  29.     //zj add START  
  30.     public Cursor getCursorByNumber(String number) {  
  31.         String selectQuery = "SELECT * FROM blacklist where number = "+number;  
  32.   
  33.         SQLiteDatabase db = this.getReadableDatabase();  
  34.         Cursor cursor = db.rawQuery(selectQuery, null);  
  35.         return cursor;  
  36.     }  
  37.     //zj add END  
  38.   
  39. }  



Service:

[java]  view plain  copy
  1. /* 
  2.  * Add By ZJ For Blacklist 
  3.  */  
  4. package com.android.dialer.calllog;  
  5.   
  6. import java.lang.reflect.Method;  
  7.   
  8. import com.android.internal.telephony.ITelephony;  
  9. import android.app.Service;  
  10. import android.content.Intent;  
  11. import android.database.Cursor;  
  12. import android.os.IBinder;  
  13. import android.telephony.PhoneStateListener;  
  14. import android.telephony.TelephonyManager;  
  15.   
  16. public class BlacklistService extends Service {  
  17.     BlacklistDbHelper dbHelper = new BlacklistDbHelper(this"blacklist.db",  
  18.             null1);  
  19.     TelephonyManager tManager;  
  20.     CustomPhoneCallListener cpListener;  
  21.   
  22.     public class CustomPhoneCallListener extends PhoneStateListener {  
  23.         @Override  
  24.         public void onCallStateChanged(int state, String incomingNumber) {  
  25.             switch (state) {  
  26.             case TelephonyManager.CALL_STATE_IDLE:  
  27.                 break;  
  28.             case TelephonyManager.CALL_STATE_OFFHOOK:  
  29.                 break;  
  30.             case TelephonyManager.CALL_STATE_RINGING:  
  31.                 System.out.println("this is 1");  
  32.                 if (isBlock(incomingNumber)) {  
  33.                     System.out.println("this is 2");  
  34.                     try {  
  35.                         Method method = Class.forName(  
  36.                                 "android.os.ServiceManager").getMethod(  
  37.                                 "getService", String.class);  
  38.                         IBinder binder = (IBinder) method.invoke(null,  
  39.                                 new Object[] { TELEPHONY_SERVICE });  
  40.                         ITelephony telephony = ITelephony.Stub  
  41.                                 .asInterface(binder);  
  42.                         telephony.endCall();  
  43.                     } catch (Exception e) {  
  44.                         e.printStackTrace();  
  45.                     }  
  46.                 }  
  47.                 break;  
  48.   
  49.             }  
  50.             super.onCallStateChanged(state, incomingNumber);  
  51.         }  
  52.   
  53.         public boolean isBlock(String number) {  
  54.             Cursor cursor = dbHelper.getReadableDatabase().rawQuery(  
  55.                     "select * from blacklist"null);  
  56.             while (cursor.moveToNext()) {  
  57.                 if (cursor.getString(1).equals(number)) {  
  58.                     return true;  
  59.                 }  
  60.             }  
  61.             return false;  
  62.         }  
  63.     }  
  64.   
  65.     @Override  
  66.     public IBinder onBind(Intent arg0) {  
  67.         // TODO Auto-generated method stub  
  68.         return null;  
  69.     }  
  70.   
  71.     @Override  
  72.     public void onStart(Intent intent, int startId) {  
  73.         // TODO Auto-generated method stub  
  74.         tManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);  
  75.         cpListener = new CustomPhoneCallListener();  
  76.         tManager.listen(cpListener, PhoneStateListener.LISTEN_CALL_STATE);  
  77.         super.onStart(intent, startId);  
  78.     }  
  79.   
  80. }  

ListView:

[java]  view plain  copy
  1. /* 
  2.  * Add By ZJ For Blacklist 
  3.  */  
  4. package com.android.dialer.calllog;  
  5.   
  6. import java.util.ArrayList;  
  7. import java.util.List;  
  8.   
  9. import android.app.Activity;  
  10. import android.content.ContentResolver;  
  11. import android.content.ContentUris;  
  12. import android.content.Intent;  
  13. import android.database.Cursor;  
  14. import android.database.sqlite.SQLiteDatabase;  
  15. import android.net.Uri;  
  16. import android.os.Bundle;  
  17. import android.provider.CallLog;  
  18. import android.provider.Contacts;  
  19. import android.view.Menu;  
  20. import android.view.MenuItem;  
  21. import android.view.View;  
  22. import android.widget.AdapterView;  
  23. import android.widget.AdapterView.OnItemClickListener;  
  24. import android.widget.ArrayAdapter;  
  25. import android.widget.ListView;  
  26. import android.widget.TextView;  
  27. import android.widget.Toast;  
  28. import android.app.ActionBar; // for ActionBar  
  29.   
  30. public class BlacklistView extends Activity {  
  31.   
  32.     public int version = Integer.valueOf(android.os.Build.VERSION.SDK);  
  33.     BlacklistDbHelper dbHelper;  
  34.   
  35.     @Override  
  36.     protected void onCreate(Bundle savedInstanceState) {  
  37.         // TODO Auto-generated method stub  
  38.         super.onCreate(savedInstanceState);  
  39.         setContentView(com.android.dialer.R.layout.zj_blacklist_result);  
  40.         dbHelper = new BlacklistDbHelper(this"blacklist.db"null1);  
  41.         final ListView listview = (ListView) findViewById(com.android.dialer.R.id.zj_blacklist_view);  
  42.         listview.setAdapter(new ArrayAdapter<String>(this,  
  43.                 com.android.dialer.R.layout.zj_blacklist_item, getData()));  
  44.   
  45.         TextView tvHint = (TextView) findViewById(com.android.dialer.R.id.zj_balcklist_hint);  
  46.         TextView tvEmpty = (TextView) findViewById(com.android.dialer.R.id.zj_blacklist_empty);  
  47.   
  48.         if (getData().isEmpty()) {  
  49.             // Toast.makeText(BlacklistView.this, "暂无黑名单", 5000).show();  
  50.   
  51.             tvEmpty.setVisibility(View.VISIBLE);  
  52.             tvHint.setVisibility(View.GONE);  
  53.             // Intent intent = new Intent(BlacklistView.this,  
  54.             // com.android.dialer.calllog.BlacklistChoice.class);  
  55.             // intent.putExtra("number", "kong");  
  56.             // startActivity(intent);  
  57.             // finish();  
  58.         } else {  
  59.             tvEmpty.setVisibility(View.GONE);  
  60.             tvHint.setVisibility(View.VISIBLE);  
  61.         }  
  62.         listview.setOnItemClickListener(new OnItemClickListener() {  
  63.   
  64.             @Override  
  65.             public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,  
  66.                     long arg3) {  
  67.                 String phoneNum = arg0.getItemAtPosition(arg2).toString();  
  68.                 dbHelper.getReadableDatabase().execSQL(  
  69.                         "delete from blacklist where number = ?",  
  70.                         new String[] { phoneNum });  
  71.                 onCreate(null);  
  72.   
  73.             }  
  74.         });  
  75.   
  76.         // actionBar  
  77.         ActionBar actionBar = getActionBar();  
  78.         actionBar.setHomeButtonEnabled(true);  
  79.         actionBar.setDisplayHomeAsUpEnabled(true);  
  80.         actionBar.setDisplayShowHomeEnabled(true);  
  81.   
  82.     }  
  83.   
  84.     private List<String> getData() {  
  85.         List<String> data = new ArrayList<String>();  
  86.         Cursor cursor = dbHelper.getReadableDatabase().rawQuery(  
  87.                 "select * from blacklist"null);  
  88.         while (cursor.moveToNext()) {  
  89.             data.add(cursor.getString(1));  
  90.         }  
  91.         cursor.close(); // zj:close cursor  
  92.   
  93.         return data;  
  94.     }  
  95.   
  96.     @Override  
  97.     public boolean onCreateOptionsMenu(Menu menu) {  
  98.         // Inflate the menu; this adds items to the action bar if it is present.  
  99.         getMenuInflater().inflate(com.android.dialer.R.menu.zj_blacklist_view,  
  100.                 menu);  
  101.         return true;  
  102.     }  
  103.   
  104.     @Override  
  105.     public boolean onOptionsItemSelected(MenuItem item) {  
  106.         switch (item.getItemId()) {  
  107.         // add for action start  
  108.         case android.R.id.home:  
  109.             finish();  
  110.             // add for animation start  
  111.             if (version > 5) {  
  112.                 overridePendingTransition(  
  113.                         com.android.dialer.R.anim.zj_right_in,  
  114.                         com.android.dialer.R.anim.zj_right_out);  
  115.             }  
  116.             // add for animation end  
  117.             break;  
  118.         // add for action end  
  119.         case com.android.dialer.R.id.zj_blacklist_clear:  
  120.             dbHelper.getReadableDatabase().execSQL("delete from blacklist");  
  121.             onCreate(null);  
  122.             break;  
  123.   
  124.         default:  
  125.             break;  
  126.         }  
  127.         return true;  
  128.     }  
  129.   
  130. }  


操作:

[java]  view plain  copy
  1. case com.android.dialer.R.id.zj_add_blacklist:  
  2.             // 添加到黑名单  
  3.             BlacklistDbHelper dbHelper = new BlacklistDbHelper(this,  
  4.                     "blacklist.db"null1);  
  5.   
  6.             boolean isBlack = isNumBlack(number);  
  7.             // ToDo:判断  
  8.             if (isBlack) { // 已经添加  
  9.                 Toast.makeText(this, com.android.dialer.R.string.zj_alredy_add,  
  10.                         Toast.LENGTH_SHORT).show();  
  11.             } else {  
  12.                 dbHelper.getReadableDatabase().execSQL(  
  13.                         "insert into blacklist values(null , ?)",  
  14.                         new String[] { number });  
  15.                 ibAddBlack.setBackgroundDrawable(getResources().getDrawable(  
  16.                         com.android.dialer.R.drawable.zj_block_red));  
  17.                 Toast.makeText(this,  
  18.                         com.android.dialer.R.string.zj_add_blacklist_ok,  
  19.                         Toast.LENGTH_SHORT).show();  
  20.             }  
  21.             break;  

[java]  view plain  copy
  1. // 联系人是否在黑名单中?  
  2.     public boolean isNumBlack(String number) {  
  3.         BlacklistDbHelper dbHelper = new BlacklistDbHelper(this,  
  4.                 "blacklist.db"null1);  
  5.         Cursor countCur = dbHelper.getCursorByNumber(number);  
  6.         int numCount = 0;  
  7.         try {  
  8.             numCount = countCur.getCount(); // zj:查看是否已在黑名单  
  9.             Log.e("numCount""" + numCount);  
  10.   
  11.         } catch (Exception e) {  
  12.             // _db.onCreate(_db);  
  13.         } finally {  
  14.             countCur.close(); // zj close cursor  
  15.         }  
  16.         if (numCount > 0)  
  17.             return true;  
  18.         else  
  19.             return false;  
  20.   
  21.     }  

[java]  view plain  copy
  1. // 加入或移出黑名单  
  2. public void zjAddBlack(View v) {  
  3.     BlacklistDbHelper dbHelper = new BlacklistDbHelper(this,  
  4.             "blacklist.db"null1);  
  5.     boolean isBlack = isNumBlack(number);  
  6.     if (isBlack) {  
  7.         // 从黑名单移除号码  
  8.         dbHelper.getReadableDatabase().execSQL(  
  9.                 "delete from blacklist where number = ?",  
  10.                 new String[] { number });  
  11.         ibAddBlack.setBackgroundDrawable(getResources().getDrawable(  
  12.                 com.android.dialer.R.drawable.zj_block_grey));  
  13.         isBlack = false;  
  14.         Toast.makeText(this,  
  15.                 com.android.dialer.R.string.zj_del_blacklist_ok,  
  16.                 Toast.LENGTH_SHORT).show();  
  17.   
  18.     } else if (!isBlack) {  
  19.         // 添加到黑名单  
  20.         dbHelper.getReadableDatabase().execSQL(  
  21.                 "insert into blacklist values(null , ?)",  
  22.                 new String[] { number });  
  23.         ibAddBlack.setBackgroundDrawable(getResources().getDrawable(  
  24.                 com.android.dialer.R.drawable.zj_block_red));  
  25.         isBlack = true;  
  26.         Toast.makeText(this,  
  27.                 com.android.dialer.R.string.zj_add_blacklist_ok,  
  28.                 Toast.LENGTH_SHORT).show();  
  29.     }  
  30. }  

67.来电界面InCallUI的布局修改:

有个客户要让来电界面适应他们提供的皮套,这样的话,就要根据皮套的开窗来调节来电界面。而来电界面并不是在Dialer代码中,而是在pacakage/apps/InCallUI中,调节对应的布局文件。

编译的时候也要注意,不可以单独模块编译InCallUI,模块编译Dialer就会把InCallUI编译进去了。

packages/apps/InCallUI/res/layout/primary_call_info.xml

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值