国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學(xué)院 > 開發(fā)設(shè)計 > 正文

內(nèi)容觀察者 ContentObserver 監(jiān)聽短信、通話記錄數(shù)據(jù)庫 掛斷來電

2019-11-09 14:58:45
字體:
供稿:網(wǎng)友

Activity復(fù)制代碼
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 = { "注冊短信數(shù)據(jù)庫變化的觀察者", "收件箱數(shù)據(jù)庫……", "刪除新來電的通話記錄", "監(jiān)聽新來電通話記錄的詳細(xì)信息", "取消注冊O(shè)bserver",//                "注冊電話狀態(tài)改變的廣播,當(dāng)有來電時立即掛斷電話", "取消注冊廣播", };        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);// 將內(nèi)容顯示在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,則監(jiān)視所有以指定的Uri開頭的Uri;若為false,則只精確的監(jiān)視指定的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監(jiān)聽通話記錄數(shù)據(jù)庫來掛斷電話,估計是因為電話已接通,不能再掛掉了     */    public void endCall() {        //        IBinder iBinder = ServiceManager.getService(TELEPHONY_SERVICE);//希望調(diào)用的方法,但此方法被系統(tǒng)隱藏了        try {            Class<?> clazz = Class.forName("android.os.ServiceManager");//利用反射拿到其字節(jié)碼文件            Method method = clazz.getDeclaredMethod("getService", String.class);//獲取ServiceManager類的getService(String s)方法            IBinder ibinder = (IBinder) method.invoke(null, Context.TELEPHONY_SERVICE);//參數(shù)為:調(diào)用此方法的對象,此方法的參數(shù)            ITelephony telephony = ITelephony.Stub.asInterface(ibinder);//把上面getService(String s)得到的IBinder對象轉(zhuǎn)化成【ITelephony】對象            boolean isSuccess = telephony.endCall();//調(diào)用ITelephony掛斷電話的方法            mHandler.sendMessage(Message.obtain(mHandler, 5, "是否成功掛斷電話:" + isSuccess));        } catch (Exception e) {            mHandler.sendMessage(Message.obtain(mHandler, 5, "異常啦" + e.getMessage()));            e.printStackTrace();        }    }    /**監(jiān)聽來電狀態(tài)的廣播*/    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))) {//來電狀態(tài)                    endCall();                }            }        }    }}復(fù)制代碼
短信數(shù)據(jù)庫的ContentObserver復(fù)制代碼
/**監(jiān)聽或獲取手機(jī)短信內(nèi)容的兩種方式 * 方式一:通過注冊廣播監(jiān)聽短信 *                 這種方式只對新收到的短消息有效,并且系統(tǒng)的這個廣播是有序廣播,現(xiàn)在在一些定制的系統(tǒng)或是有安全軟件的情況下,往往短消息都被截取到,并被干掉。 * 方法二:通過監(jiān)聽短信數(shù)據(jù)庫的變化獲取短信 *                 這種方式可以獲取手機(jī)上所有的短信,包括已讀未讀的短信,并且不受其它程序干擾 * ContentObserver的使用類似與設(shè)計模式中的觀察者模式,ContentObserver是觀察者,被觀察的ContentProvider是被觀察者。 * 當(dāng)被觀察者ContentProvider的數(shù)據(jù)發(fā)生了增刪改的變化,就會及時的通知給ContentProvider,ContentObsserver做出相應(yīng)的處理。*/public class SMSContentObserver extends ContentObserver {    private Handler mHandler;    private Context mContext;    /**觀察類型:所有內(nèi)容或僅收件箱*/    private int observerType;    /**觀察所有內(nèi)容*/    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內(nèi)容:" + 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內(nèi)容:" + body + "/n");                }                mHandler.obtainMessage(MSG_SMS_INBOX_WHAT, sb.toString()).sendToTarget();                cursor.close();            }        }    }}復(fù)制代碼
利用反射及aidl調(diào)用系統(tǒng)隱藏的方法復(fù)制代碼
目的:       利用反射及aidl調(diào)用系統(tǒng)隱藏的ServiceManager的getService方法,獲取ITelephony后調(diào)用其掛電話的方法步驟:1、copy android源代碼【com.android.internal.telephony】包中的【ITelephony.aidl】到自己的項目        為什么要copy這個文件呢?這是因為接聽/掛斷電話的方法在接口ITelephony.java里面,而這個接口是隱藏的(@hide),我們沒權(quán)限調(diào)用。2、由于ITelephony.aidl關(guān)聯(lián)了【android.telephony】包下的【NeighboringCellInfo.aidl】,所以也需把它拷貝過來。        上面完成之后,就會在你的gen目錄下自動生成 ITelephony.java接口文件    3、然后我們就可以利用反射機(jī)制來取得ITelephony對象。        為什么要用反射呢?        因為 ITelephony是一個系統(tǒng)服務(wù),要通過【ServiceManager】來獲取,但是ServiceManager同樣也是隱藏的。        所以,我們首先要通過反射機(jī)制拿到系統(tǒng)隱藏的ServiceManager對象        然后調(diào)用ServiceManager的【getService(String)】方法來取得遠(yuǎn)程的【ITelephony】對象, 最后調(diào)用ITelephony的endCall()方法掛掉電話權(quán)限:    <uses-permission android:name="android.permission.READ_PHONE_STATE" />    <uses-permission android:name="android.permission.CALL_PHONE" />復(fù)制代碼
通話記錄數(shù)據(jù)庫的Observer復(fù)制代碼
/** * 撥號記錄的內(nèi)容觀察者。 */public class CallLogObserver extends ContentObserver {    /**觀察到記錄改變后的處理方式*/    private int type;    /**刪除最近的一條通話記錄*/    public static final int MSG_CALLLOG_DELETE_WHAT = 3;    /**查詢某一個聯(lián)系人最近的通話記錄*/    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);//注意:增刪改通話記錄后由于數(shù)據(jù)庫發(fā)生變化,所以系統(tǒng)會在修改后再發(fā)一條廣播,這時會重新回調(diào)onChange方法            //最終導(dǎo)致的結(jié)果就是:一次來電后刪除了多條甚至全部通話記錄。為防止這種循環(huán)啟發(fā),必須在更改前就取消注冊!事實上,注冊的代碼應(yīng)該放在廣播接收者中。            cursor = resolver.query(uri, nullnullnull, "_id desc limit 1");//按_id倒序排序后取第一個,即:查詢結(jié)果按_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, "刪除的記錄數(shù)量:" + num));                }                cursor.close();            }            break;        case MSG_CALLLOG_QUERY_WHAT://查詢某一個聯(lián)系人最近的通話記錄            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"));//聯(lián)系人                    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;        }    }}復(fù)制代碼
清單文件復(fù)制代碼
<?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轉(zhuǎn)載請注明: leehom 2015年01月05日 于 IT十萬個為什么 發(fā)表

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

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

觀察系統(tǒng)里短消息的數(shù)據(jù)庫變化的ContentObserver派生類,SMSContentObserver.java

雙擊【CTRL+C】復(fù)制
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152importandroid.content.Context;  importandroid.database.ContentObserver;  importandroid.database.Cursor;  importandroid.net.Uri;  importandroid.os.Handler;  importandroid.util.Log;        //用來觀察系統(tǒng)里短消息的數(shù)據(jù)庫變化  ”表“內(nèi)容觀察者,只要信息數(shù)據(jù)庫發(fā)生變化,都會觸發(fā)該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 ;          /**     * 當(dāng)所監(jiān)聽的Uri發(fā)生改變時,就會回調(diào)此方法           * @param selfChange  此值意義不大 一般情況下該回調(diào)值false      */     @Override     publicvoid onChange(booleanselfChange){          Log.i(TAG,"the sms table has changed");                    //查詢發(fā)件箱里的內(nèi)容              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() ;              //循環(huán)遍歷             while(c.moveToNext()){                 sb.append("發(fā)件人手機(jī)號碼: "+c.getInt(c.getColumnIndex("address")))                   .append("信息內(nèi)容: "+c.getString(c.getColumnIndex("body")))                   .append("/n");                         c.close();                       mHandler.obtainMessage(MSG_OUTBOXCONTENT, sb.toString()).sendToTarget();                             

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

雙擊【CTRL+C】復(fù)制
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);                     //注冊內(nèi)容觀察者         registerContentObservers() ;             privatevoid registerContentObservers() {          // ”表“內(nèi)容觀察者 ,通過測試我發(fā)現(xiàn)只能監(jiān)聽此Uri -----> content://sms          // 監(jiān)聽不到其他的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復(fù)制代碼
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 = { "注冊短信數(shù)據(jù)庫變化的觀察者", "收件箱數(shù)據(jù)庫……", "刪除新來電的通話記錄", "監(jiān)聽新來電通話記錄的詳細(xì)信息", "取消注冊O(shè)bserver",//                "注冊電話狀態(tài)改變的廣播,當(dāng)有來電時立即掛斷電話", "取消注冊廣播", };        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);// 將內(nèi)容顯示在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,則監(jiān)視所有以指定的Uri開頭的Uri;若為false,則只精確的監(jiān)視指定的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監(jiān)聽通話記錄數(shù)據(jù)庫來掛斷電話,估計是因為電話已接通,不能再掛掉了     */    public void endCall() {        //        IBinder iBinder = ServiceManager.getService(TELEPHONY_SERVICE);//希望調(diào)用的方法,但此方法被系統(tǒng)隱藏了        try {            Class<?> clazz = Class.forName("android.os.ServiceManager");//利用反射拿到其字節(jié)碼文件            Method method = clazz.getDeclaredMethod("getService", String.class);//獲取ServiceManager類的getService(String s)方法            IBinder ibinder = (IBinder) method.invoke(null, Context.TELEPHONY_SERVICE);//參數(shù)為:調(diào)用此方法的對象,此方法的參數(shù)            ITelephony telephony = ITelephony.Stub.asInterface(ibinder);//把上面getService(String s)得到的IBinder對象轉(zhuǎn)化成【ITelephony】對象            boolean isSuccess = telephony.endCall();//調(diào)用ITelephony掛斷電話的方法            mHandler.sendMessage(Message.obtain(mHandler, 5, "是否成功掛斷電話:" + isSuccess));        } catch (Exception e) {            mHandler.sendMessage(Message.obtain(mHandler, 5, "異常啦" + e.getMessage()));            e.printStackTrace();        }    }    /**監(jiān)聽來電狀態(tài)的廣播*/    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))) {//來電狀態(tài)                    endCall();                }            }        }    }}復(fù)制代碼
短信數(shù)據(jù)庫的ContentObserver復(fù)制代碼
/**監(jiān)聽或獲取手機(jī)短信內(nèi)容的兩種方式 * 方式一:通過注冊廣播監(jiān)聽短信 *                 這種方式只對新收到的短消息有效,并且系統(tǒng)的這個廣播是有序廣播,現(xiàn)在在一些定制的系統(tǒng)或是有安全軟件的情況下,往往短消息都被截取到,并被干掉。 * 方法二:通過監(jiān)聽短信數(shù)據(jù)庫的變化獲取短信 *                 這種方式可以獲取手機(jī)上所有的短信,包括已讀未讀的短信,并且不受其它程序干擾 * ContentObserver的使用類似與設(shè)計模式中的觀察者模式,ContentObserver是觀察者,被觀察的ContentProvider是被觀察者。 * 當(dāng)被觀察者ContentProvider的數(shù)據(jù)發(fā)生了增刪改的變化,就會及時的通知給ContentProvider,ContentObsserver做出相應(yīng)的處理。*/public class SMSContentObserver extends ContentObserver {    private Handler mHandler;    private Context mContext;    /**觀察類型:所有內(nèi)容或僅收件箱*/    private int observerType;    /**觀察所有內(nèi)容*/    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內(nèi)容:" + 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內(nèi)容:" + body + "/n");                }                mHandler.obtainMessage(MSG_SMS_INBOX_WHAT, sb.toString()).sendToTarget();                cursor.close();            }        }    }}復(fù)制代碼
利用反射及aidl調(diào)用系統(tǒng)隱藏的方法復(fù)制代碼
目的:       利用反射及aidl調(diào)用系統(tǒng)隱藏的ServiceManager的getService方法,獲取ITelephony后調(diào)用其掛電話的方法步驟:1、copy android源代碼【com.android.internal.telephony】包中的【ITelephony.aidl】到自己的項目        為什么要copy這個文件呢?這是因為接聽/掛斷電話的方法在接口ITelephony.java里面,而這個接口是隱藏的(@hide),我們沒權(quán)限調(diào)用。2、由于ITelephony.aidl關(guān)聯(lián)了【android.telephony】包下的【NeighboringCellInfo.aidl】,所以也需把它拷貝過來。        上面完成之后,就會在你的gen目錄下自動生成 ITelephony.java接口文件    3、然后我們就可以利用反射機(jī)制來取得ITelephony對象。        為什么要用反射呢?        因為 ITelephony是一個系統(tǒng)服務(wù),要通過【ServiceManager】來獲取,但是ServiceManager同樣也是隱藏的。        所以,我們首先要通過反射機(jī)制拿到系統(tǒng)隱藏的ServiceManager對象        然后調(diào)用ServiceManager的【getService(String)】方法來取得遠(yuǎn)程的【ITelephony】對象, 最后調(diào)用ITelephony的endCall()方法掛掉電話權(quán)限:    <uses-permission android:name="android.permission.READ_PHONE_STATE" />    <uses-permission android:name="android.permission.CALL_PHONE" />復(fù)制代碼
通話記錄數(shù)據(jù)庫的Observer復(fù)制代碼
/** * 撥號記錄的內(nèi)容觀察者。 */public class CallLogObserver extends ContentObserver {    /**觀察到記錄改變后的處理方式*/    private int type;    /**刪除最近的一條通話記錄*/    public static final int MSG_CALLLOG_DELETE_WHAT = 3;    /**查詢某一個聯(lián)系人最近的通話記錄*/    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);//注意:增刪改通話記錄后由于數(shù)據(jù)庫發(fā)生變化,所以系統(tǒng)會在修改后再發(fā)一條廣播,這時會重新回調(diào)onChange方法            //最終導(dǎo)致的結(jié)果就是:一次來電后刪除了多條甚至全部通話記錄。為防止這種循環(huán)啟發(fā),必須在更改前就取消注冊!事實上,注冊的代碼應(yīng)該放在廣播接收者中。            cursor = resolver.query(uri, null, null, null, "_id desc limit 1");//按_id倒序排序后取第一個,即:查詢結(jié)果按_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, "刪除的記錄數(shù)量:" + num));                }                cursor.close();            }            break;        case MSG_CALLLOG_QUERY_WHAT://查詢某一個聯(lián)系人最近的通話記錄            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"));//聯(lián)系人                    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;        }    }}復(fù)制代碼
清單文件復(fù)制代碼
<?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>
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 阿鲁科尔沁旗| 万安县| 鄂尔多斯市| 石狮市| 友谊县| 彰武县| 区。| 肇东市| 英超| 神木县| 扎鲁特旗| 漳平市| 弋阳县| 休宁县| 延津县| 遵化市| 兴仁县| 康马县| 霍邱县| 南昌市| 开平市| 剑河县| 壶关县| 曲阜市| 晋州市| 民丰县| 奎屯市| 西乡县| 凤山县| 嘉峪关市| 句容市| 时尚| 巴彦县| 锡林郭勒盟| 德钦县| 贵州省| 七台河市| 盐山县| 佳木斯市| 绵阳市| 鄢陵县|