模仿360安全衛士項目筆記6



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"/>


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com