最近在做的一個(gè)crm項(xiàng)目要求實(shí)現(xiàn)實(shí)時(shí)上傳通話記錄和自動(dòng)撥打電話功能,研究了一下電話相關(guān)的一系列功能,趁著今天不忙在此總結(jié)下,做個(gè)備忘。
一、讀取通話記錄:
? ? ? ? 1、首先android讀取通話記錄需要在清單文件添加相關(guān)權(quán)限<uses-permission android:name="android.permission.READ_CALL_LOG"/>
? ? ? ? 2、獲取通話記錄
Cursor:Cursor cursor= ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
getContentResolver().query(CallLog.Calls.CONTENT_URI,newString[{CallLog.Calls.DURATION,CallLog.Calls.TYPE,CallLog.
Calls.DATE,CallLog.Calls.NUMBER},null,null,CallLog.Calls.DEFAULT_SORT_ORDER);
? ? ? ? 3、從每個(gè)cursor讀取對(duì)應(yīng)每條通話記錄內(nèi)容:
while(cursor.moveToNext()) {
?type=cursor.getInt(cursor.getColumnIndex(CallLog.Calls.TYPE));//1來電;2去電
?duration=cursor.getLong(cursor.getColumnIndex(CallLog.Calls.DURATION));//時(shí)長(zhǎng)
?date=cursor.getString(cursor.getColumnIndex(CallLog.Calls.DATE));//時(shí)間
?telnum=cursor.getString(cursor.getColumnIndex(CallLog.Calls.NUMBER));//號(hào)碼
?}
? ? ? ? ? 4、拿到數(shù)據(jù)按需求做你想做的事,就這么簡(jiǎn)單
二、自動(dòng)撥號(hào):
? ? ? 1、添加權(quán)限 android.permission.CALL_PHONE
? ? ? 2、調(diào)用打電話代碼一個(gè)intent即可實(shí)現(xiàn)
Uri uri=Uri.parse("tel:"+ phoneNum.trim());
Intent intent=newIntent(Intent.ACTION_CALL,uri);
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
mActivity.startActivityForResult(intent,520);
? ? ? ? 3、正常情況當(dāng)你調(diào)用這幾行代碼的確可以播出電話,但是問題來啦,android手機(jī)對(duì)自動(dòng)撥號(hào)是有權(quán)限詢問的,更有甚者用戶在系統(tǒng)設(shè)置禁 止了該權(quán)限。這兩種情況最終造成我們的功能體驗(yàn)都不太好。所以解決思路就是引導(dǎo)用戶去系統(tǒng)設(shè)置給我們的應(yīng)用自動(dòng)撥號(hào)權(quán)限添加允 ? ? ? ? ? ? ? ? 許。這種情況就要求我們?cè)趽芴?hào)之前檢查是否有該權(quán)限,但是api23之前是沒有直接的方法可以調(diào)用查詢的至于23之后有沒有我沒有去確? ? ? ? ? ? ? ? 認(rèn),但是在我后來做手機(jī)通話狀態(tài)監(jiān)聽的時(shí)候我發(fā)現(xiàn),當(dāng)有允許權(quán)限的時(shí)候startActivityForResult(intent,520)之后系統(tǒng)會(huì)發(fā)一個(gè)去電的廣 ? ? ? ? ? ? ?播android.intent.action.NEW_OUTGOING_CALL,而后會(huì)再調(diào)用mActivity的onActivityResult方法,如果權(quán)限被禁止或者處于詢問(小 ? ? ? ? ? ? ? 米)就會(huì)直接(或先)調(diào)用onActivityResult方法。這樣我們就可以在onActivityResult判斷是否開啟了允許權(quán)限,若果沒有就可一彈框引導(dǎo)? ? ? ? ? ? ? 用戶去開起了。
三、自動(dòng)掛斷:android掛斷電話的調(diào)用方法在ITelephony.java里而ITelephony.java是隱藏的,我們不能直接調(diào)用endCall()方法所以我們要實(shí)現(xiàn)就緒做如下操作。
1、由于ITelephony.java的包名是com.android.internal.telephony在自己項(xiàng)目src/main下創(chuàng)建aidl文件夾在該文件下創(chuàng)建包c(diǎn)om.android.internal.telephony然后copy android源碼中的ITelephony.aidl文件到com.android.internal.telephony
2、由于ITelephony.aidl關(guān)聯(lián)了NeighboringCellInfo.aidl所以也一起copy過來包名android.telephony
3、兩個(gè)文件copy完之后clean一下,你就會(huì)在你的gen目錄下發(fā)現(xiàn)已經(jīng)生成了ITelephony.java這個(gè)接口文件,雖然生成了.java文件但是我們并不能直接調(diào)用,這是因?yàn)镮Telephony對(duì)象是以一個(gè)系統(tǒng)服務(wù)的形式存在系統(tǒng)中的,所一要通過ServiceManager來拿到ITelephony對(duì)象,but? ServiceManager也是隱藏的。我們可以通過反射先拿到ServiceManager在通過ServiceManager.getService(String name)方法來取得ITelephony對(duì)象,而這個(gè)name就是當(dāng)時(shí)addService()的時(shí)候使用的name(也就是phone)
Method method=null;
try{
method=Class.forName("android.os.ServiceManager").getMethod("getService",String.class);
IBinder binder= (IBinder)method.invoke(null,newObject[]{"phone"});
ITelephony telephony=ITelephony.Stub.asInterface(binder);
telephony.endCall();
}catch(NoSuchMethodExceptione) {
e.printStackTrace();
}catch(ClassNotFoundExceptione) {
e.printStackTrace();
}catch(InvocationTargetExceptione) {
e.printStackTrace();
}catch(IllegalAccessExceptione) {
e.printStackTrace();
}catch(RemoteExceptione) {
e.printStackTrace();
}
四、自動(dòng)接聽
? ? ? ?1、由于自動(dòng)接聽也是用到ITelephony所以基本準(zhǔn)備工作與三相同
? ? ? 2、添加權(quán)限android.permission.CALL_PHONE和android.permission.MODIFY_PHONE_STATE
? ? ? 3、廢話不再多說直接上代碼
Method method=null;
try{
method=Class.forName("android.os.ServiceManager").getMethod("getService",String.class);
IBinder binder= (IBinder)method.invoke(null,newObject[]{"phone"});
ITelephony telephony=ITelephony.Stub.asInterface(binder);
telephony.answerRingingCall();
}catch(NoSuchMethodExceptione) {
e.printStackTrace();
}catch(ClassNotFoundExceptione) {
e.printStackTrace();
}catch(InvocationTargetExceptione) {
e.printStackTrace();
}catch(IllegalAccessExceptione) {
e.printStackTrace();
}catch(RemoteExceptione) {
e.printStackTrace();
}
4、但是answerRingingCall()在4.1之后增加了權(quán)限檢查(自動(dòng)掛斷電話沒有),這個(gè)時(shí)候再調(diào)用上面的方法會(huì)catch到一個(gè)Exception,我們可以在catch里走另外一套自動(dòng)接聽的方法,可以看一下packages/apps/Phone/src/com/android/phone/PhoneGlobals.java的源碼,你會(huì)發(fā)現(xiàn)里面注冊(cè)一個(gè)廣播接收器MediaButtonBroadcastReceiver,action就是“android.intent.action.MEDIA_BUTTON”并且在receiver方法里做了answerCall(phone.getRingingCall());接聽電話的操作,所以我們?cè)赾atch里只需發(fā)一個(gè)相應(yīng)的廣播就可以啦,是的你沒看錯(cuò)就是發(fā)一個(gè)廣播就可以啦就是這么逗。