1. 程式人生 > >android 小專案------黑名單app

android 小專案------黑名單app

週一的時候,同事在群裡問到了黑名單功能,他說網上都沒有找到一個完整的,記得誰說過一句,當都沒有做過的時候,這就是機會。這幾天公司事比較多,只能晚上抽時間寫寫,直到今天才完整的做出來。

具體效果的話大家可以執行demo看看。

首先我們分析下需求

1、UI部分,畢竟這也是一個小的app,

2、需要有一個數據庫來儲存黑名單的號碼,

3、需要用到一個服務來具體執行黑名單的功能,畢竟如果我們的app退出了,黑名單功能就失效了,這就比較坑了,

  未解決的問題,測試在L及以下版本都能夠正常工作,但是在M版本PhoneStateListener會獲取
  不到來電號碼,這個我暫時只想到了framework層的程式碼來修改。待我解決了會重新上傳的。

這裡寫圖片描述

這裡寫圖片描述

它們前面的邏輯差不多一樣,但是M版在最後呼叫binder的時候,獲取到的號碼時空的。

UI部分請看底部的原始碼,比較簡單,相信大家一看就懂。

接下來我們來設計一下黑名單的資料庫。

它首先應該包括一個id這個是設計資料庫時都有的,第二個應該就是要攔截的電話號碼了,
最後我們在來個攔截的模式(這個可有可無,主要考慮,說不定簡訊也要攔截呢)。
public class BlackNumberOpenHelper extends SQLiteOpenHelper {
    public BlackNumberOpenHelper(Context context) {
        super
(context, "blacknumber.db", null, 1); } @Override public void onCreate(SQLiteDatabase db) { //建立資料庫中表的方法 db.execSQL("create table blacknumber " + "(_id integer primary key autoincrement , phone varchar(20), mode varchar(5));"); } @Override public
void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } }

一般有資料庫後,都會提供一個操作資料庫的工具類。這個大家請看底部給出的原始碼。

上面這些都是為我們的黑名單功能服務的,接下來看下黑名單功能的具體實現。

這裡我們是用PhoneStateListener來獲取電話的狀態,如果是響鈴狀態時,通過反射來結束通話電話。

來看下PhoneStateListener的使用流程。

1、獲取TelephonyManager,
2、確定要監聽的電話狀態因為PhoneStateListener這個類不僅能監聽電話的狀態它還有非常多的其他狀態監聽。
3、重寫PhoneStateListener的onCallStateChanged方法,當狀態發生改變時來處理我們的流程。

  public void onCreate() {
        mDao = BlackNumberDao.getInstance(getApplicationContext());

        //攔截簡訊
        /*IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction("android.provider.Telephony.SMS_RECEIVED");
        intentFilter.setPriority(1000);

        mInnerSmsReceiver = new InnerSmsReceiver();
        registerReceiver(mInnerSmsReceiver, intentFilter);*/

        //監聽電話的狀態
        //1,電話管理者物件
        mTM = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
        //2,監聽電話狀態
        mPhoneStateListener = new MyPhoneStateListener();
        mTM.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);

        super.onCreate();
    }

    class MyPhoneStateListener extends PhoneStateListener{
        //3,手動重寫,電話狀態發生改變會觸發的方法
        @Override
        public void onCallStateChanged(int state, String incomingNumber) {
            switch (state) {
                case TelephonyManager.CALL_STATE_IDLE:
                    break;
                case TelephonyManager.CALL_STATE_OFFHOOK:
                    break;
                case TelephonyManager.CALL_STATE_RINGING:
                    //結束通話電話  aidl檔案中去了
//              mTM.endCall();
                    endCall(incomingNumber);
                    break;
            }
            super.onCallStateChanged(state, incomingNumber);
        }
    }

接下來看下結束通話電話的邏輯。

android早期的版本可以通過API呼叫直接結束通話電話,但是後期版本把它隱藏了,不過通過java的反射機制我們同樣可以呼叫到這個方法。

try {
                //1,獲取ServiceManager位元組碼檔案
                Class<?> clazz = Class.forName("android.os.ServiceManager");
                //2,獲取方法
                Method method = clazz.getMethod("getService", String.class);
                //3,反射呼叫此方法
                IBinder iBinder = (IBinder) method.invoke(null, Context.TELEPHONY_SERVICE);
                //4,呼叫獲取aidl檔案物件方法
                ITelephony iTelephony = ITelephony.Stub.asInterface(iBinder);
                //5,呼叫在aidl中隱藏的endCall方法
                iTelephony.endCall();
            } catch (Exception e) {
                e.printStackTrace();
            }

上面程式碼主要是通過反射獲取ServiceManager類裡面的getService方法,然後呼叫這個方法獲取iBinder物件,通過iBinder我們可以得到ITelephony,最後呼叫ITelephony.endCall來結束通話電話。

走到這裡我們的黑名單功能就基本實現了,但是當我們進到通話記錄裡面的時候會發現,剛才手機明明沒響,怎麼有未接電話呢。呵呵噠。

我們來處理下這個問題,這主要是因為結束通話了電話但是系統的phone卻是會把這個通話記錄儲存下來,只要把它刪掉就可以了。

這裡要注意下這個刪除的時機,你想啊,我們結束通話電話時就把通話記錄刪除了,但是系統要往通話記錄裡面插入資料也是需要時間的呀,有時還沒插入你就刪除了,這不就糾結了,怎麼找也找不到哪兒出問題了,這裡會用到系統提供的內容觀察者,只有系統往通話記錄資料庫中插入了資料時我們才刪除。

    mContentObserver = new MyContentObserver(new Handler(),phone);
            getContentResolver().registerContentObserver(
                    Uri.parse("content://call_log/calls"), true, mContentObserver);


 class MyContentObserver extends ContentObserver {
        private String phone;
        public MyContentObserver(Handler handler, String phone) {
            super(handler);
            this.phone = phone;
        }
        //資料庫中指定calls表發生改變的時候會去呼叫方法
        @Override
        public void onChange(boolean selfChange) {
            //插入一條資料後,再進行刪除
            getContentResolver().delete(
                    Uri.parse("content://call_log/calls"), "number = ?", new String[]{phone});
            super.onChange(selfChange);
        }
    }

github好卡,暫時只傳CSDN了。

原始碼