天天看點

安卓 來電狀态監聽、去電監聽

 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();
		}
	}
	
}