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:///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(.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();
















