亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

內容觀察者 ContentObserver 監聽短信、通話記錄數據庫 掛斷來電

2019-11-09 14:58:45
字體:
來源:轉載
供稿:網友

Activity復制代碼
public class MainActivity extends ListActivity {    PRivate TextView tv_info;    private SMSContentObserver smsContentObserver;    private CallLogObserver callLogObserver;    private PhoneStateReceiver myReceiver;    @SuppressLint("HandlerLeak")    private Handler mHandler = new Handler() {        public void handleMessage(Message msg) {            String msgBody = (String) msg.obj;            tv_info.setText(msg.obj + ":" + msgBody);        }    };    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        String[] array = { "注冊短信數據庫變化的觀察者", "收件箱數據庫……", "刪除新來電的通話記錄", "監聽新來電通話記錄的詳細信息", "取消注冊Observer",//                "注冊電話狀態改變的廣播,當有來電時立即掛斷電話", "取消注冊廣播", };        for (int i = 0; i < array.length; i++) {            array[i] = i + "、" + array[i];        }        ListAdapter mAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1new ArrayList<String>(Arrays.asList(array)));        tv_info = new TextView(this);// 將內容顯示在TextView中        tv_info.setTextColor(Color.BLUE);        tv_info.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);        tv_info.setPadding(20, 10, 20, 10);        getListView().addFooterView(tv_info);        setListAdapter(mAdapter);        myReceiver = new PhoneStateReceiver();    }    @Override    protected void onListItemClick(ListView l, View v, int position, long id) {        switch (position) {        case 0:            smsContentObserver = new SMSContentObserver(mHandler, this, SMSContentObserver.MSG_SMS_WHAT);            getContentResolver().registerContentObserver(Uri.parse("content://sms"), true, smsContentObserver);            // boolean notifyForDescendents(后裔):若為true,則監視所有以指定的Uri開頭的Uri;若為false,則只精確的監視指定的URI            break;        case 1:            smsContentObserver = new SMSContentObserver(mHandler, this, SMSContentObserver.MSG_SMS_INBOX_WHAT);            getContentResolver().registerContentObserver(Uri.parse("content://sms/inbox"), true, smsContentObserver);            break;        case 2:            callLogObserver = new CallLogObserver(mHandler, this, CallLogObserver.MSG_CALLLOG_DELETE_WHAT);            getContentResolver().registerContentObserver(Uri.parse("content://call_log/calls"), true, callLogObserver);            break;        case 3:            callLogObserver = new CallLogObserver(mHandler, this, CallLogObserver.MSG_CALLLOG_QUERY_WHAT);            getContentResolver().registerContentObserver(CallLog.Calls.CONTENT_URItrue, callLogObserver);//等價于【Uri.parse("content://call_log/calls")】            break;        case 4:            if (smsContentObserver != null) getContentResolver().unregisterContentObserver(smsContentObserver);            if (callLogObserver != null) getContentResolver().unregisterContentObserver(callLogObserver);            break;        case 5:            registerReceiver(myReceiver, new IntentFilter(TelephonyManager.ACTION_PHONE_STATE_CHANGED));            break;        case 6:            try {                unregisterReceiver(myReceiver);            } catch (Exception e) {            }            break;        }    }    /**     * 利用aidl及反射自動掛斷來電。注意,不能通過ContentResolver監聽通話記錄數據庫來掛斷電話,估計是因為電話已接通,不能再掛掉了     */    public void endCall() {        //        IBinder iBinder = ServiceManager.getService(TELEPHONY_SERVICE);//希望調用的方法,但此方法被系統隱藏了        try {            Class<?> clazz = Class.forName("android.os.ServiceManager");//利用反射拿到其字節碼文件            Method method = clazz.getDeclaredMethod("getService", String.class);//獲取ServiceManager類的getService(String s)方法            IBinder ibinder = (IBinder) method.invoke(null, Context.TELEPHONY_SERVICE);//參數為:調用此方法的對象,此方法的參數            ITelephony telephony = ITelephony.Stub.asInterface(ibinder);//把上面getService(String s)得到的IBinder對象轉化成【ITelephony】對象            boolean isSuccess = telephony.endCall();//調用ITelephony掛斷電話的方法            mHandler.sendMessage(Message.obtain(mHandler, 5, "是否成功掛斷電話:" + isSuccess));        } catch (Exception e) {            mHandler.sendMessage(Message.obtain(mHandler, 5, "異常啦" + e.getMessage()));            e.printStackTrace();        }    }    /**監聽來電狀態的廣播*/    class PhoneStateReceiver extends BroadcastReceiver {        @Override        public void onReceive(Context context, Intent intent) {            if (intent != null) {                if (TelephonyManager.EXTRA_STATE_RINGING.equalsIgnoreCase(intent.getStringExtra(TelephonyManager.EXTRA_STATE))) {//來電狀態                    endCall();                }            }        }    }}復制代碼
短信數據庫的ContentObserver復制代碼
/**監聽或獲取手機短信內容的兩種方式 * 方式一:通過注冊廣播監聽短信 *                 這種方式只對新收到的短消息有效,并且系統的這個廣播是有序廣播,現在在一些定制的系統或是有安全軟件的情況下,往往短消息都被截取到,并被干掉。 * 方法二:通過監聽短信數據庫的變化獲取短信 *                 這種方式可以獲取手機上所有的短信,包括已讀未讀的短信,并且不受其它程序干擾 * ContentObserver的使用類似與設計模式中的觀察者模式,ContentObserver是觀察者,被觀察的ContentProvider是被觀察者。 * 當被觀察者ContentProvider的數據發生了增刪改的變化,就會及時的通知給ContentProvider,ContentObsserver做出相應的處理。*/public class SMSContentObserver extends ContentObserver {    private Handler mHandler;    private Context mContext;    /**觀察類型:所有內容或僅收件箱*/    private int observerType;    /**觀察所有內容*/    public static final int MSG_SMS_WHAT = 1;    /**僅觀察收件箱*/    public static final int MSG_SMS_INBOX_WHAT = 2;    public SMSContentObserver(Handler handler, Context context, int observerType) {        super(handler);        this.mHandler = handler;        this.mContext = context;        this.observerType = observerType;    }    @Override    public void onChange(boolean selfChange) {        super.onChange(selfChange);        if (observerType == MSG_SMS_WHAT) {            Uri uri = Uri.parse("content://sms");            Cursor cursor = mContext.getContentResolver().query(uri, new String[] { "_id", "address", "body", "type", "date" }, nullnull, "date desc");            if (cursor != null) {                if (cursor.moveToFirst()) { //最后收到的短信在第一條. This method will return false if the cursor is empty                    int msgId = cursor.getInt(cursor.getColumnIndex("_id"));                    String msgAddr = cursor.getString(cursor.getColumnIndex("address"));                    String msgBody = cursor.getString(cursor.getColumnIndex("body"));                    String msgType = cursor.getString(cursor.getColumnIndex("type"));                    String msgDate = cursor.getString(cursor.getColumnIndex("date"));                    String date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(new Date(Long.parseLong(msgDate)));                    String msgObj = "收件箱/nId:" + msgId + "/n號碼:" + msgAddr + "/n內容:" + msgBody + "/n類型:" + msgType + "/n時間:" + date + "/n";                    mHandler.sendMessage(Message.obtain(mHandler, MSG_SMS_WHAT, msgObj));                }                cursor.close();            }        } else if (observerType == MSG_SMS_INBOX_WHAT) {            Uri uri = Uri.parse("content://sms/inbox");            Cursor cursor = mContext.getContentResolver().query(uri, null, "read = 0", null, "date desc");//Passing null will return all columns, which is inefficient.            //等價于附加條件 if (cursor.getInt(cursor.getColumnIndex("read")) == 0) //表示短信未讀。這種方式不靠譜啊,建議用上面的方式!            if (cursor != null) {                StringBuilder sb = new StringBuilder("未讀短信/n");                while (cursor.moveToNext()) {                    String sendNumber = cursor.getString(cursor.getColumnIndex("address"));                    String body = cursor.getString(cursor.getColumnIndex("body"));                    sb.append("號碼:" + sendNumber + "/n內容:" + body + "/n");                }                mHandler.obtainMessage(MSG_SMS_INBOX_WHAT, sb.toString()).sendToTarget();                cursor.close();            }        }    }}復制代碼
利用反射及aidl調用系統隱藏的方法復制代碼
目的:       利用反射及aidl調用系統隱藏的ServiceManager的getService方法,獲取ITelephony后調用其掛電話的方法步驟:1、copy android源代碼【com.android.internal.telephony】包中的【ITelephony.aidl】到自己的項目        為什么要copy這個文件呢?這是因為接聽/掛斷電話的方法在接口ITelephony.java里面,而這個接口是隱藏的(@hide),我們沒權限調用。2、由于ITelephony.aidl關聯了【android.telephony】包下的【NeighboringCellInfo.aidl】,所以也需把它拷貝過來。        上面完成之后,就會在你的gen目錄下自動生成 ITelephony.java接口文件    3、然后我們就可以利用反射機制來取得ITelephony對象。        為什么要用反射呢?        因為 ITelephony是一個系統服務,要通過【ServiceManager】來獲取,但是ServiceManager同樣也是隱藏的。        所以,我們首先要通過反射機制拿到系統隱藏的ServiceManager對象        然后調用ServiceManager的【getService(String)】方法來取得遠程的【ITelephony】對象, 最后調用ITelephony的endCall()方法掛掉電話權限:    <uses-permission android:name="android.permission.READ_PHONE_STATE" />    <uses-permission android:name="android.permission.CALL_PHONE" />復制代碼
通話記錄數據庫的Observer復制代碼
/** * 撥號記錄的內容觀察者。 */public class CallLogObserver extends ContentObserver {    /**觀察到記錄改變后的處理方式*/    private int type;    /**刪除最近的一條通話記錄*/    public static final int MSG_CALLLOG_DELETE_WHAT = 3;    /**查詢某一個聯系人最近的通話記錄*/    public static final int MSG_CALLLOG_QUERY_WHAT = 4;    public static final String NUMBER = "17084143285";    private Handler mHandler;    private Uri uri = CallLog.Calls.CONTENT_URI;//等價于【Uri.parse("content://call_log/calls")】    private ContentResolver resolver;    public CallLogObserver(Handler handler, Context context, int type) {        super(handler);        this.mHandler = handler;        this.type = type;        resolver = context.getContentResolver();    }    @Override    public void onChange(boolean selfChange) {        Cursor cursor;        switch (type) {        case MSG_CALLLOG_DELETE_WHAT://刪除最近的一條通話記錄            resolver.unregisterContentObserver(this);//注意:增刪改通話記錄后由于數據庫發生變化,所以系統會在修改后再發一條廣播,這時會重新回調onChange方法            //最終導致的結果就是:一次來電后刪除了多條甚至全部通話記錄。為防止這種循環啟發,必須在更改前就取消注冊!事實上,注冊的代碼應該放在廣播接收者中。            cursor = resolver.query(uri, nullnullnull, "_id desc limit 1");//按_id倒序排序后取第一個,即:查詢結果按_id從大到小排序,然后取最上面一個(最近的通話記錄)            if (cursor != null) {                if (cursor.moveToFirst()) {                    int num = resolver.delete(uri, "_id=?", new String[] { cursor.getInt(cursor.getColumnIndex("_id")) + "" });                    mHandler.sendMessage(Message.obtain(mHandler, MSG_CALLLOG_DELETE_WHAT, "刪除的記錄數量:" + num));                }                cursor.close();            }            break;        case MSG_CALLLOG_QUERY_WHAT://查詢某一個聯系人最近的通話記錄            String[] projection = new String[] { "_id", CallLog.Calls.TYPE, CallLog.Calls.NUMBER, CallLog.Calls.CACHED_NAME, CallLog.Calls.DATE, CallLog.Calls.DURATION };            String selection = "number=? and (type=1 or type=3)";            String[] selectionArgs = new String[] { NUMBER };            String sortOrder = CallLog.Calls.DEFAULT_SORT_ORDER;//按時間排序【date DESC】            cursor = resolver.query(uri, projection, selection, selectionArgs, sortOrder);            if (cursor != null) {                if (cursor.moveToFirst()) {                    int _id = cursor.getInt(cursor.getColumnIndex("_id"));                    int type = cursor.getInt(cursor.getColumnIndex("type"));//通話類型,1 來電 .INCOMING_TYPE;2 已撥 .OUTGOING_;3 未接 .MISSED_                    String number = cursor.getString(cursor.getColumnIndex("number"));// 電話號碼                    String name = cursor.getString(cursor.getColumnIndex("name"));//聯系人                    long date = cursor.getLong(cursor.getColumnIndex("date"));//通話時間,即可以用getString接收,也可以用getLong接收                    String formatDate = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss", Locale.getDefault()).format(new Date(date));                    int duration = cursor.getInt(cursor.getColumnIndex("duration"));//通話時長,單位:秒                    String msgObj = "/nID:" + _id + "/n類型:" + type + "/n號碼:" + number + "/n名稱:" + name + "/n時間:" + formatDate + "/n時長:" + duration;                    mHandler.sendMessage(Message.obtain(mHandler, MSG_CALLLOG_QUERY_WHAT, msgObj));                }                cursor.close();            }            break;        }    }}復制代碼
清單文件復制代碼
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"    package="com.itheima.ipdail"    android:versionCode="1"    android:versionName="1.0" >    <uses-permission android:name="android.permission.RECEIVE_SMS" />    <uses-permission android:name="android.permission.READ_SMS" />    <uses-permission android:name="android.permission.READ_CALL_LOG" />    <uses-permission android:name="android.permission.WRITE_CALL_LOG" />    <uses-permission android:name="android.permission.CALL_PHONE" />    <uses-permission android:name="android.permission.READ_PHONE_STATE" />    <uses-sdk        android:minSdkVersion="17"        android:targetSdkVersion="17" />    <application        android:allowBackup="true"        android:icon="@drawable/ic_launcher"        android:label="@string/app_name"        android:theme="@style/APPTheme" >        <activity            android:name=".MainActivity"            android:label="@string/app_name" >            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>        </activity>    </application></manifest>

 

本文固定鏈接: http://www.ithtw.com/624.html轉載請注明: leehom 2015年01月05日 于 IT十萬個為什么 發表

ContentObserver——內容觀察者,目的是觀察(捕捉)特定Uri引起的數據庫的變化,繼而做一些相應的處理,它類似于數據庫技術中的觸發器(Trigger),當ContentObserver所觀察的Uri發生變化時,便會觸發它。觸發器分為表觸發器、行觸發器,相應地ContentObserver也分為“表“ContentObserver、“行”ContentObserver,當然這是與它所監聽的Uri MIME Type有關的。熟悉Content Provider(內容提供者)的應該知道,我們可以通過UriMatcher類注冊不同類型的Uri,我們可以通過這些不同的Uri來查詢不同的結果。根據Uri返回的結果,Uri Type可以分為:返回多條數據的Uri、返回單條數據的Uri。

注冊/取消注冊ContentObserver方法,抽象類ContentResolver類中的方法原型如下:public final void registerContentObserver(Uri uri, boolean notifyForDescendents, ContentObserver observer)功能:為指定的Uri注冊一個ContentObserver派生類實例,當給定的Uri發生改變時,回調該實例對象去處理。參數:uri 需要觀察的Uri(需要在UriMatcher里注冊,否則該Uri也沒有意義了)notifyForDescendents 為false 表示精確匹配,即只匹配該Uri

觀察系統里短消息的數據庫變化的ContentObserver派生類,SMSContentObserver.java

雙擊【CTRL+C】復制
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152importandroid.content.Context;  importandroid.database.ContentObserver;  importandroid.database.Cursor;  importandroid.net.Uri;  importandroid.os.Handler;  importandroid.util.Log;        //用來觀察系統里短消息的數據庫變化  ”表“內容觀察者,只要信息數據庫發生變化,都會觸發該ContentObserver 派生類  publicclass SMSContentObserver extendsContentObserver {      privatestatic String TAG = "SMSContentObserver"           privateint MSG_OUTBOXCONTENT = 2           privateContext mContext  ;      privateHandler mHandler ;   //更新UI線程            publicSMSContentObserver(Context context,Handler handler) {          super(handler);         mContext = context ;          mHandler = handler ;          /**     * 當所監聽的Uri發生改變時,就會回調此方法           * @param selfChange  此值意義不大 一般情況下該回調值false      */     @Override     publicvoid onChange(booleanselfChange){          Log.i(TAG,"the sms table has changed");                    //查詢發件箱里的內容              Uri outSMSUri = Uri.parse("content://sms/sent") ;                     Cursor c = mContext.getContentResolver().query(outSMSUri, null,null,null,"date desc");         if(c != null){                            Log.i(TAG,"the number of send is"+c.getCount()) ;                             StringBuilder sb = newStringBuilder() ;              //循環遍歷             while(c.moveToNext()){                 sb.append("發件人手機號碼: "+c.getInt(c.getColumnIndex("address")))                   .append("信息內容: "+c.getString(c.getColumnIndex("body")))                   .append("/n");                         c.close();                       mHandler.obtainMessage(MSG_OUTBOXCONTENT, sb.toString()).sendToTarget();                             

主工程邏輯為MainActivity.java,對短消息的觀察Uri,通過測試我發現只能監聽此Uri “content://sms” (等同于"content://sms/"),而不能監聽其他的Uri,比如"content://sms/outbox"等。

雙擊【CTRL+C】復制
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748importandroid.app.Activity;  importandroid.database.Cursor;  importandroid.net.Uri;  importandroid.os.Bundle;  importandroid.os.Handler;  importandroid.os.Message;  importandroid.provider.*;  importandroid.util.Log;  importandroid.widget.EditText;  importandroid.widget.TextView;     publicclass MainActivity extendsActivity {         privateTextView tvAirplane;      privateEditText etSmsoutbox;         privateSMSContentObserver smsContentObserver;         /** Called when the activity is first created. */     @Override     publicvoid onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);         setContentView(R.layout.main);            etSmsoutbox = (EditText) findViewById(R.id.smsoutboxContent);             smsContentObserver = newSMSContentObserver(this, mHandler);                     //注冊內容觀察者         registerContentObservers() ;             privatevoid registerContentObservers() {          // ”表“內容觀察者 ,通過測試我發現只能監聽此Uri -----> content://sms          // 監聽不到其他的Uri 比如說 content://sms/outbox          Uri smsUri = Uri.parse("content://sms");         getContentResolver().registerContentObserver(smsUri,true,smsContentObserver);            privateHandler mHandler = newHandler() {             publicvoid handleMessage(Message msg) {                  String outbox = (String) msg.obj;                  etSmsoutbox.setText(outbox);                         }; 
Activity復制代碼
public class MainActivity extends ListActivity {    private TextView tv_info;    private SMSContentObserver smsContentObserver;    private CallLogObserver callLogObserver;    private PhoneStateReceiver myReceiver;    @SuppressLint("HandlerLeak")    private Handler mHandler = new Handler() {        public void handleMessage(Message msg) {            String msgBody = (String) msg.obj;            tv_info.setText(msg.obj + ":" + msgBody);        }    };    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        String[] array = { "注冊短信數據庫變化的觀察者", "收件箱數據庫……", "刪除新來電的通話記錄", "監聽新來電通話記錄的詳細信息", "取消注冊Observer",//                "注冊電話狀態改變的廣播,當有來電時立即掛斷電話", "取消注冊廣播", };        for (int i = 0; i < array.length; i++) {            array[i] = i + "、" + array[i];        }        ListAdapter mAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, new ArrayList<String>(Arrays.asList(array)));        tv_info = new TextView(this);// 將內容顯示在TextView中        tv_info.setTextColor(Color.BLUE);        tv_info.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);        tv_info.setPadding(20, 10, 20, 10);        getListView().addFooterView(tv_info);        setListAdapter(mAdapter);        myReceiver = new PhoneStateReceiver();    }    @Override    protected void onListItemClick(ListView l, View v, int position, long id) {        switch (position) {        case 0:            smsContentObserver = new SMSContentObserver(mHandler, this, SMSContentObserver.MSG_SMS_WHAT);            getContentResolver().registerContentObserver(Uri.parse("content://sms"), true, smsContentObserver);            // boolean notifyForDescendents(后裔):若為true,則監視所有以指定的Uri開頭的Uri;若為false,則只精確的監視指定的URI            break;        case 1:            smsContentObserver = new SMSContentObserver(mHandler, this, SMSContentObserver.MSG_SMS_INBOX_WHAT);            getContentResolver().registerContentObserver(Uri.parse("content://sms/inbox"), true, smsContentObserver);            break;        case 2:            callLogObserver = new CallLogObserver(mHandler, this, CallLogObserver.MSG_CALLLOG_DELETE_WHAT);            getContentResolver().registerContentObserver(Uri.parse("content://call_log/calls"), true, callLogObserver);            break;        case 3:            callLogObserver = new CallLogObserver(mHandler, this, CallLogObserver.MSG_CALLLOG_QUERY_WHAT);            getContentResolver().registerContentObserver(CallLog.Calls.CONTENT_URI, true, callLogObserver);//等價于【Uri.parse("content://call_log/calls")】            break;        case 4:            if (smsContentObserver != null) getContentResolver().unregisterContentObserver(smsContentObserver);            if (callLogObserver != null) getContentResolver().unregisterContentObserver(callLogObserver);            break;        case 5:            registerReceiver(myReceiver, new IntentFilter(TelephonyManager.ACTION_PHONE_STATE_CHANGED));            break;        case 6:            try {                unregisterReceiver(myReceiver);            } catch (Exception e) {            }            break;        }    }    /**     * 利用aidl及反射自動掛斷來電。注意,不能通過ContentResolver監聽通話記錄數據庫來掛斷電話,估計是因為電話已接通,不能再掛掉了     */    public void endCall() {        //        IBinder iBinder = ServiceManager.getService(TELEPHONY_SERVICE);//希望調用的方法,但此方法被系統隱藏了        try {            Class<?> clazz = Class.forName("android.os.ServiceManager");//利用反射拿到其字節碼文件            Method method = clazz.getDeclaredMethod("getService", String.class);//獲取ServiceManager類的getService(String s)方法            IBinder ibinder = (IBinder) method.invoke(null, Context.TELEPHONY_SERVICE);//參數為:調用此方法的對象,此方法的參數            ITelephony telephony = ITelephony.Stub.asInterface(ibinder);//把上面getService(String s)得到的IBinder對象轉化成【ITelephony】對象            boolean isSuccess = telephony.endCall();//調用ITelephony掛斷電話的方法            mHandler.sendMessage(Message.obtain(mHandler, 5, "是否成功掛斷電話:" + isSuccess));        } catch (Exception e) {            mHandler.sendMessage(Message.obtain(mHandler, 5, "異常啦" + e.getMessage()));            e.printStackTrace();        }    }    /**監聽來電狀態的廣播*/    class PhoneStateReceiver extends BroadcastReceiver {        @Override        public void onReceive(Context context, Intent intent) {            if (intent != null) {                if (TelephonyManager.EXTRA_STATE_RINGING.equalsIgnoreCase(intent.getStringExtra(TelephonyManager.EXTRA_STATE))) {//來電狀態                    endCall();                }            }        }    }}復制代碼
短信數據庫的ContentObserver復制代碼
/**監聽或獲取手機短信內容的兩種方式 * 方式一:通過注冊廣播監聽短信 *                 這種方式只對新收到的短消息有效,并且系統的這個廣播是有序廣播,現在在一些定制的系統或是有安全軟件的情況下,往往短消息都被截取到,并被干掉。 * 方法二:通過監聽短信數據庫的變化獲取短信 *                 這種方式可以獲取手機上所有的短信,包括已讀未讀的短信,并且不受其它程序干擾 * ContentObserver的使用類似與設計模式中的觀察者模式,ContentObserver是觀察者,被觀察的ContentProvider是被觀察者。 * 當被觀察者ContentProvider的數據發生了增刪改的變化,就會及時的通知給ContentProvider,ContentObsserver做出相應的處理。*/public class SMSContentObserver extends ContentObserver {    private Handler mHandler;    private Context mContext;    /**觀察類型:所有內容或僅收件箱*/    private int observerType;    /**觀察所有內容*/    public static final int MSG_SMS_WHAT = 1;    /**僅觀察收件箱*/    public static final int MSG_SMS_INBOX_WHAT = 2;    public SMSContentObserver(Handler handler, Context context, int observerType) {        super(handler);        this.mHandler = handler;        this.mContext = context;        this.observerType = observerType;    }    @Override    public void onChange(boolean selfChange) {        super.onChange(selfChange);        if (observerType == MSG_SMS_WHAT) {            Uri uri = Uri.parse("content://sms");            Cursor cursor = mContext.getContentResolver().query(uri, new String[] { "_id", "address", "body", "type", "date" }, null, null, "date desc");            if (cursor != null) {                if (cursor.moveToFirst()) { //最后收到的短信在第一條. This method will return false if the cursor is empty                    int msgId = cursor.getInt(cursor.getColumnIndex("_id"));                    String msgAddr = cursor.getString(cursor.getColumnIndex("address"));                    String msgBody = cursor.getString(cursor.getColumnIndex("body"));                    String msgType = cursor.getString(cursor.getColumnIndex("type"));                    String msgDate = cursor.getString(cursor.getColumnIndex("date"));                    String date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(new Date(Long.parseLong(msgDate)));                    String msgObj = "收件箱/nId:" + msgId + "/n號碼:" + msgAddr + "/n內容:" + msgBody + "/n類型:" + msgType + "/n時間:" + date + "/n";                    mHandler.sendMessage(Message.obtain(mHandler, MSG_SMS_WHAT, msgObj));                }                cursor.close();            }        } else if (observerType == MSG_SMS_INBOX_WHAT) {            Uri uri = Uri.parse("content://sms/inbox");            Cursor cursor = mContext.getContentResolver().query(uri, null, "read = 0", null, "date desc");//Passing null will return all columns, which is inefficient.            //等價于附加條件 if (cursor.getInt(cursor.getColumnIndex("read")) == 0) //表示短信未讀。這種方式不靠譜啊,建議用上面的方式!            if (cursor != null) {                StringBuilder sb = new StringBuilder("未讀短信/n");                while (cursor.moveToNext()) {                    String sendNumber = cursor.getString(cursor.getColumnIndex("address"));                    String body = cursor.getString(cursor.getColumnIndex("body"));                    sb.append("號碼:" + sendNumber + "/n內容:" + body + "/n");                }                mHandler.obtainMessage(MSG_SMS_INBOX_WHAT, sb.toString()).sendToTarget();                cursor.close();            }        }    }}復制代碼
利用反射及aidl調用系統隱藏的方法復制代碼
目的:       利用反射及aidl調用系統隱藏的ServiceManager的getService方法,獲取ITelephony后調用其掛電話的方法步驟:1、copy android源代碼【com.android.internal.telephony】包中的【ITelephony.aidl】到自己的項目        為什么要copy這個文件呢?這是因為接聽/掛斷電話的方法在接口ITelephony.java里面,而這個接口是隱藏的(@hide),我們沒權限調用。2、由于ITelephony.aidl關聯了【android.telephony】包下的【NeighboringCellInfo.aidl】,所以也需把它拷貝過來。        上面完成之后,就會在你的gen目錄下自動生成 ITelephony.java接口文件    3、然后我們就可以利用反射機制來取得ITelephony對象。        為什么要用反射呢?        因為 ITelephony是一個系統服務,要通過【ServiceManager】來獲取,但是ServiceManager同樣也是隱藏的。        所以,我們首先要通過反射機制拿到系統隱藏的ServiceManager對象        然后調用ServiceManager的【getService(String)】方法來取得遠程的【ITelephony】對象, 最后調用ITelephony的endCall()方法掛掉電話權限:    <uses-permission android:name="android.permission.READ_PHONE_STATE" />    <uses-permission android:name="android.permission.CALL_PHONE" />復制代碼
通話記錄數據庫的Observer復制代碼
/** * 撥號記錄的內容觀察者。 */public class CallLogObserver extends ContentObserver {    /**觀察到記錄改變后的處理方式*/    private int type;    /**刪除最近的一條通話記錄*/    public static final int MSG_CALLLOG_DELETE_WHAT = 3;    /**查詢某一個聯系人最近的通話記錄*/    public static final int MSG_CALLLOG_QUERY_WHAT = 4;    public static final String NUMBER = "17084143285";    private Handler mHandler;    private Uri uri = CallLog.Calls.CONTENT_URI;//等價于【Uri.parse("content://call_log/calls")】    private ContentResolver resolver;    public CallLogObserver(Handler handler, Context context, int type) {        super(handler);        this.mHandler = handler;        this.type = type;        resolver = context.getContentResolver();    }    @Override    public void onChange(boolean selfChange) {        Cursor cursor;        switch (type) {        case MSG_CALLLOG_DELETE_WHAT://刪除最近的一條通話記錄            resolver.unregisterContentObserver(this);//注意:增刪改通話記錄后由于數據庫發生變化,所以系統會在修改后再發一條廣播,這時會重新回調onChange方法            //最終導致的結果就是:一次來電后刪除了多條甚至全部通話記錄。為防止這種循環啟發,必須在更改前就取消注冊!事實上,注冊的代碼應該放在廣播接收者中。            cursor = resolver.query(uri, null, null, null, "_id desc limit 1");//按_id倒序排序后取第一個,即:查詢結果按_id從大到小排序,然后取最上面一個(最近的通話記錄)            if (cursor != null) {                if (cursor.moveToFirst()) {                    int num = resolver.delete(uri, "_id=?", new String[] { cursor.getInt(cursor.getColumnIndex("_id")) + "" });                    mHandler.sendMessage(Message.obtain(mHandler, MSG_CALLLOG_DELETE_WHAT, "刪除的記錄數量:" + num));                }                cursor.close();            }            break;        case MSG_CALLLOG_QUERY_WHAT://查詢某一個聯系人最近的通話記錄            String[] projection = new String[] { "_id", CallLog.Calls.TYPE, CallLog.Calls.NUMBER, CallLog.Calls.CACHED_NAME, CallLog.Calls.DATE, CallLog.Calls.DURATION };            String selection = "number=? and (type=1 or type=3)";            String[] selectionArgs = new String[] { NUMBER };            String sortOrder = CallLog.Calls.DEFAULT_SORT_ORDER;//按時間排序【date DESC】            cursor = resolver.query(uri, projection, selection, selectionArgs, sortOrder);            if (cursor != null) {                if (cursor.moveToFirst()) {                    int _id = cursor.getInt(cursor.getColumnIndex("_id"));                    int type = cursor.getInt(cursor.getColumnIndex("type"));//通話類型,1 來電 .INCOMING_TYPE;2 已撥 .OUTGOING_;3 未接 .MISSED_                    String number = cursor.getString(cursor.getColumnIndex("number"));// 電話號碼                    String name = cursor.getString(cursor.getColumnIndex("name"));//聯系人                    long date = cursor.getLong(cursor.getColumnIndex("date"));//通話時間,即可以用getString接收,也可以用getLong接收                    String formatDate = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss", Locale.getDefault()).format(new Date(date));                    int duration = cursor.getInt(cursor.getColumnIndex("duration"));//通話時長,單位:秒                    String msgObj = "/nID:" + _id + "/n類型:" + type + "/n號碼:" + number + "/n名稱:" + name + "/n時間:" + formatDate + "/n時長:" + duration;                    mHandler.sendMessage(Message.obtain(mHandler, MSG_CALLLOG_QUERY_WHAT, msgObj));                }                cursor.close();            }            break;        }    }}復制代碼
清單文件復制代碼
<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"    package="com.itheima.ipdail"    android:versionCode="1"    android:versionName="1.0" >    <uses-permission android:name="android.permission.RECEIVE_SMS" />    <uses-permission android:name="android.permission.READ_SMS" />    <uses-permission android:name="android.permission.READ_CALL_LOG" />    <uses-permission android:name="android.permission.WRITE_CALL_LOG" />    <uses-permission android:name="android.permission.CALL_PHONE" />    <uses-permission android:name="android.permission.READ_PHONE_STATE" />    <uses-sdk        android:minSdkVersion="17"        android:targetSdkVersion="17" />    <application        android:allowBackup="true"        android:icon="@drawable/ic_launcher"        android:label="@string/app_name"        android:theme="@style/AppTheme" >        <activity            android:name=".MainActivity"            android:label="@string/app_name" >            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>        </activity>    </application></manifest>
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
午夜精品一区二区三区在线| 456亚洲影院| 成人在线中文字幕| 日韩电视剧在线观看免费网站| 欧美网站在线观看| 97视频在线观看免费| 欧美中文字幕在线视频| 粉嫩老牛aⅴ一区二区三区| 91av在线不卡| 大桥未久av一区二区三区| 亚洲欧美福利视频| 国产精品福利片| 91在线播放国产| 久久中国妇女中文字幕| 精品国产一区二区三区久久| 日韩av在线导航| 日韩精品在线电影| 久久久久久亚洲精品| 亚洲免费中文字幕| 在线观看精品自拍私拍| 国产精品h在线观看| 成人国产亚洲精品a区天堂华泰| 亚洲激情在线观看| 亚洲成人黄色网址| 久久久久国产一区二区三区| 国产日韩在线一区| 亚洲精选中文字幕| 国产精品久久一区主播| 亚洲影影院av| 国产在线观看91精品一区| 亚洲免费视频一区二区| zzijzzij亚洲日本成熟少妇| 福利视频一区二区| 成人精品在线观看| 亚洲综合中文字幕在线观看| 国产视频久久久| 国产精品久久久久国产a级| 国产精品va在线播放我和闺蜜| 久久99久久99精品免观看粉嫩| 欧美中文字幕第一页| 亚洲专区国产精品| 国产精品成人一区| 精品视频偷偷看在线观看| 久久久久国产一区二区三区| 亚洲国产日韩欧美在线图片| 成人黄色午夜影院| 在线日韩av观看| 97精品欧美一区二区三区| 日韩美女在线看| 久久中文精品视频| 成人黄色生活片| 欧美成人免费一级人片100| 国产精品美女在线| 欧美大全免费观看电视剧大泉洋| 91极品女神在线| 久久久久久久影视| 亚洲va国产va天堂va久久| xxxx欧美18另类的高清| 亚洲视频999| 国产精品男人的天堂| 69av视频在线播放| 国产精品偷伦视频免费观看国产| 日韩成人在线网站| 国产精品男女猛烈高潮激情| 亚洲缚视频在线观看| 91经典在线视频| 日韩视频第一页| 日韩美女写真福利在线观看| 精品久久久久久久久久ntr影视| 国产一区二区三区视频在线观看| xxx成人少妇69| 韩国三级日本三级少妇99| 日韩在线视频线视频免费网站| 国产一区二区在线播放| 亚洲第一级黄色片| 亚洲日韩欧美视频一区| 欧美午夜精品在线| 久久久精品影院| 欧美激情xxxx| 欧美性色xo影院| 成人国内精品久久久久一区| 色偷偷88888欧美精品久久久| 精品国偷自产在线视频| 日韩欧美亚洲国产一区| 国产主播精品在线| 深夜福利亚洲导航| 国产91精品视频在线观看| 91在线视频导航| 精品日韩中文字幕| 中文字幕在线国产精品| 国产精品直播网红| 日韩成人在线播放| 亚洲永久免费观看| 亚洲白拍色综合图区| 91av国产在线| 欧美国产精品va在线观看| 亚洲美腿欧美激情另类| 国产成人久久久| 91久久国产综合久久91精品网站| 国产一区二区欧美日韩| www.亚洲成人| 久久精品国产亚洲精品| 国产精品1区2区在线观看| 国产一区二区av| 欧美一级大片视频| 欧美在线视频在线播放完整版免费观看| 综合av色偷偷网| 欧美激情欧美激情在线五月| 国产国语videosex另类| 国产美女久久精品香蕉69| 永久免费精品影视网站| 欧美人在线观看| 福利一区福利二区微拍刺激| 成人性生交xxxxx网站| 亚洲xxxx做受欧美| 中文在线不卡视频| 亚洲黄色免费三级| 国产在线日韩在线| 国产精品一区二区女厕厕| 欧美日韩精品在线观看| 一本色道久久88精品综合| 欧美一级大片在线观看| 色综合老司机第九色激情| 国产欧美日韩综合精品| 久久久久久久国产| 亚洲一区二区中文字幕| 欧美日本高清一区| 一本一本久久a久久精品牛牛影视| 91豆花精品一区| 91久久综合亚洲鲁鲁五月天| 九九热r在线视频精品| 欧美性高跟鞋xxxxhd| 久久久久久成人| 中文字幕视频一区二区在线有码| xvideos成人免费中文版| 日韩在线视频线视频免费网站| 国产精品丝袜高跟| 亚洲黄页视频免费观看| 亚洲美女精品成人在线视频| 欧美一级电影免费在线观看| 国产va免费精品高清在线| 国产在线高清精品| 国产精品视频男人的天堂| 欧美黑人性生活视频| 中文字幕av一区二区三区谷原希美| 自拍偷拍亚洲一区| 国产成人精品久久二区二区| 国产成+人+综合+亚洲欧洲| 久久av中文字幕| 日韩风俗一区 二区| 亚洲视频在线播放| 一区二区三欧美| 欧美黄网免费在线观看| 色妞久久福利网| 日韩视频欧美视频| 亚洲国产精品成人一区二区| 欧美激情久久久| 精品国产一区二区三区久久久狼| 亚洲а∨天堂久久精品9966| 亚洲少妇中文在线| 欧美一性一乱一交一视频| 国产乱人伦真实精品视频| 久久久久久久久综合| 成人激情在线播放|