Add PhoneStateListener
You have to create a receiver to catch phone calls.
To do this, add this in your in manifest.xml:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<receiver android:name=".ServiceReceiver">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
and create these classes:
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.webkit.WebView;
public class MyPhoneStateListener extends PhoneStateListener {
public static Boolean phoneRinging = false;
public void onCallStateChanged(int state, String incomingNumber) {
switch (state) {
case TelephonyManager.CALL_STATE_IDLE:
Log.d("DEBUG", "IDLE");
phoneRinging = false;
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
Log.d("DEBUG", "OFFHOOK");
phoneRinging = false;
break;
case TelephonyManager.CALL_STATE_RINGING:
Log.d("DEBUG", "RINGING");
phoneRinging = true;
break;
}
}
}
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
public class ServiceReceiver extends BroadcastReceiver {
TelephonyManager telephony;
public void onReceive(Context context, Intent intent) {
MyPhoneStateListener phoneListener = new MyPhoneStateListener();
telephony = (TelephonyManager) context
.getSystemService(Context.TELEPHONY_SERVICE);
telephony.listen(phoneListener, PhoneStateListener.LISTEN_CALL_STATE);
}
public void onDestroy() {
telephony.listen(null, PhoneStateListener.LISTEN_NONE);
}
}
Calling PhoneStateListener in a thread inside a service
This code works fine inside onCreate
Because it using Looper of Android Main Thread
, when you put your code into Thread
, Looper
not available there, you need make your own Looper
. Try this
final class phoneStateThread implements Runnable
{
@Override
public void run() {
Looper.prepare()
Log.v(TAG,"Starting telephony");
telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
Log.v(TAG,"Starting listener");
phoneStateListener = new PhoneStateListener(){
@Override
public void onCallStateChanged(int state, String incomingNumber) {
Log.v(TAG,"Starting CallStateChange");
switch (state){
//=====Phone ringing. Pause music=====
case TelephonyManager.CALL_STATE_OFFHOOK:
case TelephonyManager.CALL_STATE_RINGING:
if(mediaPlayer!=null) {
pauseMedia();
isPausedInCall=true;
}
break;
//=====Phone idle. start music=====
case TelephonyManager.CALL_STATE_IDLE:
if(mediaPlayer!=null){
if(isPausedInCall){
isPausedInCall=false;
playMedia();
}
}
break;
}
}
};
telephonyManager.listen(phoneStateListener,PhoneStateListener.LISTEN_CALL_STATE);
Looper.loop()
}
}
Does android PhoneStateListener run on background?
Ok, so I've solved the issue.
The short answer is no, the PhoneStateListener
doesn't run in background.
By default the listener runs only when the application is in foreground for what I've seen.
Maybe there's a way to run it in a service but I couldn't get it to work.
Instead I solved the problem with a BroadcastReceiver
.
So, for the solution
The CallStateMonitor
stayed the same as it was before, I just moved it from where it was.
For the service, as I said, I replaced it for a broadcast receiver:
class CallBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val telephonyManager = context?.getSystemService(TELEPHONY_SERVICE) as TelephonyManager
val monitor = StateMonitor()
telephonyManager.listen(monitor, LISTEN_CALL_STATE)
}
private val tag = "STATE_MONITOR"
private inner class StateMonitor : PhoneStateListener() {
override fun onCallStateChanged(state: Int, phoneNumber: String?) {
when (state) {
TelephonyManager.CALL_STATE_IDLE -> Log.d(tag, "IDLE")
TelephonyManager.CALL_STATE_OFFHOOK -> Log.d(tag, "OFF-HOOK")
TelephonyManager.CALL_STATE_RINGING -> Log.d(tag, "RINGING")
}
}
}
}
The rest is just starting the receiver from the main activity:
class CallMonitorActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
registerReceiver(CallBroadcastReceiver(), IntentFilter(ACTION_CONFIGURATION_CHANGED))
Log.d(ACTIVITY_TAG, "Registered call receiver.")
}
}
And that's it, hope it can help someone else ^-^
How to start PhoneStateListener programmatically?
you have to used this code and it is 100% work.
(1) you have to start services
startService(new Intent(this, CallServices.class));
(2) you have to make CallServices class and start your contentobser.
public class CallServices extends Service{
private static final String TAG = "CallService";
Context mContext;
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "onBind");
return null;
}
@Override
public void onCreate() {
Log.d(TAG, "onCreate");
mContext=getApplicationContext();
}
@Override
public void onStart(Intent intent, int startId) {
//super.onStart(intent, startId);
Log.d(TAG, "onStart services is started");
Uri mediaUri = Uri.parse("content://call_log/calls");
Handler handler = new Handler(){};
CustomContentObserver custObser = new CustomContentObserver(handler,mContext);
mContext.getContentResolver().registerContentObserver(mediaUri, true, custObser);
}
}
(3) make CustomContentObserver class to getting you to call log.
public class CustomContentObserver extends ContentObserver {
long lastTimeofCall = 0L;
long lastTimeofUpdate = 0L;
long threshold_time = 10000;
public CustomContentObserver(Handler handler,Context con) {
super(handler);
this.mContext=con;
System.out.println("Content obser");
callflag=true;
}
@Override
public boolean deliverSelfNotifications() {
return false;
}
public void onChange(boolean selfChange) {
super.onChange(selfChange);
lastTimeofCall = System.currentTimeMillis();
if(lastTimeofCall - lastTimeofUpdate > threshold_time){
if(callflag){
System.out.println("Content obser onChange()");
Log.d("PhoneService", "custom StringsContentObserver.onChange( " + selfChange + ")");
//if(!callFlag){
String[] projection = new String[]{CallLog.Calls.NUMBER,
CallLog.Calls.TYPE,
CallLog.Calls.DURATION,
CallLog.Calls.CACHED_NAME,
CallLog.Calls._ID};
Cursor c;
c=mContext.getContentResolver().query(CallLog.Calls.CONTENT_URI, projection, null, null, CallLog.Calls._ID + " DESC");
if(c.getCount()!=0){
c.moveToFirst();
lastCallnumber = c.getString(0);
lastCallnumber=FormatNumber(lastCallnumber);
String type=c.getString(1);
String duration=c.getString(2);
String name=c.getString(3);
String id=c.getString(4);
System.out.println("CALLLLing:"+lastCallnumber+"Type:"+type);
Database db=new Database(mContext);
Cursor cur =db.getFirstRecord(lastCallnumber);
System.out.println("CUSTOM GALLARY..."+cur.getCount());
final String endCall=lastCallnumber;
//checking incoming/outgoing call
if(type.equals("1")){
//incoming call code
}else if(type.equals("2")){
//outgoing call code
} else{
//missed call code
}
}
lastTimeofUpdate = System.currentTimeMillis();
}
}
}
}
in this way you have to read call log data.
i am using content Observer because of in htc device can not read phonestateListner that's way.
Related Topics
Google Glass Gdk: How to Communicate with Android Device
Add a Search Filter on Recyclerview with Cards
Using Listview:How to Add a Header View
Recyclerview Gridlayoutmanager: How to Auto-Detect Span Count
When to Use a Content Provider
Overlay Images Onto Camera Preview Surfaceview
How to Resize Image (Bitmap) to a Given Size
Programmatically Add Id to R.Id
How to Repeat a Method Every 10 Minutes After a Button Press and End It on Another Button Press
How to Add an Image in Email Body
How to Hide Underbar in Edittext
Fragments Destroyed/Recreated with Jetpack's Android Navigation Components
Any Way to Link to the Android Notification Settings for My App