In my app i want to identify whether the outgoing call state like waiting,received or rejected by other side.
I searched a lot in these below links
Outgoing call status How to detect answered or rejected state in outgoing call,outgoing call information through android BroadcastReceiver,identify outgoing call connect event
But couldn'd find a proper answer.Plz help me.Thanx.
I know its been a while but i hope to be helpful for someone still looking for a solution!
I recently had to work on a similar project where i needed to capture the ringing state of an outgoing call and the only way i could find was using the hidden Api of native dial-up App. This would only be possible for android > 5.0 because of the api changes. This was tested on Android 5.0.1, and worked like a charm. (p.s. you would need a rooted device for it to work, because you need to install your app as a System application (google how!) which will then be able to detect the outgoing call states).
For the record, PhoneStateListener doesn't work for detecting the outgoing call states as mentioned in many posts.
First, add this permission in the manifest file,
<uses-permission android:name="android.permission.READ_PRECISE_PHONE_STATE" />
Then define you broadcastreceiver, (here is a sample code!)
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.TelephonyManager;
public class MyBroadcastReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, final Intent intent)
{
switch (intent.getIntExtra("foreground_state", -2)) {
case 0: // PreciseCallState.PRECISE_CALL_STATE_IDLE:
System.out.println("IDLE");
break;
case 3: // PreciseCallState.PRECISE_CALL_STATE_DIALING:
System.out.println("DIALING");
break;
case 4: // PreciseCallState.PRECISE_CALL_STATE_ALERTING:
System.out.println("ALERTING");
break;
case 1: // PreciseCallState.PRECISE_CALL_STATE_ACTIVE:
System.out.println("ACTIVE");
break;
}
}
}
I replace some of the constants with their values because i saw alot of confusion among the folks unfamiliar with the concept of reflection (for ease).
Alerting is basically the state when receiver is actually ringing! and that does not include the call setup time!.
I had a similar issue. I wanted to detect some states of outgoing calls. I solved the issue by using visualizer class in android. It can return you with a Fourier transform of the current audio playing on the speaker. Using the type of audio being played(small beeping on the front speaker) you can determine the state of out-going call. For example you can know whether the phone has started ringing on the receiver or not. When ever visualizer return non-zero samples it is a yes.
Background audio wont disturb you because during a phone call the caller app shuts down all other audio.
Wait for status off_hook and then start your visualizer class
Try this, Look in else part and do changes there, it will work.
public class CallBr extends BroadcastReceiver {
Bundle bundle;
String state;
String inCall, outCall;
public boolean wasRinging = false;
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ACTION_IN)) {
if ((bundle = intent.getExtras()) != null) {
state = bundle.getString(TelephonyManager.EXTRA_STATE);
if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
inCall = bundle.getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
wasRinging = true;
Toast.makeText(context, "IN : " + inCall, Toast.LENGTH_LONG).show();
} else if (state.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)) {
if (wasRinging == true) {
Toast.makeText(context, "ANSWERED", Toast.LENGTH_LONG).show();
String out = new SimpleDateFormat("dd-MM-yyyy hh-mm-ss").format(new Date());
File sampleDir = new File(Environment.getExternalStorageDirectory(), "/TestRecordingDasa1");
if (!sampleDir.exists()) {
sampleDir.mkdirs();
}
String file_name = "Record";
try {
audiofile = File.createTempFile(file_name, ".amr", sampleDir);
} catch (IOException e) {
e.printStackTrace();
}
String path = Environment.getExternalStorageDirectory().getAbsolutePath();
recorder = new MediaRecorder();
// recorder.setAudioSource(MediaRecorder.AudioSource.VOICE_CALL);
recorder.setAudioSource(MediaRecorder.AudioSource.VOICE_COMMUNICATION);
recorder.setOutputFormat(MediaRecorder.OutputFormat.AMR_NB);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
recorder.setOutputFile(audiofile.getAbsolutePath());
try {
recorder.prepare();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
recorder.start();
recordstarted = true;
}
} else if (state.equals(TelephonyManager.EXTRA_STATE_IDLE)) {
wasRinging = false;
Toast.makeText(context, "REJECT || DISCO", Toast.LENGTH_LONG).show();
if (recordstarted) {
recorder.stop();
recordstarted = false;
}
}
}
} else if (intent.getAction().equals(ACTION_OUT)) {
if ((bundle = intent.getExtras()) != null) {
outCall = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
Toast.makeText(context, "OUT : " + outCall, Toast.LENGTH_LONG).show();
}
}
}
}
Try this, You can use PhoneListener extends to PhoneStateListener.
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
public class ListenToCallState extends BroadcastReceiver {
// private LoadProfImage mProfile;
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
// mProfile = new LoadProfImage(context);
PhoneListener phoneListener = new PhoneListener(context);
TelephonyManager telephony = (TelephonyManager) context
.getSystemService(Context.TELEPHONY_SERVICE);
telephony.listen(phoneListener, PhoneStateListener.LISTEN_CALL_STATE);
}
class PhoneListener extends PhoneStateListener {
private Context context;
public PhoneListener(Context context) {
// TODO Auto-generated constructor stub
this.context = context;
}
public void onCallStateChanged(int state, String incomingNumber) {
switch (state) {
case TelephonyManager.CALL_STATE_IDLE:
//Do your stuff
break;
case TelephonyManager.CALL_STATE_RINGING:
//Do your stuff
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
//Do your stuff
break;
}
}
}
}
Related
I'm developing an app that will only be used in house for testing purpose. I have searched a lot and tried different suggestions as suggested in different post but none seems to be working for me.
I'm open to any suggestions like Reflections, Accessibility Service, root or any other hack. Please help.
Regards
TRY THIS
Set all required permission in manifest.xml file.
Call this class in Service
public class PhoneListener extends PhoneStateListener {
private static PhoneListener instance = null;
/**
* Must be called once on app startup
*
* #param context - application context
* #return
*/
public static PhoneListener getInstance(Context context) {
if (instance == null) {
instance = new PhoneListener(context);
}
return instance;
}
public static boolean hasInstance() {
return null != instance;
}
private final Context context;
private CallLog phoneCall;
private PhoneListener(Context context) {
this.context = context;
}
AtomicBoolean isRecording = new AtomicBoolean();
AtomicBoolean isWhitelisted = new AtomicBoolean();
/**
* Set the outgoing phone number
* <p/>
* Called by {#link MyCallReceiver} since that is where the phone number is available in a outgoing call
*
* #param phoneNumber
*/
public void setOutgoing(String phoneNumber) {
if (null == phoneCall)
phoneCall = new CallLog();
phoneCall.setPhoneNumber(phoneNumber);
phoneCall.setOutgoing();
// called here so as not to miss recording part of the conversation in TelephonyManager.CALL_STATE_OFFHOOK
isWhitelisted.set(Database.isWhitelisted(context, phoneCall.getPhoneNumber()));
}
#Override
public void onCallStateChanged(int state, String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);
switch (state) {
case TelephonyManager.CALL_STATE_IDLE: // Idle... no call
if (isRecording.get()) {
RecordCallService.stopRecording(context);
phoneCall = null;
isRecording.set(false);
}
break;
case TelephonyManager.CALL_STATE_OFFHOOK: // Call answered
if (isWhitelisted.get()) {
isWhitelisted.set(false);
return;
}
if (!isRecording.get()) {
isRecording.set(true);
// start: Probably not ever usefull
if (null == phoneCall)
phoneCall = new CallLog();
if (!incomingNumber.isEmpty()) {
phoneCall.setPhoneNumber(incomingNumber);
}
// end: Probably not ever usefull
RecordCallService.sartRecording(context, phoneCall);
}
break;
case TelephonyManager.CALL_STATE_RINGING: // Phone ringing
// DO NOT try RECORDING here! Leads to VERY poor quality recordings
// I think something is not fully settled with the Incoming phone call when we get CALL_STATE_RINGING
// a "SystemClock.sleep(1000);" in the code will allow the incoming call to stabilize and produce a good recording...(as proof of above)
if (null == phoneCall)
phoneCall = new CallLog();
if (!incomingNumber.isEmpty()) {
phoneCall.setPhoneNumber(incomingNumber);
// called here so as not to miss recording part of the conversation in TelephonyManager.CALL_STATE_OFFHOOK
isWhitelisted.set(Database.isWhitelisted(context, phoneCall.getPhoneNumber()));
}
break;
}
}
}
And use Broadcast Receiver
public class MyCallReceiver extends BroadcastReceiver {
public MyCallReceiver() {
}
static TelephonyManager manager;
#Override
public void onReceive(Context context, Intent intent) {
Log.i("JLCreativeCallRecorder", "MyCallReceiver.onReceive ");
if (!AppPreferences.getInstance(context).isRecordingEnabled()) {
removeListener();
return;
}
if (Intent.ACTION_NEW_OUTGOING_CALL.equals(intent.getAction())) {
if (!AppPreferences.getInstance(context).isRecordingOutgoingEnabled()) {
removeListener();
return;
}
PhoneListener.getInstance(context).setOutgoing(intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER));
} else {
if (!AppPreferences.getInstance(context).isRecordingIncomingEnabled()) {
removeListener();
return;
}
}
// Start Listening to the call....
if (null == manager) {
manager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
}
if (null != manager)
manager.listen(PhoneListener.getInstance(context), PhoneStateListener.LISTEN_CALL_STATE);
}
private void removeListener() {
if (null != manager) {
if (PhoneListener.hasInstance())
manager.listen(PhoneListener.getInstance(null), PhoneStateListener.LISTEN_NONE);
}
}
}
I hope you get some help from this code.
Thanks
You can use accessibility events to detect the call duration and from that you can detect if the outgoing call is answered or not..
I have answered it in detail in Here` you can check that.
You need this permission in manifest
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
TelephonyManager has a listener to get phone state. implement this tho know if the phone is ringing or in a call.
TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
PhoneStateListener callStateListener = new PhoneStateListener() {
public void onCallStateChanged(int state, String incomingNumber) {
// TODO React to a incoming call.
try {
if (state == TelephonyManager.CALL_STATE_RINGING) {
Toast.makeText(getApplicationContext(), "Phone Is Ringing" + incomingNumber, Toast.LENGTH_LONG).show();
number = incomingNumber;
//g.setPhoneNo(incomingNumber);
AndroidNetCommunicationClientActivity.mMsgSendRequest("CommandMsgCallIncoming" + number);
} else if (state == TelephonyManager.CALL_STATE_OFFHOOK) {
Toast.makeText(getApplicationContext(), "Phone is Currently in A call" + incomingNumber, Toast.LENGTH_LONG).show();
//number = mIntent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
number = incomingNumber;
} else if (state == TelephonyManager.DATA_DISCONNECTED) {
number = "";
CallID = "";
}
} catch (Exception e) {
// TODO Auto-generated catch block
//conn.MessageBox(MainActivity.this, e.getMessage());
e.printStackTrace();
}
super.onCallStateChanged(state, incomingNumber);
}
};
telephonyManager.listen(callStateListener, PhoneStateListener.LISTEN_CALL_STATE);
Backgroud
I am developing an app which makes calls like lollpop. When a call comes it should show a popup on the screen and the default calling screen should not be visible.
What I have done
I have build the broadcast receiver and currently I am able to show a popup every time a call come.
by using this code
public class PhoneCallReceive extends BroadcastReceiver {
Class<?> c;
public static ITelephony telephonyService = null;
TelephonyManager telephony;
Method m;
public static int flag = 0;
public static AudioManager audioManager;
#Override
public void onReceive(Context conk, Intent inter) {
final Context context = conk;
final Intent intent = inter;
Thread pageTimer = new Thread() {
public void run() {
try {
sleep(800);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
try {
telephony = (TelephonyManager) context
.getSystemService(Context.TELEPHONY_SERVICE);
c = Class.forName(telephony.getClass().getName());
m = c.getDeclaredMethod("getITelephony");
m.setAccessible(true);
telephonyService = (ITelephony) m.invoke(telephony);
audioManager = (AudioManager) context
.getSystemService(Context.AUDIO_SERVICE);
} catch (Exception e) {
e.printStackTrace();
}
if (telephony.getCallState() == 1)
flag = 1;
Log.d("Rec", "reciever");
audioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
callingscreen("1", context, intent);
}
}
};
pageTimer.start();
}
public void callingscreen(final String type, final Context context,
final Intent intent) {
Intent intentPhoneCall = new Intent(context.getApplicationContext(),
CallerScreen.class);
intentPhoneCall.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_SINGLE_TOP);
intentPhoneCall.putExtra(
"number",
intent.getExtras().getString(
TelephonyManager.EXTRA_INCOMING_NUMBER));
intentPhoneCall.putExtra("type", type);
context.startActivity(intentPhoneCall);
}
} // class
Problem
But the Problem is that this popup is showing over the default calling screen. What I want to show the popup on the user current screen on which he was working.
Question
So the simple question is that how can I get the user current screen with its all functionality below the popup?
Please help:)
This solution works on every version of android, including lollipop
Use this broadcast reciever
class TeleListener extends PhoneStateListener {
public void onCallStateChanged(int state, String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);
switch (state) {
case TelephonyManager.CALL_STATE_IDLE:
// CALL_STATE_IDLE;
Toast.makeText(getApplicationContext(), "CALL_STATE_IDLE",
Toast.LENGTH_LONG).show();
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
// CALL_STATE_OFFHOOK;
Toast.makeText(getApplicationContext(), "CALL_STATE_OFFHOOK",
Toast.LENGTH_LONG).show();
break;
case TelephonyManager.CALL_STATE_RINGING:
// CALL_STATE_RINGING, call intent here
Intent i = null;
i = new Intent(context, My_activity.class).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
break;
default:
break;
}
}
}
and register it like this in onCreate
TelephonyManager TelephonyMgr = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
TelephonyMgr.listen(new TeleListener(), PhoneStateListener.LISTEN_CALL_STATE);
And yes, please dont miss
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
Cheers! Your problems is solved ;)
After a phone call ends, I must open another Activity.
However, it doesn't catch the "call end signal".
I've used mTelManager in BroadcastReceiver and Service, but it doesn't work.
When Activity is opened by a Service or BroadcastReceiver, it shows the MainActivity and not the targeted one instead.
Source code:
public class MainService extends Service{
TelephonyManager mTelManager;
PhoneStateRead pListener;
String TAG = "Call State catch";
boolean callOutState = false; //calling state
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate() {
Log.i(TAG, "ServiceReceiver->onReceive();");
pListener = new PhoneStateRead();
mTelManager = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
mTelManager.listen(pListener, PhoneStateListener.LISTEN_CALL_STATE);
if(callOutState){ //if call end
Intent showRecord = new Intent(getBaseContext(), Call_Out_Record_Activity.class);
showRecord.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(showRecord);//open Call_Out_Record_Activity
}
}
public class PhoneStateRead extends PhoneStateListener {
private final String TAG = "Phone State Read";
#Override
public void onCallStateChanged(int state, String incomingNumber) {
switch (state) {
case TelephonyManager.CALL_STATE_IDLE:
Log.i(TAG,"MyPhoneStateListener->onCallStateChanged() -> CALL_STATE_IDLE "+incomingNumber);
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
Log.i(TAG,"MyPhoneStateListener->onCallStateChanged() -> CALL_STATE_OFFHOOK "+incomingNumber);
break;
case TelephonyManager.CALL_STATE_RINGING:
Log.i(TAG,"MyPhoneStateListener->onCallStateChanged() -> CALL_STATE_RINGING "+incomingNumber);
break;
default:
Log.i(TAG,"MyPhoneStateListener->onCallStateChanged() -> default -> "+Integer.toString(state));
break;
}
CatchCallState(state);
}
}
private void CatchCallState(int state){
if(state == TelephonyManager.CALL_STATE_OFFHOOK || state == TelephonyManager.CALL_STATE_RINGING)
callOutState = false;
else if(state == TelephonyManager.CALL_STATE_IDLE)
callOutState = true;
}
}
So it looks like you have a couple problems here. First, you are trying to start your activity when you start your Service - you should do this code:
if(callOutState){ //if call end
Intent showRecord = new Intent(getBaseContext(), Call_Out_Record_Activity.class);
showRecord.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(showRecord);//open Call_Out_Record_Activity
}
in the CallStateListener. Or just put it in your CatchCallState method.
Next, notice that there is not a "call end signal" - the phone will go from "OFF_HOOK" to "IDLE" so you need flags to track that. Also, notice that "RINGING" happens on incoming calls, but not outgoing calls. So you may want to display different messages depending on incoming or outgoing calls.
I am trying to delete a particular incoming number from call log when phone hang-up. I tried as i can do but that code not working the number still remain in call log.
it is working properly when broadcast invoke but this is not deleting number of incoming call.
Thanks in Advance.
public class ListenPhoneState extends BroadcastReceiver {
private boolean isPressOffHock = false;
static private String incomingNumberToDelete;
#Override
public void onReceive(Context context, Intent intent) {
try {
// TELEPHONY MANAGER class object to register one listner
TelephonyManager tmgr = (TelephonyManager) context
.getSystemService(Context.TELEPHONY_SERVICE);
//Create Listner
MyPhoneStateListener PhoneListener = new MyPhoneStateListener();
// Register listener for LISTEN_CALL_STATE
tmgr.listen(PhoneListener, PhoneStateListener.LISTEN_CALL_STATE);
} catch (Exception e) {
Log.e("Phone Receive Error", " " + e);
}
if(incomingNumberToDelete != null)
{
String queryString="NUMBER="+incomingNumberToDelete;
context.getContentResolver().delete(CallLog.Calls.CONTENT_URI,queryString,null);
Log.d("Delete", "Delete Number " + incomingNumberToDelete );
}
}
private class MyPhoneStateListener extends PhoneStateListener {
public void onCallStateChanged(int state, String incomingNumber) {
if(state == TelephonyManager.CALL_STATE_RINGING)
{
incomingNumberToDelete = incomingNumber;
Log.d("Check", "income " + incomingNumberToDelete );
}
switch(state) {
case TelephonyManager.CALL_STATE_IDLE:
//Log.d("IDLE", state + "incoming" + incomingNumber);
isPressOffHock = true;
break;
case TelephonyManager.CALL_STATE_RINGING:
//Log.d("RINGING", state + "incoming" + incomingNumber);
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
String msg = "New Phone Call Event. Incomming Number : "+incomingNumber;
// Log.d("CALL_STATE_OFFHOOK",msg );
break;
}
}
}
}
Usually there is a delay between the broadcast of a phone state and the system data that is written or system activities (such as call logs or phone ringing). Right now, your receiver is probably trying to delete the call log before it is present.
You could delay the delete or take a look at this post for registering a ContentObserver:
Delete call from call log after call end
In my application I need to generate an alert or something of that kind which asks the user for confirmation before outgoing and incoming calls and texts. I'm done with NEW_OUTGOING_CALL and I can just Toast a msg.
You can use ITelephone.aidl and place events to listen the phone state. I am helping you for the Telephone calls handling (Including a short snippet about how to disconnect it). SMS also happens in similar way. It would be best if you can research and figure out about it
import com.android.internal.telephony.ITelephony;
import android.os.IBinder;
import android.widget.Toast;
import android.telephony.TelephonyManager;
import android.telephony.PhoneStateListener;
public class CallMonitor
{
protected StateListener phoneStateListener;
//stops the service to monitor any call.
public void stopMonitor()
{
try
{
TelephonyManager telephonymanager = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);
telephonymanager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE);
phoneStateListener=null;
Toast.makeText(this, "Call Monitoring Stopped", Toast.LENGTH_SHORT).show();
}
catch (Exception e)
{
}
}
public void startMonitor()
{
try
{
phoneStateListener = new StateListener();
TelephonyManager telephonymanager = (TelephonyManager)getSystemService(TELEPHONY_SERVICE);
telephonymanager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
Toast.makeText(this, "Call Monitoring Started", Toast.LENGTH_SHORT).show();
}
catch (Exception e)
{
e.printStackTrace();
}
}
#Override
public IBinder onBind(Intent arg0)
{
return null;
}
class StateListener extends PhoneStateListener
{
#Override
public void onCallStateChanged(int state, String incomingNumber)
{
super.onCallStateChanged(state, incomingNumber);
switch(state)
{
case TelephonyManager.CALL_STATE_RINGING:
Context context = getApplicationContext();
try
{
TelephonyManager manager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
Class c = Class.forName(manager.getClass().getName());
Method m = c.getDeclaredMethod("getITelephony");
m.setAccessible(true);
ITelephony telephony = (ITelephony)m.invoke(manager);
telephony.endCall();
}
catch(Exception e)
{
Toast.makeText(context, "Error ending the call" + e.getMessage(), Toast.LENGTH_LONG).show();
}
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
break;
case TelephonyManager.CALL_STATE_IDLE:
break;
}
}
};
}
Permissions are
<uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.CALL_PHONE" />
I have not worked in this area before but I think, You can use PhoneStateListener interface.. which will invoke functions as the phone state changes....The Telephony Manager might be useful too.
Just a try from my side hope that helped,