第四天:拦截电话,还原短信,程序管理
2012-12-19 18:42
246 查看
1. 黑名单表 2. 白名单表 if(黑名单拦截){ }eles if(白名单拦截){ }else if(拒接模式){ 拦截所有的电话和短信 } 挂断电话: 一、copy两个aidl文件。 二、因为默认API是没有默认给我们暴露出来方法, 所以我们必须通过反射来做。所以通过反射调用挂断电话的方法。AIDL必须会。一共有七步。 try { Method method = Class.forName("android.os.ServiceManager").getMethod("getService", String.class); IBinder iBinder = (IBinder) method.invoke(null, new Object[]{TELEPHONY_SERVICE}); ITelephony iTelephony = ITelephony.Stub.asInterface(iBinder); iTelephony.endCall(); } catch (Exception e) { e.printStackTrace(); } 三、要加电话的权限 你发现你把电话拦截以后,还会在通话记录里面有记录,那么我们通过内容观察者 把它给删除。 因为这个记录产生在打电话1秒或者2S之后立生的,所以我们不知道什么时间调用, 所以用一个内容观察者,去观察它的数据库,如果发现数据库有变化,就去执行 相应的回调函数。 ////注册一个内容观察者 观察call_log的uri的信息 观察这个CallLog.Calls.CONTENT_URI 并对其子URI也观察true getContentResolver().registerContentObserver(CallLog.Calls.CONTENT_URI, true, new MyObserver(new Handler(), incomingNumber)); private class MyObserver extends ContentObserver{ private String incomingNumber; public MyObserver(Handler handler,String incomingNumber) { super(handler); this.incomingNumber = incomingNumber; } /** * 发现内容改变的时间调用 */ @Override public void onChange(boolean selfChange) { super.onChange(selfChange); deleteCallLog(incomingNumber); //当删除之后 ,我们再把它反注册掉,不能一直观察呀,多费内存呀。 getContentResolver().unregisterContentObserver(this); } } 拦截短信的话,应该在短信获取短信的广播接收者里面判断。 一个极为重要的问题你想在service里面开启一个activity,因为service是在任务栈外面的 你在外面想要开启里面的一个东西,这不可能吧。所以在加一句话 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 两个电话: 往外打电话是一个广播setResult(null) 外面往里面打电话用上面的方法。 我们拦截一些电话和短信容易,可是要根据内容来拦截,其实 是有一个大的数据库去匹配而已。 响一声电话主要练习了notifaction的应用。必须要学会notifaction的应用 重构对话框。 短信的备份和还原。 短信在哪个数据库里?在com.android.providers.telephony下面它和电话是在一起的 在databases下面有个。 首先你要研究短信的源码, 第一,去下载 第二,在system/app下全部是它的apk文件,在这里面可以反编译它。 反编译步骤: 第一、apktool d tt.apk 反编译出来资源文件(F:\安卓笔记\八、安卓核心基础\ziliao\apktool-install-windows-r04-brut1) 第二、反编译DEX文件,先解压apk,然后得到.dex文件,然后再说 dex2jar tt.dex 得到一个相应的jar包。(F:\安卓笔记\八、安卓核心基础\ziliao\dex2jar-0.0.7.11-SNAPSHOT) 第三、把那个得到的jar文件从jd-gui.exe打开。 复习ContentProvider看 db 和 other这两个项目。 根据配置文件会写URI。里面的具体内容怎么写,看源码。 它肯定是以这个开头content:// 今天你记住,调用任何内容提供者它的Uri一定都是以content://开头的。 我们从得到的编译文件可以知道: <provider android:name="SmsProvider" android:readPermission="android.permission.READ_SMS" android:writePermission="android.permission.WRITE_SMS" android:multiprocess="true" android:authorities="sms" /> 主机名是sms,所以content://sms/ 但是具体路径你还不知道看源码得知, sURLMatcher = new UriMatcher(-1); sURLMatcher.addURI("sms", null, 0); sURLMatcher.addURI("sms", "#", 1); sURLMatcher.addURI("sms", "inbox", 2); ..... 它是这样的。 你想要备份一个东西,时间肯定会比较长,肯定放在一子线程里面, 而activity和广播 的周期又太短,它们两个一旦结束,里面的所有 子线程也会结束,所以要把这个备份的操作放在一个服务里面。 //存储到SD卡上,这个方法应该抽离出来,首先判断SD存在不?然后判断挂载没有,然后再用环境变量得到SD卡目录 。 在子线程中不用handler发送消息也能调用界面UI。 Looper.prepare(); Toast.makeText(getApplicationContext(), "备份成功", 0).show(); Looper.loop(); 抽空研究一下轮询器。 自定义内容提供和去调用是我的弱项。 以前用pull解析 XML,现在用XmlSerializer解析。 子线程里面不能执行Toast,因为没有消息队列和Handler。 不过还是可以的。 备份是点击备份后,开启后台一个服务,用户可以去干其它,然后结束时间显示个Toast。 ContentValues是要插入到内容提供者里面的信息的。 在子线程里面显示Toast,有两种做法: 第一、通过Message发送给Handler,让主线线处理 第二、looper .prepare() loop() 还原进度。一个总值不好传过去,把Progress传过来。 所有的还原短信之前都把它先删除了。再还原。 /** * 备份 ,还原的业务方法。 * @author chen */ public class SmsInfoService { private Context context; public SmsInfoService(Context context) { this.context = context; } /** * 通过内容提供者,获得所有的短信内容 * @return */ public List<SmsInfo> getSmsInfos(){ List<SmsInfo> list = new ArrayList<SmsInfo>(); SmsInfo smsInfo = null; //得到内容解析者 ContentResolver resolver = context.getContentResolver(); Uri uri = Uri.parse("content://sms/"); //projection A list of which columns to return. Passing null will return all columns, which is inefficient. Cursor cursor = resolver.query(uri, new String[]{"_id","address","date","type","body"}, null, null, null); while (cursor.moveToNext()) { smsInfo = new SmsInfo(); String id = cursor.getString(cursor.getColumnIndex("_id")); String address = cursor.getString(cursor.getColumnIndex("address")); String date = cursor.getString(cursor.getColumnIndex("date")); String type = cursor.getString(cursor.getColumnIndex("type")); String body = cursor.getString(cursor.getColumnIndex("body")); smsInfo.setId(id); smsInfo.setAddress(address); smsInfo.setBody(body); smsInfo.setDate(date); smsInfo.setType(Integer.parseInt(type)); list.add(smsInfo); smsInfo = null; } return list; } /** * 还原短信,为了让它显示进度条,传个PD,把最大值给它设置进行, * 每次完成一个就在相应的事件里面加1即可。你也可以设置个返回值,为另外 * 一个方法提供结果即可,但是这样绝对是不对的,因为它是要求在方法执行之前把总共有多少 * 条短信传输过去 ,所以我们可以把Pd直接作为方法的参数,在这里面给它设置即可。 * 最重要的是,还原之前先把所有的短信都清空,然后再住里面插入数据(根据提供的URI)。 * 把pd传过来是一个很重要的思路。 * @param path * @param pd */ public void restoreSms(String path,ProgressDialog pd) throws Exception{ File file = new File(path); ContentValues values = null; FileInputStream fis = new FileInputStream(file); XmlPullParser parser = Xml.newPullParser(); parser.setInput(fis, "utf-8"); int type = parser.getEventType(); int currentcount = 0; while (type != XmlPullParser.END_DOCUMENT) { switch (type) { case XmlPullParser.START_TAG: if ("count".equals(parser.getName())) { String count = parser.nextText(); pd.setMax(Integer.parseInt(count)); // continue;//结束这次循环,开始下一次循环。不能加它,因为while是个大循环,直接到下一个case也错过了。 } if ("sms".equals(parser.getName())) { values = new ContentValues(); }else if ("address".equals(parser.getName())) { values.put("address", parser.nextText()); }else if ("date".equals(parser.getName())) { values.put("date", parser.nextText()); }else if ("type".equals(parser.getName())) { values.put("type", parser.nextText()); }else if ("body".equals(parser.getName())) { values.put("body", parser.nextText()); } break; case XmlPullParser.END_TAG: if ("sms".equals(parser.getName())) { ContentResolver resolver = context.getContentResolver(); System.out.println("有木有"); resolver.insert(Uri.parse("content://sms/"), values); values = null; currentcount ++; pd.setProgress(currentcount); } break; } type = parser.next(); } } } /** * 开启一个后台服务去备份, */ public class BackupSmsService extends Service{ private SmsInfoService smsInfoService; @Override public IBinder onBind(Intent intent) { return null; } /** * 开启备份短信的一个服务 * 因为一旦开启,onCreate方法就执行一次, */ @Override public void onCreate() { super.onCreate(); smsInfoService = new SmsInfoService(this); //开始往XML里面写数据 new Thread(){ public void run() { try { List<SmsInfo> list = smsInfoService.getSmsInfos(); //存储到SD卡上,这个方法应该抽离出来,首先判断SD存在不?然后判断挂载没有,然后再用环境变量得到SD卡目录 。 File file = new File(Environment.getExternalStorageDirectory()+"/smsback.xml"); //This interface will be part of XmlPull 1.2 API. FileOutputStream fos = new FileOutputStream(file); XmlSerializer xmlSerializer = Xml.newSerializer(); xmlSerializer.setOutput(fos, "utf-8"); xmlSerializer.startDocument("utf-8", true); xmlSerializer.startTag(null, "smss"); xmlSerializer.startTag(null, "count"); xmlSerializer.text(list.size()+""); xmlSerializer.endTag(null, "count"); for (SmsInfo info : list) { xmlSerializer.startTag(null, "sms"); xmlSerializer.startTag(null, "id"); xmlSerializer.text(info.getId()+""); xmlSerializer.endTag(null, "id"); xmlSerializer.startTag(null, "address"); xmlSerializer.text(info.getAddress()); xmlSerializer.endTag(null, "address"); xmlSerializer.startTag(null, "date"); xmlSerializer.text(info.getDate()); xmlSerializer.endTag(null, "date"); xmlSerializer.startTag(null, "type"); xmlSerializer.text(info.getType()+""); xmlSerializer.endTag(null, "type"); xmlSerializer.startTag(null, "body"); xmlSerializer.text(info.getBody()); xmlSerializer.endTag(null, "body"); xmlSerializer.endTag(null, "sms"); } xmlSerializer.endTag(null, "smss"); xmlSerializer.endDocument(); //把文件缓冲区的数据写出去 fos.flush(); fos.close(); Looper.prepare(); Toast.makeText(getApplicationContext(), "备份成功", 0).show(); Looper.loop(); } catch (Exception e) { e.printStackTrace(); Looper.prepare(); Toast.makeText(getApplicationContext(), "备份失败", 0).show(); Looper.loop(); } }; }.start(); } } 学会了在github下载源码,这个程序管理主要看了设置里面的代码 如何获得所有应用程序信息。 开发一个业务方法,获取所有应用程序。 用帧布局在中间放置一个进度条。 ProgressBar它是一个饼。有不同的样式 。 ProgressDialog它一定是个对话框, 在ProgressDialog里面一定有一个ProgressBar. 企业开发中会有所有消息对应的常量。 写一个适配器,要把所有的列表给过来 ,所以 要有下private List<SmsInfo> list; 并且写成构造方法 。 这次有一个像WEB中的模态要做,用了帧布局和消息机制。 因为单独的Adapter没有上下文,所以也要传过来。 这就是我们在封装的时间,缺什么变量加上成员变量 上,然后通过构造方法传过来,多么好的思路呀。 极其重要的问题? 优化问题: 1、怎么去优化listview?怎么优化gridview? 2、怎么去优化java虚拟机。 所有的优化时间问题都可以转化为下面两种思路 1、时间换时间 360安全卫士,QQ电脑管家。 (禁用一些开机启动项,或者延时加载一些开机启动) 优化安卓系统的开机启动时间。 有的只是把系统的一些功能启动了,开机以后电话,短信 , 相机都不能,而是在开机完之后再自己加载。给用户造成一 种错觉,优化有效果了。 听音乐,sd卡 .mp3 .jpg这些听歌软件为什么能够直接列 出来所有,因为后台早就自己做好放到数据库里面了。 2、空间换时间 我们看图片正常应该是从SD卡到内存中才能看到。 图片资源 sd-->内存-->显示出来。 不过,现在我们定义一个缓存,直接显示更快了。 缓存-->显示。 因为每次显示一个条目,都会调用一次getView方法。 所以把View里面的控件变成静态的。 View.inflate()非常消耗内存。 View convertView 转化View对象,历史view对象的缓存。 也就是说我们要使用历史缓存对象,因为getView每次 每个条目都会调用,所以如果发现这个条目的缓存对象 存在就不再inflate它,而是直接用历史缓存对象。 static TextView tv;如果不用静态的,它每次都要在栈 内存空间创建一个对象。 inflate()会通过反射消耗大量内存所以不能总是创建, 每个条目只能创建(吹起来)一次,再次用的话,直接就用缓存的。 要明白,每个条目显示都要调用getView()方法,而getView 里面有大量消耗内存的操作,通过静态一些对象和利用缓存 去减少它的使用内存。 ListView重要总结: android ListView几个比较特别的属性 由于这两天在做listView的东西,所以整理出来一些我个人认为比较特别的属性,通过设置这样的属性可以做出更加美观的列表 首先是stackFromBottom属性,这只该属性之后你做好的列表就会显示你列表的最下面,值为true和false android:stackFromBottom="true" 第二是 transciptMode属性,需要用ListView或者其它显示大量Items的控件实时跟踪或者查看信息, 并且希望最新的条目可以自动滚动到可视范围内。通过设置的控件transcriptMode属性可以将Android平台的控件(支持ScrollBar)自动滑动到最底部。 android:transcriptMode="alwaysScroll" 第三cacheColorHint属性,很多人希望能够改变一下它的背景, 使他能够符合整体的UI设计, 改变背景背很简单只需要准备一张图片然后指定属性 android:background="@drawable/bg",不过不要高兴地太早,当你这么做以后,发现背景是变了, 但是当你拖动,或者点击list空白位置的时候发现ListItem都变成黑色的了,破坏了整体效果。 第四divider属性,该属性作用是每一项之间需要设置一个图片做为间隔,或是去掉item之间的分割线 android:divider="@drawable/list_driver" 其中 @drawable/list_driver 是一个图片资源, 如果不想显示分割线则只要设置为android:divider="@drawable/@null" 就可以了 第五fadingEdge属性,上边和下边有黑色的阴影 android:fadingEdge="none" 设置后没有阴影了~ 第五scrollbars属性,作用是隐藏listView的滚动条, android:scrollbars="none"与setVerticalScrollBarEnabled(true);的效果是一样的,不活动的时候隐藏,活动的时候也隐藏。 第六fadeScrollbars属性,android:fadeScrollbars="true" 配置ListView布局的时候,设置这个属性为true就可以实现滚动条的自动隐藏和显示。 原来做安卓下的模态需要帧布局,因为它跟WEB下的DIV是一样的,都是从左上角到右下角一层一层来的。所以,哈哈。这是一个非常重要的布局。 //总结 思路:在写业务类的一个重要思路,你写着写着,发现需要一个类,把它放在成员变量里面,然后在构造函数里面初始化, //这样别人在调用你这个业务类的时间就可以把它给传过来 private Context context; private PackageManager packageManager; public AppInfoProvider(Context context){ this.context = context; packageManager = context.getPackageManager(); } //一些非常重要的布局和属性,必须要掌握。 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/backgroundcolor" android:orientation="vertical" > <!-- 为什么要加个LinearLayout这是很值得思考的,因为你外包一层,位置控制就非常的容易 。 --> <LinearLayout android:layout_width="match_parent" android:layout_height="40dip" android:background="#dd555F5F" android:gravity="center_vertical|center_horizontal" android:orientation="vertical" > <TextView android:id="@+id/tv_app_manager_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="所有程序" android:textColor="@android:color/white" android:textSize="25sp" /> </LinearLayout> <!-- 帧布局 类似div层,所有的帧布局都是从左上角开始的.每个控件相当于一个 DIV,并且都是从左上角开始的. ListView有一些个重要属性,必须要掌握。 android:listSelector:它对就的是 一个状态列表,即点击,获取焦点等不同状态下有不同的效果。 android:cacheColorHint: 这个是当你设置了背景图片以后,再滚动的时间缓存会出现,你把它的 背景色改成透明的就行了。 --> <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent" > <ListView android:id="@+id/lv_app_manager" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginTop="1dip" android:cacheColorHint="@android:color/transparent" android:listSelector="@drawable/item_background_selector" > </ListView> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_vertical|center_horizontal" android:orientation="vertical" android:visibility="visible" android:id="@+id/ll_app_manager_loading" > <ProgressBar android:layout_width="60dip" android:layout_height="60dip" /> <TextView android:text="正在加载应用程序" android:textSize="18sp" android:textColor="@android:color/white" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout> </FrameLayout> </LinearLayout> //还有如何实现安卓下的模态。 结合上面布局的代码,我们来实现安卓的模态问题。 //一加载就开始显示那个帧布局的东西,处于可见状态。 ll_app_manager_loading.setVisibility(View.VISIBLE); //因为搜索所有程序列表很耗时,所以另外起一个线程 new Thread(){ @Override public void run() { provider = new AppInfoProvider(AppManagerActivity.this); appInfos = provider.getAppInfos(); //得到所有信息之后 ,通知主线程,开始更新界面吧。 Message message = new Message(); message.what = GET_ALL_APP_FINISH; handler.sendMessage(message); }; }.start(); 然后在消息机制里面这样做: private Handler handler = new Handler(){ @Override public void handleMessage(Message msg) { switch (msg.what) { case GET_ALL_APP_FINISH: //结束之后 要处于不可见状态,这是多么好的模态呀。 ll_app_manager_loading.setVisibility(View.INVISIBLE); adapter = new AppManagerAdapter(AppManagerActivity.this, appInfos); lv_app_manager.setAdapter(adapter); break; } }; }; ImageView一般用这个android:scaleType="fitXY"因为它正好能够填充满这个。 //很重要的一个方法,从listView里面直接得到这个对象 。这是SDK提供的方法。 AppInfo appInfo = (AppInfo) lv_app_manager.getItemAtPosition(position); //popwindow它是比acitvity开销小的小窗体。 得到listview每个条目的左上角位置。 界面中只让存在一个popupwindow的操作。 在使用popupwindow的时间一定要设置一个背景颜色,否则会产生很多问题。 为某个东西添加控件的思路,先把动画通过XML或者代码定义出来,然后附加 在某个控件上,它们两个独立的。 LinearLayout ll = (LinearLayout) popupView.findViewById(R.id.ll_popup); ScaleAnimation animation = new ScaleAnimation(0.0f, 1.0f, 0.0f, 1.0f); animation.setDuration(200); ll.startAnimation(animation); 操,太牛逼了,可以为某个控件添加一个值,就是附属在它上面的,它可以为 任何一个前台的组件赋值jquery里面的data,这个值可以附带一个值 ,当时感觉 jquery的强大之处,没有想到安卓也是这样设计的,有一个setTag()可以为某个 控件带一个值,在用的时间再取出来,原来所有前台的设计思想是一样的。 这个在安卓中,一个界面有很多view,不好通过ID区别,就可以通过它。 就是setTag方法太强大 了。用的地方特别多。 // 把当前条目在listview中的位置设置给view对象 ll_start.setTag(position);//把一个数据记录在这个控件上,我用jquery中的data谈过这个方法。 ll_share.setTag(position); ll_uninstall.setTag(position); 调用 : //上面设置Tag就是为了给其它地方传播数据。这是前台的各个控件数据传输的一种重要方法。 int position = (Integer) v.getTag();
相关文章推荐
- 自己以前写电话本管理程序
- Linux C和MySQL数据库写的一个“电话本管理程序”
- Android短信拦截和电话拦截
- Android项目:手机安全卫士(12)—— 通讯卫士之电话短信黑名单设置与拦截
- iOS程序中调用系统自带应用(短信,邮件,浏览器,地图,appstore,拨打电话)
- iOS程序中调用系统自带应用(短信,邮件,浏览器,地图,appstore,拨打电话)
- iOS程序中调用系统自带应用(短信,邮件,浏览器,地图,AppStore,拨打电话)
- 关于短信拦截和电话拦截
- windows moblie 5.0在托管程序中实现短信接收和拦截
- 短信,电话拦截的优先级问题
- android短信和电话拦截
- Ios拦截手机短信程序
- windows moblie 5.0在托管程序中实现短信接收和拦截
- 短信与电话的拦截
- iphone-调系统电话,短信等功能(自动返回程序)
- android 使用广播接收者监听短信和拦截外拨电话
- 黑名单电话和短信拦截
- iOS 程序中调用系统自带应用(短信,邮件,浏览器,地图,appstore,拨打电话)
- 转 iOS程序中调用系统自带应用(短信,邮件,浏览器,地图,appstore,拨打电话)
- Android电话短信拦截项目总结之 SQLite数据库简介和使用