Android開(kāi)發(fā)四大組件之實(shí)現(xiàn)電話(huà)攔截和電話(huà)錄音
一、問(wèn)題描述
使用BordercastReceiver和Service組件實(shí)現(xiàn)下述功能:
1.當(dāng)手機(jī)處于來(lái)電狀態(tài),啟動(dòng)監(jiān)聽(tīng)服務(wù),對(duì)來(lái)電進(jìn)行監(jiān)聽(tīng)錄音。
2.設(shè)置電話(huà)黑名單,當(dāng)來(lái)電是黑名單電話(huà),則直接掛斷。
當(dāng)撥打電話(huà)或電話(huà)狀態(tài)發(fā)生改變時(shí),系統(tǒng)就會(huì)發(fā)出有序廣播,因此我們可以使用BordercastReceiver接受廣播,因BordercastReceiver執(zhí)行時(shí)間短不能執(zhí)行耗時(shí)任務(wù)也不能使用子線(xiàn)程,因此我們應(yīng)啟動(dòng)一個(gè)Service來(lái)監(jiān)聽(tīng)電話(huà)并進(jìn)行處理
二、加入AIDL文件
Android沒(méi)有對(duì)外公開(kāi)結(jié)束通話(huà)的API,要結(jié)束通話(huà)就必須使用AIDL與電話(huà)管理服務(wù)進(jìn)行通信,并調(diào)用服務(wù)中的API實(shí)現(xiàn)結(jié)束通話(huà),這樣需要android 源碼文件NeighboringCellInfo.aidl和ITelephony.aidl添加到項(xiàng)目中,如圖所示:

Android Studio 會(huì)自動(dòng)編譯產(chǎn)生對(duì)應(yīng)的類(lèi)文件
三、編寫(xiě)TelReceiver組件
public class TelReceiver extends BroadcastReceiver {
public TelReceiver() {
}
@Override
public void onReceive(Context context, Intent intent) {
Intent i=new Intent(context,ListenPhoneService.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
i.setAction(intent.getAction());
i.putExtra(TelephonyManager.EXTRA_INCOMING_NUMBER,
intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER));//電話(huà)號(hào)碼
i.putExtra(TelephonyManager.EXTRA_STATE,
intent.getStringExtra(TelephonyManager.EXTRA_STATE));//電話(huà)狀態(tài)
context.startService(i);//啟動(dòng)服務(wù)
}
}
注冊(cè)廣播:
<receiver android:name=".TelReceiver" > <intent-filter android:priority="1000" > <action android:name="android.intent.action.PHONE_STATE" /> <action android:name="android.intent.action.NEW_OUTGOING_CALL" /> </intent-filter> </receiver>
四、編寫(xiě)ListenPhoneService組件
public class ListenPhoneService extends Service {
private AudioManager mAudioManager;
private TelephonyManager tm;
public ListenPhoneService() {
}
@Override
public void onCreate() {
super.onCreate();
mAudioManager=(AudioManager)getSystemService(Context.AUDIO_SERVICE);
tm=(TelephonyManager)getSystemService(Service.TELEPHONY_SERVICE);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(intent.getAction().equals(Intent.ACTION_NEW_OUTGOING_CALL)){//去電廣播,android沒(méi)有來(lái)電話(huà)廣播
}else{//去掉撥打電話(huà)就是來(lái)電狀態(tài)了
//方法1
//獲得來(lái)電電話(huà)
// String number=intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
//獲得電話(huà)狀態(tài)
// String state=intent.getStringExtra(TelephonyManager.EXTRA_STATE);
// Log.d("jereh", "incoming phone:" + number);
// Log.d("jereh","call state:"+state);
// TelephonyManager.EXTRA_STATE_IDLE: 沒(méi)有來(lái)電 或者 掛斷
// TelephonyManagerEXTRA_STATE_OFFHOOK: 接起電話(huà)
// TelephonyManager.EXTRA_STATE_RINGING:當(dāng)電話(huà)呼入時(shí),響鈴時(shí)
// if(state.equals(TelephonyManager.EXTRA_STATE_RINGING)){
// if(number.equals("13280998858")){//攔截指定的電話(huà)號(hào)碼
// mAudioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
// Log.d("jereh","電話(huà)被攔截");
// stopCall();
// mAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);//恢復(fù)鈴聲
// }
// }else if(state.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)){
//接起電話(huà)
// recordCall();//開(kāi)始錄音
// }else if(state.equals(TelephonyManager.EXTRA_STATE_IDLE)){
// stopCall();//停止錄音
// }
//方法2
// 設(shè)置一個(gè)監(jiān)聽(tīng)器,監(jiān)聽(tīng)電話(huà)狀態(tài)
tm.listen(listener,PhoneStateListener.LISTEN_CALL_STATE);
}
return super.onStartCommand(intent, flags, startId);
}
/**
* 掛斷電話(huà)
*/
private void stopCall(){
try {
//Android的設(shè)計(jì)將ServiceManager隱藏了,所以只能使用反射機(jī)制獲得。
Method method=Class.forName("android.os.ServiceManager").getMethod("getService", String.class);
IBinder binder=(IBinder)method.invoke(null, new Object[]{"phone"});//獲得系統(tǒng)電話(huà)服務(wù)
ITelephony telephoney=ITelephony.Stub.asInterface(binder);
telephoney.endCall();//掛斷電話(huà)
stopSelf();//停止服務(wù)
} catch (Exception e) {
e.printStackTrace();
}
}
PhoneStateListener listener=new PhoneStateListener(){
@Override
public void onCallStateChanged(int state,String incomingNumber){
switch (state){
//手機(jī)空閑了
case TelephonyManager.CALL_STATE_IDLE:
stopCall();//停止錄音
break;
//接起電話(huà)
case TelephonyManager.CALL_STATE_OFFHOOK:
recordCall();//開(kāi)始錄音
break;
// 響鈴時(shí)
case TelephonyManager.CALL_STATE_RINGING:
Log.e("jereh", "來(lái)電號(hào)碼是:"+ incomingNumber);
// 如果該號(hào)碼屬于黑名單
if (incomingNumber.equals("123456")) {
// 如果是黑名單,就進(jìn)行屏蔽
stopCall();
}
break;
}
}
};
/**
* 停止錄音
*/
private void stopRecord(){
if(recording){
recorder.stop();
recorder.release();
recording=false;
stopSelf();//停止服務(wù)
}
}
/**
* 電話(huà)錄音
*/
private MediaRecorder recorder;
private boolean recording ;
private void recordCall(){
Log.d("jereh", "record calling")
if( Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
recorder=new MediaRecorder();
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);//讀麥克風(fēng)的聲音
recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);//設(shè)置輸出格式
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);// 編碼方式
File file=new File(Environment.getDownloadCacheDirectory().getAbsolutePath(),"recorder");
if(!file.exists()){
file.mkdir();
}
recorder.setOutputFile(file.getAbsolutePath() + "/"
+ System.currentTimeMillis() + "3gp");// 存放的位置是放在sd卡recorder目錄下
try {
recorder.prepare();
recorder.start();
recording=true;
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
}
Service XML配置
<service android:name=".ListenPhoneService" android:enabled="true" android:exported="true" > </service>
五、最后別忘了一些權(quán)限的設(shè)置
<!-- 添加訪(fǎng)問(wèn)手機(jī)電話(huà)狀態(tài)的權(quán)限 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!-- 撥打電話(huà)權(quán)限 -->
<uses-permission android:name="android.permission.CALL_PHONE" />
<!-- 監(jiān)聽(tīng)手機(jī)去電的權(quán)限 -->
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<!-- 在SDCard中創(chuàng)建與刪除文件權(quán)限 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<!-- 往SDCard寫(xiě)入數(shù)據(jù)權(quán)限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
好了,以上就是本文的全部所述,希望對(duì)大家學(xué)習(xí)android四大基本組件有所幫助,謝謝。
相關(guān)文章
Android應(yīng)用啟動(dòng)流程之從啟動(dòng)到可交互的過(guò)程解析
這篇文章將給大家總結(jié)學(xué)習(xí)Android 基礎(chǔ)知識(shí),Android應(yīng)用啟動(dòng)流程,從啟動(dòng)到可交互的過(guò)程解析,在學(xué)習(xí)過(guò)程中,大家最好是把源碼下載下來(lái),感興趣的小伙伴跟著小編一起來(lái)看看吧2023-08-08
Android StickListView實(shí)現(xiàn)懸停效果
這篇文章主要介紹了Android StickListView實(shí)現(xiàn)懸停效果的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-06-06
Android 實(shí)現(xiàn)不同字體顏色的TextView實(shí)現(xiàn)代碼
這篇文章主要介紹了Android 實(shí)現(xiàn)不同字體顏色的TextView實(shí)現(xiàn)代碼的相關(guān)資料,需要的朋友可以參考下2017-05-05
Flutter使用AnimatedOpacity實(shí)現(xiàn)圖片漸現(xiàn)動(dòng)畫(huà)
其實(shí)在Flutter中提供了一些封裝好的動(dòng)畫(huà)組件,以便我們快速應(yīng)用。本文將利用其中的AnimatedOpacity組件實(shí)現(xiàn)圖片漸現(xiàn)動(dòng)畫(huà)效果,需要的可以參考一下2022-03-03
Android中的ViewPager視圖滑動(dòng)切換類(lèi)的入門(mén)實(shí)例教程
Android中ViewPager通常與Fragments組件共同使用來(lái)實(shí)現(xiàn)視圖切換功能,本文就帶大家一起來(lái)學(xué)習(xí)Android中的ViewPager視圖滑動(dòng)切換類(lèi)的入門(mén)實(shí)例教程:2016-06-06
Android中獲得正在運(yùn)行的程序和系統(tǒng)服務(wù)的方法
這篇文章主要介紹了Android中獲得正在運(yùn)行的程序和系統(tǒng)服務(wù)的方法,分別是對(duì)ActivityManager.RunningAppProcessInfo類(lèi)和ActivityManager.RunningServiceInfo類(lèi)的使用,需要的朋友可以參考下2016-02-02
Android RecyclerView自定義上拉和下拉刷新效果
這篇文章主要為大家詳細(xì)介紹了Android RecyclerView自定義上拉和下拉刷新效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-02-02

