20190401_16.04
來電監聽:補充完成 2、3、4處的邏輯即可
package com.sc.broad;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import com.sc.call.CallProcess;
/* AndroidManifest.xml添加配置
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<!-- 靜态廣播注冊,接收來電、去電廣播 -->
<receiver android:name="com.sc.broad.CallReceiver" >
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
</intent-filter>
</receiver>
*/
/** 來電、去電廣播監聽 */
public class CallReceiver extends BroadcastReceiver
{
private Context context;
@Override
public void onReceive(Context context, Intent intent)
{
this.context = context;
String action = intent.getAction();
// Toast.makeText(context, "action" + action, Toast.LENGTH_SHORT).show();
if (action.equals("android.intent.action.NEW_OUTGOING_CALL"))
{ // 接收到去電廣播,執行去電處理邏輯
// IntentFilter intentFilter = new IntentFilter(Intent.ACTION_NEW_OUTGOING_CALL);
// context.registerReceiver(this, intentFilter);
// String phoneNumber = getResultData();
String phoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
phoneNumber = phoneNumber.replace("-", "").replace(" ", ""); // 剔除号碼中的分隔符
//1、// CallProcess.OutCall(context, phoneNumber); // 去電處理邏輯
}
else if (action.equals("android.intent.action.PHONE_STATE"))
{ // 接收到來電廣播,執行來電監聽處理邏輯
TelephonyManager tm = (TelephonyManager) context.getSystemService(Service.TELEPHONY_SERVICE);
tm.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);
}
}
private PhoneStateListener listener = new PhoneStateListener()
{
@Override
public void onCallStateChanged(int state, String phoneNumber)
{
super.onCallStateChanged(state, phoneNumber);
phoneNumber = phoneNumber.replace("-", "").replace(" ", ""); // 剔除号碼中的分隔符
switch (state)
{
case TelephonyManager.CALL_STATE_IDLE:
//2、// CallProcess.HungUp(context, phoneNumber); // 空閑/挂斷處理邏輯
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
//3、// CallProcess.OffHook(context, phoneNumber); // 接聽處理邏輯
break;
case TelephonyManager.CALL_STATE_RINGING: // 來電處理邏輯
//4、// CallProcess.Ringing(context, phoneNumber);
break;
}
}
};
}
來電 接聽、挂斷
示例應用: https://blog.csdn.net/scimence/article/details/88894411
以下内容(可忽略)為:
從廣播啟動服務、在services服務中進行來電監聽:
電話狀态(來電、接聽、挂斷、撥打電話)監聽邏輯:
package com.sc.call;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
/**
* CallListener.java: 來電狀态監聽、去電監聽。
* 用法:建立CallListener執行個體,并重寫電話相關的四個abstract抽象函數即可。
* new CallListener(context){...};
*
* 需要添權重限:
* uses-permission android:name="android.permission.READ_PHONE_STATE"
* uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"
* -----
* 2019-1-9 上午10:16:06
* scimence
*/
public abstract class CallListener
{
CallListener Instance;
CallInListener callin; // 來電監聽
OutCallListener callout; // 撥出監聽
public CallListener(Context context)
{
Instance = this;
callin = new CallInListener(context)
{
@Override
public void Ringing(String phoneNumber)
{
Instance.Ringing(phoneNumber);
}
@Override
public void OffHook(String phoneNumber)
{
Instance.OffHook(phoneNumber);
}
@Override
public void HungUp(String phoneNumber)
{
Instance.HungUp(phoneNumber);
}
};
callout = new OutCallListener(context)
{
@Override
public void OutCall(String phoneNumber)
{
Instance.OutCall(phoneNumber);
}
};
}
/** 響鈴時執行邏輯 */
public abstract void Ringing(String phoneNumber);
/** 接聽時執行邏輯 */
public abstract void OffHook(String phoneNumber);
/** 挂斷時執行邏輯 */
public abstract void HungUp(String phoneNumber);
/** 去電時執行邏輯 */
public abstract void OutCall(String phoneNumber);
}
/**
* 來電狀态監聽。
*
* <uses-permission android:name="android.permission.READ_PHONE_STATE" />
* */
abstract class CallInListener extends PhoneStateListener
{
TelephonyManager phoneManager;
public CallInListener(Context context)
{
phoneManager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
Listen();
}
/** 監聽來電狀态 */
public void Listen()
{
phoneManager.listen(this, PhoneStateListener.LISTEN_CALL_STATE); // 在系統服務上,為目前Listener注冊CALL_STATE狀态監聽
}
/** 不再監聽 */
public void ClearListen()
{
phoneManager.listen(this, PhoneStateListener.LISTEN_NONE);
}
/** 重寫監聽來電狀态 */
public void onCallStateChanged(int state, String phoneNumber)
{
if(state == TelephonyManager.CALL_STATE_IDLE) // 空閑/挂斷
{
HungUp(phoneNumber);
}
else if(state == TelephonyManager.CALL_STATE_RINGING) // 響鈴
{
Ringing(phoneNumber);
}
else if(state == TelephonyManager.CALL_STATE_OFFHOOK) // 接聽
{
OffHook(phoneNumber);
}
}
/** 響鈴時執行邏輯 */
public abstract void Ringing(String phoneNumber);
/** 接聽時執行邏輯 */
public abstract void OffHook(String phoneNumber);
/** 挂斷時執行邏輯 */
public abstract void HungUp(String phoneNumber);
}
/**
* 去電監聽。
*
* <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
* */
abstract class OutCallListener extends BroadcastReceiver
{
Context context;
public OutCallListener(Context context)
{
this.context = context;
Listen();
}
/** 監聽來電狀态 */
public void Listen()
{
IntentFilter intentFilter = new IntentFilter(Intent.ACTION_NEW_OUTGOING_CALL);
context.registerReceiver(this, intentFilter);
}
/** 不再監聽 */
public void ClearListen()
{
context.unregisterReceiver(this);
}
/** 重寫監聽去電事件 */
public void onReceive(Context context, Intent intent)
{
String phoneNumber = getResultData();
OutCall(phoneNumber);
}
/** 去電時執行邏輯 */
public abstract void OutCall(String phoneNumber);
}
簡易調用:(引入CallProcess.jar,改寫CallProcess.java)
{
CallProcess.jar下載下傳
package com.sc.call;
//import java.util.ArrayList;
import android.content.Context;
import android.widget.Toast;
//
// 整體調用邏輯:
// (1)從BroadCast_Start廣播接收到的系統事件(開機、鎖屏等)啟動服務CallService;
// (2)在CallService中添加來電、撥出事件監聽,在監聽到電話事件(來電、接聽、挂斷、撥打電話)後進行事件處理
// (3)在CallService中調用CallProcess中編寫好的邏輯
//-----
// 2019-1-9 上午10:16:06
// scimence
/** 接入邏輯(在AndroidManifest.xml中)
*
* 1、添權重限:
* uses-permission android:name="android.permission.READ_PHONE_STATE"
* uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"
* uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"
*
* 2、添加receiver和service
<application ...>
....
<!-- 添加靜态廣播接收,監聽開啟、鎖屏、解屏 事件(以啟動電話監聽CallService) -->
<receiver
android:name="com.sc.broad.BroadCast_Start"
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.SCREEN_OFF" />
<action android:name="android.intent.action.SCREEN_ON" />
</intent-filter>
</receiver>
<!-- 定義CallService,用于執行電話事件處理邏輯 -->
<service
android:name="com.sc.service.CallService"
android:enabled="true"
android:exported="true" >
</service>
</application>
*
*
* 3、電話事件處理邏輯:改寫該類中的處理邏輯(實作來電、接聽、挂斷、撥出 事件邏輯)
*
* 備注:若改變目前類名、路徑,請在CallService.CallLogic()中修改調用
* */
public class CallProcess
{
/** 添加來電處理邏輯 */
public static void Ringing(Context context, String phoneNumber)
{
// TODO 添加來電相關處理邏輯
Toast.makeText(context, "來電相關處理邏輯!", Toast.LENGTH_SHORT).show();
}
/** 添加接聽處理邏輯 */
public static void OffHook(Context context, String phoneNumber)
{
// TODO 添加接聽相關處理邏輯
Toast.makeText(context, "接聽相關處理邏輯!", Toast.LENGTH_SHORT).show();
}
/** 添加挂斷處理邏輯 */
public static void HungUp(Context context, String phoneNumber)
{
// TODO 添加挂斷相關處理邏輯
Toast.makeText(context, "挂斷相關處理邏輯!", Toast.LENGTH_SHORT).show();
}
/** 添加撥出處理邏輯 */
public static void OutCall(Context context, String phoneNumber)
{
// TODO 添加撥出相關處理邏輯
Toast.makeText(context, "撥出相關處理邏輯!", Toast.LENGTH_SHORT).show();
}
}
}簡易調用結束
相關源碼附錄:
package com.sc.broad;
//import java.util.HashMap;
import com.sc.service.CallService;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
/* 需在AndroidManifest.xml添加廣播靜态配置,<intent-filter/>中添加需要監聽的廣播類型
<application ...>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
...
<receiver
android:name="com.sc.broad.BroadCast_Start"
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.SCREEN_OFF" />
<action android:name="android.intent.action.SCREEN_ON" />
<!-- 自定義廣播類型 -->
<action android:name="com.sc.broad.actionDemo" />
</intent-filter>
</receiver>
</application>
*/
/** AndroidManifest.xml的靜态注冊廣播(安裝app時會自動注冊,app未運作時也可正常接收廣播 )
*
* 用法:無需調用,通過開啟、鎖屏 廣播啟動電話監聽Service */
public class BroadCast_Start extends BroadcastReceiver
{
@Override
public void onReceive(Context context, Intent intent)
{
String action = intent.getAction();
Broad(action, context, intent);
}
/** 廣播回調,action為廣播類型 */
public void Broad(String action, Context context, Intent intent)
{
// if(action.equals("android.intent.action.BOOT_COMPLETED"))
// {
// CallService.GetInstance().start(context, CallService.class);
CallService.GetInstance().start(context, CallService.class, 500);
// }
}
// ------------
// /** 發送自定義廣播,action廣播名稱 如:"com.sc.broad.actionDemo"; extData廣播附帶的資料; extName廣播資料對應的名稱 */
// public void SendBroadCast(Context context, String action, String extName, String extData)
// {
// BroadCastTool.SendBroadCast(context, action, extName, extData);
// }
//
// /** 發送自定義廣播,action廣播名稱 如:"com.sc.broad.actionDemo"; ext為廣播附帶的資料 */
// public void SendBroadCast(Context context, String action, HashMap<String, String> ext)
// {
// BroadCastTool.SendBroadCast(context, action, ext);
// }
}
package com.sc.service;
import com.sc.call.CallListener;
import com.sc.call.CallProcess;
import android.widget.Toast;
/* 在AndroidManifest.xml
*
* 添權重限:
* uses-permission android:name="android.permission.READ_PHONE_STATE"
* uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"
*
* 添加 <service/>
<application ...>
....
<service
android:name="com.sc.service.CallService"
android:enabled="true"
android:exported="true" >
</service>
</application>
*/
/**
* 定義:繼承BaseService,重寫自定義服務邏輯serviceLogic()
*
* 1、擷取服務:CallService.GetInstance()
*
* 2、啟動服務:CallService.GetInstance().start(context, CallService.class);
* 3、停止服務:CallService.GetInstance().stop();
* */
public class CallService extends BaseService
{
/** 在service中待執行的邏輯(在service未停止時,會一直執行)*/
public void serviceLogic()
{
CheckListener(); // 檢測電話監聽狀态
CallLogic(); // 執行對應電話狀态邏輯
}
public static boolean isRinging = false;
public static boolean isOutCall = false;
public static boolean isOffHook = false;
public static boolean isHungUp = false;
public static String Number = "";
CallListener callListen;
// 檢測并自動建立來電、去電監聽
private void CheckListener()
{
if(callListen == null)
{
callListen = new CallListener(this)
{
@Override
public void Ringing(String phoneNumber)
{
isRinging = true;
Number = phoneNumber;
}
@Override
public void OutCall(String phoneNumber)
{
isOutCall = true;
Number = phoneNumber;
}
@Override
public void OffHook(String phoneNumber)
{
isOffHook = true;
Number = phoneNumber;
}
@Override
public void HungUp(String phoneNumber)
{
isHungUp = true;
Number = phoneNumber;
}
};
}
}
/** 電話狀态處理邏輯 */
private void CallLogic()
{
if(isRinging)
{
isRinging = false;
CallProcess.Ringing(this, Number);
}
else if(isOffHook)
{
isOffHook = false;
CallProcess.OffHook(this, Number);
}
else if(isHungUp)
{
isHungUp = false;
CallProcess.HungUp(this, Number);
}
else if(isOutCall)
{
isOutCall = false;
CallProcess.OutCall(this, Number);
}
}
// /** 電話狀态處理邏輯 */
// private void CallLogic()
// {
//
// // 執行定義在CallProcess中的邏輯
// for(CallProcess proccesser : CallProcess.ProcessList())
// {
// if(isRinging)
// {
// isRinging = false;
// proccesser.Ringing(this, Number);
// }
// else if(isOffHook)
// {
// isOffHook = false;
// proccesser.OffHook(this, Number);
// }
// else if(isHungUp)
// {
// isHungUp = false;
// proccesser.HungUp(this, Number);
// }
// else if(isOutCall)
// {
// isOutCall = false;
// proccesser.OutCall(this, Number);
// }
// }
//
// }
// public void Ringing(String phoneNumber)
// {
// // TODO 添加來電處理邏輯
// }
//
// public void OffHook(String phoneNumber)
// {
// // TODO 添加接聽處理邏輯
// }
//
// public void HungUp(String phoneNumber)
// {
// // TODO 添加挂斷處理邏輯
// }
//
// public void OutCall(String phoneNumber)
// {
// // TODO 添加撥出處理邏輯
// }
}
package com.sc.service;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.widget.Toast;
/* 在AndroidManifest.xml添加 <service/>
<application ...>
....
<service
android:name="com.sc.service.MsgService"
android:enabled="true"
android:exported="true" >
</service>
</application>
*/
/** Service類,簡化Service調用:
* 子類可繼承BaseService,重寫函數serviceLogic()實作自定義服務邏輯
*
* 1、擷取服務單例對象 BaseService.GetInstance()
* 2、啟動服務 .start(Context context, Class<?> service_cls)(一次啟動,持續運作)
* 3、停止服務 .stop() */
public class BaseService extends Service
{
protected BaseService()
{}
@Override
public IBinder onBind(Intent intent)
{
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId)
{
if (!isrunning)
{
// if (BaseService.intent == null) BaseService.intent = intent;
// if (context == null) context = this.getBaseContext();
isrunning = true;
// Log.i(this.getClass().getSimpleName(), "onStartCommand");
// 執行服務處理邏輯
doServicesLogic(IntervalMillis);
}
return super.onStartCommand(intent, flags, startId);
}
/** service執行間隔時間(毫秒) */
public static long IntervalMillis = 2000;
Runnable runable;
/** 循環執行服務處理邏輯 */
private void doServicesLogic(final long delayMillis)
{
if(runable == null)
{
runable = new Runnable()
{
@Override
public void run()
{
if (isrunning)
{
// Toast.makeText(context, "doServicesLogic is running !", Toast.LENGTH_SHORT).show();
serviceLogic(); // 執行服務處理邏輯
doServicesLogic(delayMillis); // 處理邏輯執行完成1秒後再次執行
}
}
};
}
new Handler().postDelayed(runable, delayMillis);
}
/** 在service中待執行的邏輯(在service未停止時,會一直執行,每輪邏輯執行間隔IntervalMillis毫秒) */
public void serviceLogic()
{};
static BaseService Instance;
/** 擷取目前服務的單例對象 */
public static BaseService GetInstance()
{
if (Instance == null) Instance = new BaseService();
return Instance;
}
// ------------
private static boolean isrunning = false;
// private static Intent intent;
// private static Context context;
/** 啟動服務, service_cls目前服務對應的類, Millis指定服務邏輯serviceLogic()執行間隔毫秒數 */
public void start(Context context, Class<?> service_cls, long Millis)
{
IntervalMillis = Millis;
if (!isrunning)
{
// BaseService.context = context;
Intent intent = new Intent(context, service_cls);
context.startService(intent);
Toast.makeText(context, this.getClass().getSimpleName() + " 服務已啟動 !", Toast.LENGTH_SHORT).show();
}
}
/** 啟動服務, service_cls目前服務對應的類 */
public void start(Context context, Class<?> service_cls)
{
start(context, service_cls, 2000);
}
/** 停止服務(暫時停止服務,服務邏輯會在應用退出後自行重新開機,并一直運作) */
public void stop()
{
if (isrunning)
{
stopSelf();
// context.stopService(intent);
isrunning = false;
// Toast.makeText(context, this.getClass().getSimpleName() + " 服務已停止 !", Toast.LENGTH_SHORT).show();
}
}
}