模仿360安全卫士项目笔记6

来源:互联网 发布:windows 10 下载 编辑:程序博客网 时间:2024/06/04 18:43


51_黑名单号码数据库的创建&曾删改查_40

1、演示金山卫士的拦截效果;

2、创建手机防盗页面CallSmsSafeActivity,并在功能清单文件注册。

3、添加跳转逻辑,并实现布局文件,头部采用相对布局

 

4、在com.itheima.mobile.db目录下创建数据库打开帮助类BlackNumberDBOpenHelper,它是继承SQLiteOpenHelper的;

 

5、讲解构造方法的参数和OnCreate方法什么时候执行;

 

6、创建数据库的表结构

//创建表 blacknumber 主键_id自增长 ,number黑名单号码,mode拦截模式:1电话拦截 2短信拦截  3全部拦截

db.execSQL("create table blacknumber (_id integer primary key autoincrement,number varchar(20),mode varchar(2))");

 

 

7、创建新包com.itheima.mobilesafe.test并创建测试数据类TestBlackNumberDB 继承AndroidTestCase

 

 

8、创建数据库方法testCreateDB()

public void testCreateDb(){

BlackNumberDBOpenHelper helper = new BlackNumberDBOpenHelper(getContext());

helper.getWritableDatabase();

}

 

9、测试报错后,添加测试框架相关参数;

测试框架(放在manifest根节点)

<instrumentation

        android:name="android.test.InstrumentationTestRunner"

        android:targetPackage="com.itheima.mobilesafe" />

 

依赖库(放在application里面)

  <uses-library android:name="android.test.runner" />

 

运行测试代码,查看是否已经成功创建数据库,导出用工具打开查看列表信息

 

10、数据的增、删、改、查的实现 com.itheima.mobilesafe.db.dao

   创建类BlackNumberDao 在里面实现增删改查;

   A:在构造方法里创建数据库

helper = new BlackNumberDBOpenHelper(context);

 

   B:数据库的添加add(String number,String mode)

     SQLiteDatabase db= helper.getWritableDatabase();

  ContentValues values = new ContentValues();

values.put("number", number);

values.put("mode", mode);

//第二个参数:当内容为空时

db.insert("blacknumber"null, values);

db.close();

 

nullColumnHack
当values参数为空或者里面没有内容的时候,insert是会失败的(底层数据库不允许插入一个空行),为了防止这种情况,要在这里指定一个列名,到时候如果发现将要插入的行为空行时,就会将你指定的这个列名的值设为null,然后再向数据库中插入。
通过观察源码的insertWithOnConflict方法可以看到当ContentValues类型的数据initialValues为null或size<=0时,就会在sql语句中添加nullColumnHack的设置。

 

  C:数据库的删除delete(String number)

SQLiteDatabase db= helper.getWritableDatabase();

db.delete("blacknumber""number=?"new String[]{number});

db.close();

 

  D:数据的修改update(String number ,String newMode):

SQLiteDatabase db= helper.getWritableDatabase();

ContentValues values = new ContentValues();

values.put("mode", newMode);

db.update("blacknumber", values, "number=?"new String[]{number});

db.close();

 

 

  E:查询黑名单是否存在该号码find(String number)

 

  boolean result = false;

SQLiteDatabase db= helper.getWritableDatabase();

Cursor cursor = db.query("blacknumber"null"number=?"new String[]{number}, nullnullnull);

if(cursor.moveToNext()){

result = true;

}

cursor.close();

db.close();

return result;

  F:查询拦截模式findMode(String number)

 

String mode = null;

SQLiteDatabase db= helper.getWritableDatabase();

Cursor cursor = db.query("blacknumber"new String[]{"mode"}, "number=?"new String[]{number}, nullnullnull);

if(cursor.moveToNext()){

mode = cursor.getString(0);

}

cursor.close();

db.close();

return mode;

 

11、写测试代码

 

public void testadd() {

BlackNumberDao blackNumberDao = new BlackNumberDao(getContext());

blackNumberDao.add("119""1");

}

 

public void testdelete() {

BlackNumberDao blackNumberDao = new BlackNumberDao(getContext());

blackNumberDao.delete("119");

}

 

public void testupdate() {

BlackNumberDao blackNumberDao = new BlackNumberDao(getContext());

blackNumberDao.update("119""2");

 

}

 

public void testfind() {

BlackNumberDao blackNumberDao = new BlackNumberDao(getContext());

boolean find = blackNumberDao.find("119");

assertEquals(true, find);

}

 

public void testfindMode() {

BlackNumberDao blackNumberDao = new BlackNumberDao(getContext());

String mode = blackNumberDao.findMode("119");

System.out.println("拦截模式:" + mode);

 

}

 知识拓展

assertEquals:用于判断实际值和期望值是否相同
assertSame:判断实际值和期望值是否为同一个对象

 

12.进入模拟器查看数据

  A:列出两个模拟器命令:adb devices

  B: 进入指导模拟器命令:adb -s emulator-5554 shell

  C:进入到data/data/com.ithiema.mobilesafe/databases目录下

  D:打开数据库命令:sqlite3 blacknumber.db

  F: 查询表内容SQL语句:select * from blacknumber;

 

 

 

知识拓展:

Android使用getWritableDatabase()和getReadableDatabase()方法都可以获取一个用于操作数据库的SQLiteDatabase实例。(getReadableDatabase()方法中会调用getWritableDatabase()方法)

其中getWritableDatabase() 方法以读写方式打开数据库,一旦数据库的磁盘空间满了,数据库就只能读而不能写,倘若使用的是getWritableDatabase() 方法就会出错。

getReadableDatabase()方法则是先以读写方式打开数据库,如果数据库的磁盘空间满了,就会打开失败,当打开失败后会继续尝试以只读方式打开数据库。如果该问题成功解决,则只读数据库对象就会关闭,然后返回一个可读写的数据库对象。

 

  

 

52_黑名单号码界面的展现_10

1、便于展示先添加100条数据

 Random random = new Random();

//13512340001

for(int i = 0 ;i< 100;i++ ){

blackNumberDao.add("1351234000"+i, String.valueOf(random.nextInt(3)+1));

}

 

2.增加到所有黑名单数据的接口List<BlackNumberInfo> findAll()

 

List<BlackNumberInfo> infos = new ArrayList<BlackNumberInfo>();

SQLiteDatabase database = helper.getWritableDatabase();

Cursor cursor = database.query("blacknumber"new String[]{"number","mode"}, nullnullnullnullnull);

while(cursor.moveToNext()){

BlackNumberInfo info = new BlackNumberInfo();

String number = cursor.getString(0);

String mode = cursor.getString(1);

info.setMode(mode);

info.setNumber(number);

infos.add(info);

}

cursor.close();

database.close();

return infos;

 

3.初始化ListView 显示数据

       初始化数据

       dao=  new BlackNumberDao(this);

list = dao.findAll();

    

 

       数据显示:

       public int getCount() {

// TODO Auto-generated method stub

return list.size();

}

public View getView(int position, View convertView, ViewGroup parent) {

 

TextView view = new TextView(getApplicationContext());

view.setText(list.get(position).toString());

 

return view;

}

 

    运行演示测试效果

53_ListView的简单优化_35

1、自定义每条的样式创建相对布局文件list_callsmssafe_item.xml

  <?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="match_parent"

    android:layout_height="wrap_content" >

 

    <TextView

        android:id="@+id/tv_number"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_marginLeft="5dip"

        android:layout_marginTop="5dip"

        android:text="5554"

        android:textColor="#000000"

        android:textSize="20sp" />

 

    <TextView

        android:id="@+id/tv_mode"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        android:layout_below="@id/tv_number"

        android:layout_marginLeft="5dip"

        android:layout_marginTop="1dip"

        android:text="拦截模式"

        android:textColor="#99000000"

        android:textSize="16sp" />

 

    <ImageView

        android:layout_centerVertical="true"

        android:src="@drawable/delete_button"

        android:layout_alignParentRight="true"

        android:layout_width="40dip"

        android:layout_height="40dip" />

 

</RelativeLayou

 

2、在getView里面实现显示代码

         if("1".equals(info.getMode())){

tv_mode.setText("拦截电话");

}else if("2".equals(info.getMode())){

tv_mode.setText("拦截短信");

}else if("3".equals(info.getMode())){

tv_mode.setText("拦截电话+短信");

}

 

 

 

 

  

 3ListView的简单优化

       View view;

if(convertView != null){

view = convertView;

Log.i(TAG"使用历史缓存的显示数据"+position);

}else{

Log.i(TAG"创建新的View的显示数据"+position);

view =View.inflate(CallSmsSafeActivity.this, R.layout.list_callsmssafe_itemnull);

}

 

4.进一步优化

view.findViewById(R.id.tv_number);该代码查找孩子的时候比较耗时,消耗资源,画图分析原理如下;

 

 

5、代码实现

 A:定义容器

  static class ViewHolder{

TextView tv_number;

TextView tv_mode;

}

 

B:当创建View的时候实例化容器;

           ViewHolder holder;

if(convertView != null){

view = convertView;

holder = (ViewHolder) view.getTag();

}else{

//初始化容器

holder = new ViewHolder();

设置与该视图相关联的标记。一个标签可以用来标记一个视图层次结构层次结构内不必是惟一的。标签也可以用来存储数据在一个视图没有求助于另一个数据结构

view.setTag(holder);

}

 

C:使用

         holder.tv_number.setText(info.getNumber());

if("1".equals(info.getMode())){

holder.tv_mode.setText("拦截电话");

}else if("2".equals(info.getMode())){

holder.tv_mode.setText("拦截短信");

}else if("3".equals(info.getMode())){

holder.tv_mode.setText("拦截电话+短信");

}

 

性能提高百分之五左右。

54_ListView的加载UI效果优化_8

1、解决数据库内容很多的情形;

  findAll()在该方法休眠3秒演示效果

2、创建一个线程去读取数据:

  new Thread() {

 public void run() {

list = dao.findAll();//查询数据库得到数据

handler.sendEmptyMessage(0);//发消息给主线程更新数据

  };

}.start();

3、更新数据

//更新数据

private Handler handler = new Handler() {

public void handleMessage(android.os.Message msg) {

lv_call_sms_safe.setAdapter(new CallSmsSafeAdapter());

};

};

 

4、没数据的时候加一个提醒效果,写布局文件

  <FrameLayout

        android:layout_width="match_parent"

        android:layout_height="match_parent" >

 

        <ListView

            android:id="@+id/lv_call_sms_safe"

            android:layout_width="match_parent"

            android:layout_height="match_parent" >

        </ListView>

 

        <LinearLayout

            android:id="@+id/ll_loading"

            android:gravity="center"

            android:visibility="invisible"

            android:layout_width="match_parent"

            android:layout_height="match_parent"

            android:orientation="vertical" >

 

            <ProgressBar

                android:layout_width="wrap_content"

                android:layout_height="wrap_content" />

 

            <TextView

                android:text="给力加载中..."

                android:layout_width="wrap_content"

                android:layout_height="wrap_content" />

        </LinearLayout>

</FrameLayout>

 

5、代码配合处理

ll_loading.setVisibility(View.VISIBLE);//没数据的时候显示

ll_loading.setVisibility(View.INVISIBLE);//数据加载好了隐藏

 

 

55_ListView的数据分批加载_41

1、讲解分批加载的好处:不用等待太久、节约流量、慢慢引导用户看感兴趣内容;

 

2、导出数据库,打开数据库的分批查询,写SQL语句:

   select number ,mode from blacknumber limit 10 offset 10   //查询部分的数据

 

基于findAll()修改

public List<BlackNumberInfo> findPart(int startIndex){

try {

Thread.sleep(600);

catch (InterruptedException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

List<BlackNumberInfo> infos = new ArrayList<BlackNumberInfo>();

SQLiteDatabase database = helper.getWritableDatabase();

Cursor cursor = database.rawQuery("select number ,mode from blacknumber limit 20 offset ?"new String[]{startIndex+""});

while(cursor.moveToNext()){

BlackNumberInfo info = new BlackNumberInfo();

String number = cursor.getString(0);

String mode = cursor.getString(1);

info.setMode(mode);

info.setNumber(number);

infos.add(info);

}

cursor.close();

database.close();

return infos;

}

然后使用,运行演示;

 

3、监听拖动到末尾

lv_call_sms_safe.setOnScrollListener(new OnScrollListener() {

/**

 * 当滚动状态发生改变的时候调用这个方法

 * 静止--->滚动

 * 滚动--->静止

 * 手指触摸滑动--->惯性滚动

 */

@Override

public void onScrollStateChanged(AbsListView view, int scrollState) {

switch (scrollState) {

case OnScrollListener.SCROLL_STATE_IDLE://空闲状态

int position = lv_call_sms_safe.getLastVisiblePosition();//19 最后一条显示的位置

int total = list.size();//20总的数据有多少

if(position == (total-1)){

//最后一条了,该去加数据了

Toast.makeText(getApplicationContext(), "加载更多数据", 0).show();

}

break;

case OnScrollListener.SCROLL_STATE_FLING://惯性滑动

break;

case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL://触摸滚动

 

default:

break;

}

}

/**

 * 当滚动的时候调用该方法

 */

@Override

public void onScroll(AbsListView view, int firstVisibleItem,

int visibleItemCount, int totalItemCount) {

}

});

 

 

4、加载数据,抽取线程代码为方法fillData()、指定加载位置定义成类的成员变量startIndex,然后在监听到末尾处加载数据。

 

定义类的成员变量:

private int startIndex = 0;

 

   加载数据:

   if(position == (total-1)){

//最后一条了,该去加重数据了

Toast.makeText(getApplicationContext(), “加载, 0).show();

//startIndex = startIndex +20;

       ll_loading.setVisibility(View.VISIBLE);//显示加载

startIndex += 20;

fillData();

}

 

5、处理数据被覆盖的问题

fillData()方法里面代码修改:

if(list == null){

list = dao.findPart(startIndex);//查询数据库得到数据

}else{

//已经有数据了

list.addAll(dao.findPart(startIndex));

}

6、让数据继续停留在当前位置

  两种实现方式

 第一种:lv_call_sms_safe.setSelection(startIndex);//不推荐

 第二种:重复利用适配器,数据变化通知一下就行了

  private CallSmsSafeAdapter adapter;

 

  Handler里面修改成:

   if(adapter == null){

adapter = new CallSmsSafeAdapter();

lv_call_sms_safe.setAdapter(adapter);

}else{

//通知数据适配器更新一下界面

adapter.notifyDataSetChanged();

}

 

 

7、防止重复加载

 定义成员变量

 private boolean isLoading  = false;

 

 在加载的过程中

  if(isLoading){

 return;

  } 

 

  isLoading = true;

 

  加载好后 handler里面处理

  isLoading = false;

 

 

8、处理拖动到所有数据的最后一条时的处理

  得到数据库一共有多少条数据

  /**得到数据的总数

 * @return

 */

public int  getTotalCount(){

int count = 0;

SQLiteDatabase database = helper.getWritableDatabase();

Cursor cursor = database.rawQuery("select count(*) from blacknumber"null);

if(cursor.moveToNext()){

 count = cursor.getInt(0);

}

cursor.close();

database.close();

return count;

}

 

代码处理

if(startIndex >= total){

Toast.makeText(getApplicationContext(), "已经最后一条了", 0).show();

return;

}

 

 

总结分批处理:

分批处理 解决的时候时间等待的问题

不能解决内存占用的问题

要想解决内存占用问题,可以采用分页方式;

 

56_黑名单号码的添加和删除_32

1、画图添加黑名单号码对话框

 

 

2、创建布局文件dialog_add_blacknumber.xml(添加黑名单号码)

  <?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="300dip"

    android:layout_height="wrap_content"

    android:gravity="center_horizontal"

    android:orientation="vertical" >

 

    <TextView

        android:layout_width="300dip"

        android:layout_height="50dip"

        android:background="#66ff6600"

        android:gravity="center"

        android:text="添加黑名单号码"

        android:textColor="#000000"

        android:textSize="22sp" />

 

    <EditText

        android:layout_width="280dip"

        android:layout_height="wrap_content"

        android:hint="请输入电话号码"

        android:inputType="phone" />

 

    <RadioGroup

        android:id="@+id/radioGroup1"

        android:layout_width="280dip"

        android:layout_height="wrap_content"

        android:gravity="center_horizontal"

        android:orientation="horizontal" >

 

        <RadioButton

            android:id="@+id/radio0"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:checked="true"

            android:text="电话" />

 

        <RadioButton

            android:id="@+id/radio1"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:text="短信" />

 

        <RadioButton

            android:id="@+id/radio2"

            android:layout_width="wrap_content"

            android:layout_height="wrap_content"

            android:text="全部" />

    </RadioGroup>

 

    <LinearLayout

        android:layout_width="280dip"

        android:layout_height="wrap_content" >

 

        <Button

            android:layout_width="140dip"

            android:layout_height="wrap_content"

            android:background="@drawable/button_bg"

            android:text="确定" />

 

        <Button

            android:layout_width="140dip"

            android:layout_height="wrap_content"

            android:background="@drawable/button_bg"

            android:text="取消" />

    </LinearLayout>

 

</LinearLayout>

 

3、添加点击事件addBlackNumber

 

public void addBlackNumber(View view){

AlertDialog.Builder builder = new Builder(this);

AlertDialog dialog = builder.create();

View contentView = View.inflate(this, R.layout.dialog_add_blacknumbernull);

dialog.setView(contentView, 0, 0, 0, 0);

dialog.show();

}

运行演示

4、处理按钮点击事件

定义id et_blacknumberrg_moderb_allrb_phonerb_smsokcancel

点击事件确定

// 判断是否有号码

String number = et_blacknumber.getText().toString().trim();

if (TextUtils.isEmpty(number)) {

Toast.makeText(CallSmsSafeActivity.this"号码为空", 0).show();

return;

}

 

int id = rg_mode.getCheckedRadioButtonId();

String mode = "3";//拦截模式

switch (id) {

case R.id.rb_all:

mode = "3";

break;

case R.id.rb_phone:

mode = "1";

 

break;

case R.id.rb_sms:

mode = "2";

break;

 

}

dao.add(number, mode);

dialog.dismiss();

totalCount = dao.getTotalCount();//得到总数

 

 

5、倒序显示数据

 修改SQL语句

select number ,mode from blacknumber order by _id desc limit 20 offset ?

 

 刷新界面

 直接把当前对象添加到当前集合列表里面

   BlackNumberInfo info = new BlackNumberInfo();

info.setMode(mode);

info.setNumber(number);

//直接加到当前的列表里面去

list.add(0, info);

adapter.notifyDataSetChanged();//更新数据    

 

6、删除数据

  listViewitem默认是有点击效果的

  画图回顾事件传递过程

   

 

getView()方法里点击删除的实现

holder.iv_delete.setOnClickListener(new OnClickListener() {

@Override

public void onClick(View v) {

System.out.println("点击位置:"+position);

BlackNumberInfo blackNumberInfo = list.get(position);

String number = blackNumberInfo.getNumber();

//删除该号码数据库里面的黑名单信息

   dao.delete(number);

//把要删除的黑名单在当前列表移除

list.remove(blackNumberInfo);

//更新界面

adapter.notifyDataSetChanged();

}

});

 

 优化建议:写对话框去提示是否确定删除;

 

  

57_拦截短信_22

1、回顾之前做过的短信拦截

 

2、为了支持手动开启和关闭拦截短信,在服务(CallSmsSafeService)里面创建广播接收者(InnerSmsReceiver),并在功能清单文件注册;

 

 

public class CallSmsSafeService extends Service {

 

public static final String TAG = "CallSmsSafeService";

private BlackNumberDao dao;

private InnerSmsReceiver receiver;

 

@Override

public IBinder onBind(Intent intent) {

// TODO Auto-generated method stub

return null;

}

class InnerSmsReceiver extends BroadcastReceiver{

 

@Override

public void onReceive(Context context, Intent intent) {

Log.i(TAG"内部类的广播接收者--收到一条短信了");

//接收短信

Object [] objs = (Object[]) intent.getExtras().get("pdus");

for(Object obj : objs){

SmsMessage sms = SmsMessage.createFromPdu((byte[]) obj);

String sender = sms.getOriginatingAddress();//得到一个电话号码

//看一看这个电话号码是否是黑名单里面的

String mode = dao.findMode(sender);

if("2".equals(mode)||"3".equals(mode)){

abortBroadcast();//把这个广播终止掉

}

}

}

}

@Override

public void onCreate() {

// TODO Auto-generated method stub

super.onCreate();

dao = new BlackNumberDao(this);

//用代码注册广播接收者

receiver = new InnerSmsReceiver();

IntentFilter filter = new IntentFilter();

filter.addAction("android.provider.Telephony.SMS_RECEIVED");

filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);

registerReceiver(receiver, filter);

}

 

@Override

public void onDestroy() {

// TODO Auto-generated method stub

super.onDestroy();

unregisterReceiver(receiver);

receiver = null;

}

 

}

 

3、在设置中心里添加开启和关闭短信拦截服务的功能

 在activity_setting.xml里增加开启拦截服务的勾选框

 <com.itheima.mobilesafe.ui.SettingItemView

        android:id="@+id/siv_callsmssafe"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content"

        itheima:desc_off="设置黑名单拦截已经关闭"

        itheima:desc_on="设置黑名单拦截已经开启"

        itheima:title="设置黑名单拦截" >

</com.itheima.mobilesafe.ui.SettingItemView>

 

 

  在SettingActvity代码处理点击事件,开启服务和关闭服务

运行演示

4、智能拦截模式原理简介

 打开金山手机卫士,查看智能拦截模式;

 解压金山手机卫士APK ,进入assets目录 ,找到数据库firewall_sys_rules.db

 

 

 拦截短信内容带广告的

 

String body = sms.getMessageBody();

//查询数据库

if(body.contains("fapiao")){

Log.i(TAG"拦截到卖发票的短信");

abortBroadcast();

}

 

  拦截到的短信如何处理?

  一般会用数据库保存

  A便于再次查看;

  B有些人喜欢看垃圾短信;

  C:防止拦截误判 例如--你看我头发票不漂亮;luncene分词检索框架

 

 

 

5、讲解功能清单文件注册接收短信和代码注册接收短信谁优先收到;

 A打日志演示,优先级一样高的情况下代码注册的比功能清单文件的快

 B、根据系统漏掉设置最大Int

  filter.setPriority(Integer.MAX_VALUE);

 C、在布局文件也加上2147483647

 

一般手机卫士类似软件,一开机就启动服务把广播注册好。

  

 

 

 

 

 

 

58_拦截电话的原理_13

arm类型的手机里演示电话拦截;

 

1、电话拦截原理

当电话来的时候,立刻挂掉并把来电记录清除掉;如果手机速度快的话无法看到这个效果,就达到拦截的效果了。

 

2、监听当前电话呼叫的状态(TelephonyManager

 

监听来电代码

 

tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);

listener = new MyPhoneListener();

tm.listen(listenerPhoneStateListener.LISTEN_CALL_STATE);

 

 

具体监听实现代码

     switch (state) {

case TelephonyManager.CALL_STATE_RINGING://电话铃声响起来了

String mode = dao.findMode(incomingNumber);

if("1".equals(mode) || "3".equals(mode)){

 Log.i(TAG"黑名单的电话号码,马上挂断");

}

break;

default:

break;

}

取消监听来电代码

tm.listen(listener, PhoneStateListener.LISTEN_NONE);

listener = null;

 

 

59_利用反射调用系统隐藏API挂断电话_35

1、挂断电话的API早期版本endCall()是可以使用的,现在不可以用了;但本身挂断电话这个功能是存在的。

2、读getSystemService()源代码;

3、如何查看真面目?到内存中去看,运行起来看,打断点。例如

 

Context context = getApplication();//看他里面的---mBase---ContextImpl.java

TelephonyManager tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);

 

 搜索:ContextImpl.java,看看源代码

  ContextImpl继承了Context---->  搜索getSystemService

 --->看看各种服务

 

 

 在基础课的时候我们也可以写一个服务在后台运行,调用服务的时候可以获取远程服务的代理对象(Ibinder),得到代理对象后就可以调用里面的方法了。

 

 

4、重新启动模拟器看日志

  Zygote-->sysem_process---->batteryService---->SensorService....

 

开机过程其实就是各种服务加载的过程。

 

 

getSystemService()得到的服务把相关API隐藏了,只提供常用的方法,那么想要得到原生的TelephonyManager的方法就得绕开使用这个方法;

 

 

 

5挂断电话具体实现步骤

A创建endCall()方法,里面代码实现如下;

public void endCall() {

//ServiceManager.getService(TELEPHONY_SERVICE);

try {

//得到ServiceManager的字节码

Class clazz = CallSmsSafeService.class.getClassLoader().loadClass("android.os.ServiceManager");

//得到字节码的方法

Method method =clazz.getDeclaredMethod("getService", String.class);

//调用方法得到远程服务代理类

        IBinder b = (IBinder) method.invoke(nullTELEPHONY_SERVICE);

//获取到原生未经包装的系统电话的管理服务

catch (Exception e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

 

 

远程服务代理对象IBinder 需要一个.aidl文件去生成方法去管理服务

 

ITelephony.aidl

接口用于与手机交互。主要使用的
TelephonyManager类。一些地方仍然是直接使用这个。
请清理他们如果可能的话,使用TelephonyManager insteadl

 

ITelephony.aidl拷贝到com.android.internal.telephony

 

NeighboringCellInfo.aidl拷贝到android.telephony

 

不报错后看一下gen目录

 

endCall()方法加上如下代码

ITelephony telephony = ITelephony.Stub.asInterface(b);

telephony.endCall();//挂断电话

 

 

需要加上权限

 <uses-permission android:name="android.permission.CALL_PHONE"/>

 

 

 

知识拓展

60_利用内容观察者和内容提供者删除呼叫记录_25

 

1、增加方法deleteCalllog();

  导出呼叫记录数据data/data/com.android.proveders.contacts/databases/contacts2.db

 

  数据看里面的内容 number 电话号码 、 date时间、 type 打进来 打出去 未接

 

 

2、使用内容解析者去删除电话记录

 

ContentResolver resolver = getContentResolver();

Uri url = Uri.parse("content://call_log/calls");

resolver.delete(url, "number=?"new String[]{incomingNumber});

 

Uri 路径如何写可以参照源代码

运行演示,会报错;

3、需要加两个权限

 <uses-permission android:name="android.permission.READ_CALL_LOG"/>

<uses-permission android:name="android.permission.WRITE_CALL_LOG"/>

 

 

4、解释删除有时成功,有时不成功的情况;

立刻把电话挂断了,但呼叫的生成并不是同步的代码;它是一个异步的代码

5、用观察者去监听日志产生后再去删除

 

 注册监听

getContentResolver().registerContentObserver(url, truenew MyContentObserver(new Handler(), incomingNumber));

 

自定义内容观察者

private class MyContentObserver extends ContentObserver{

private String incomingNumber;

public MyContentObserver(Handler handler,String incomingNumber) {

super(handler);

this.incomingNumber = incomingNumber;

}

@Override

public void onChange(boolean selfChange) {

super.onChange(selfChange);

//删除呼叫记录

deleteCalllog(incomingNumber);

//取消注册内容观察者

getContentResolver().unregisterContentObserver(this);

}

}

 

 

补充Android2.3模拟器上需要多加权限

 

 <uses-permission android:name="android.permission.WRITE_CONTACTS"/>

0 0