I am developing an application which has a countdown timer. I want to pause that timer only if there is an incoming call on the phone. Is there any way to fire an event whenever we receive a call?
I think you should extends PhoneStateListener class.In that class you handle the phone state.For that use the permission in the manifest file for handling phone state (i.e. <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE">).
And use TelephonyManager to get the status of phone.
TelephonyManager manager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
manager.listen(this, LISTEN_CALL_STATE); // Registers a listener object to receive notification of changes in specified telephony states.
And override this method.
#Override
public void onCallStateChanged(int state, String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);
switch (state) {
case TelephonyManager.CALL_STATE_OFFHOOK:
case TelephonyManager.CALL_STATE_RINGING:
// Here you can perform your task while phone is ringing.
break;
case TelephonyManager.CALL_STATE_IDLE:
break;
}
}
When a Phone-Call is received OS fires a Message, technically called Broadcast.
Any Application can view/Respond to this message via Registering for PhoneIntentReceiver,
if more than one Application installed has registered for this, then all of them are given a chance to view this message based on Priority.
You can register for PhoneIntentReceiver via Manifest or Programatically. In both case you specify a Class that extends broadcast receiver in your project, that will receive a callback on detecting an Incoming call.
Then in this class the control is passed on to onReceive method. Its here that you can Stop your Timmer.
This is the story behind it.Happy Coding.
You have to write the Broadcast receiver which listens for incoming call
see this link for more info...
you have to use broadcast receiver for that........
First of all register your receiver in manifest.xml
<receiver android:name="com.cygnet.phonefinder.receiver.PhoneIntentReceiver" >
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
then you have to handle that reciever in
public class PhoneIntentReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) { } }
I would say the best implementation would be to utilize time stamps, timers (java.util.Timer or android.app.AlarmManager), and then listen for phone events using a broadcast receiver.
Basically every time you need to start an alarm for a certain period of time store a timestamp for the start of that alarm(probably easiest in an sql db) and then start the timer/alarm. When an alarm goes off make sure to clean up your stored timestamps.
Make sure to listen to phone state changes and on a phone call answered change clear all your alarms/timers and record the stop dates along with the previous timestamps and then when the phone call ends (from your reciever event) restart the timers/alarms for the remaining time.
In your Broadcastreceiver onReceive() write following code
Don't forget to give appropriate permission
TelephonyManager telephony = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
MyCallStateListener customPhoneListener = new MyCallStateListener();
telephony.listen(customPhoneListener, PhoneStateListener.LISTEN_CALL_STATE);
if (!intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_OFFHOOK))
return;
public class MyCallStateListener extends PhoneStateListener {
public void onCallStateChanged(int state, String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
break;
}
}
}
public class OutgoingCallReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "My Toast", Toast.LENGTH_LONG).show();
}
}
Try This receiver to fire an event
Related
I'm very new to mobile development and to Xamarin.
I created a new Xamarin.Forms solution "AndroidApp1" which by default consists of two projects, "AndroidApp1.Android" and "AndroidApp1".
If I understood correctly what I read, the first one contains the code specific to Android and the second one contains the code that can be used in Android, iOS or Windows Phone.
My solution runs in an Android emulation in debug mode, now I'd like to be notified when there's an incoming call, I'd like to get the telephone number that is calling me.
Google told me, that I need to create a class that inherits from BroadcastReceiver and override the OnReceive function.
I assume that this class needs to reside in the Android specific project (AndroidApp1.Android), so I created the class here, but now what?
I can't find any information about what to do with this class? Where do I instantiate it? How do I get the notification and the phone number to react on in my "AndroidApp1" project?
Here's the source code of my BroadcastReceiver (copied from the internet):
[BroadcastReceiver(Enabled = true, Exported = false)]
[IntentFilter(new[] { "android.intent.action.PHONE_STATE" })]
public class IncomingCallReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
// ensure there is information
if (intent.Extras != null)
{
// get the incoming call state
string state = intent.GetStringExtra(TelephonyManager.ExtraState);
// check the current state
if (state == TelephonyManager.ExtraStateRinging)
{
// read the incoming call telephone number...
string telephone = intent.GetStringExtra(TelephonyManager.ExtraIncomingNumber);
// check the reade telephone
if (string.IsNullOrEmpty(telephone))
telephone = string.Empty;
}
else if (state == TelephonyManager.ExtraStateOffhook)
{
// incoming call answer
}
else if (state == TelephonyManager.ExtraStateIdle)
{
// incoming call end
}
}
}
}
You need to register brodcast receiver for the call state.
<action android:name="android.intent.action.PHONE_STATE" />
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
and create a notification once your get broadcast events.
Make sure you have defined permission.
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
You need to have a Broadcast Receiver something like this.
/**
* Listener to detect incoming calls.
*/
private class CallStateListener extends PhoneStateListener {
#Override
public void onCallStateChanged(int state, String incomingNumber) {
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
// called when someone is ringing to this phone
Toast.makeText(ctx, "Incoming: "+incomingNumber,
Toast.LENGTH_LONG).show();
break;
}
}
You can register the lister for incoming call events.
tm = (TelephonyManager) ctx.getSystemService(Context.TELEPHONY_SERVICE);
tm.listen(callStateListener, PhoneStateListener.LISTEN_CALL_STATE);
Here is the more info
https://stackoverflow.com/questions/9684866/how-to-detect-when-phone-is-answered-or-rejected
Finally I am one step forward. I created a class StateListener that inherits from PhoneStateListener in the Android specific project like this:
public class StateListener : PhoneStateListener
{
public override void OnCallStateChanged(CallState state, string incomingNumber)
{
base.OnCallStateChanged(state, incomingNumber);
switch (state)
{
case CallState.Ringing:
break;
case CallState.Offhook:
break;
case CallState.Idle:
break;
}
}
}
Then I instantiated this class in the OnCreate function of the MainActivity class of the Android specific project with these three lines of code:
StateListener phoneStateListener = new StateListener();
TelephonyManager telephonyManager = (TelephonyManager)GetSystemService(Context.TelephonyService);
telephonyManager.Listen(phoneStateListener, PhoneStateListenerFlags.CallState);
Now when I set break points in the case parts of the switch (state) in OnCallStateChanged they break, but the incomingNumber is always empty, although I've set the corresponding rights in the manifest.
So, that will be my next step, to get the calling number.
To detect when an outgoing call is answered, I tried creating a PhoneStateListener and listening for TelephonyManager's CALL_STATE_RINGING, CALL_STATE_OFFHOOK, and CALL_STATE_IDLE, from this question, but it does not seem to work, as explained below.
First, I registered the following permission in the manifest:
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
Then, a BroadcastReceiver called OutCallLogger that catches the NEW_OUTGOING_CALL event whenever an outgoing call is made:
<receiver android:name=".listener.OutCallLogger">
<intent-filter>
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
</intent-filter>
</receiver>
Next, my implementation of OutCallLogger. I set up a boolean called noCallListenerYet to avoid attaching a new PhoneStateListener to the TelephonyManager whenever onReceive() is invoked.
public class OutCallLogger extends BroadcastReceiver {
private static boolean noCallListenerYet = true;
#Override
public void onReceive(final Context context, Intent intent) {
number = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
if (noCallListenerYet) {
final TelephonyManager tm = (TelephonyManager) context.getSystemService(
Context.TELEPHONY_SERVICE);
tm.listen(new PhoneStateListener() {
#Override
public void onCallStateChanged(int state, String incomingNumber) {
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
Log.d(This.LOG_TAG, "RINGING");
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
Log.d(This.LOG_TAG, "OFFHOOK");
break;
case TelephonyManager.CALL_STATE_IDLE:
Log.d(This.LOG_TAG, "IDLE");
break;
default:
Log.d(This.LOG_TAG, "Default: " + state);
break;
}
}
}, PhoneStateListener.LISTEN_CALL_STATE);
noCallListenerYet = false;
}
}
}
Now, when I make an outgoing call in my device, CALL_STATE_RINGING is NEVER invoked. I always only get printouts of "IDLE" to "OFFHOOK" when the other line starts ringing, nothing when the call is answered, and a printout of "IDLE" again when the call is ended.
How can I reliably detect when an outgoing call is answered in Android, or is that even possible?
Since Android 5.0 this is possible for system apps. But you need to use the hidden Android API.
I got it to work like this:
<uses-permission android:name="android.permission.READ_PRECISE_PHONE_STATE" />
<receiver android:name=".listener.OutCallLogger">
<intent-filter>
<action android:name="android.intent.action.PRECISE_CALL_STATE" />
</intent-filter>
</receiver>
public class OutCallLogger extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
switch (intent.getIntExtra(TelephonyManager.EXTRA_FOREGROUND_CALL_STATE, -2) {
case PreciseCallState.PRECISE_CALL_STATE_IDLE:
Log.d(This.LOG_TAG, "IDLE");
break;
case PreciseCallState.PRECISE_CALL_STATE_DIALING:
Log.d(This.LOG_TAG, "DIALING");
break;
case PreciseCallState.PRECISE_CALL_STATE_ALERTING:
Log.d(This.LOG_TAG, "ALERTING");
break;
case PreciseCallState.PRECISE_CALL_STATE_ACTIVE:
Log.d(This.LOG_TAG, "ACTIVE");
break;
}
}
}
You can find all possible call states in PreciseCallState.java and all extras that the intent contains in TelephonyRegistry.java.
It looks like the RINGING state is reached only by incoming calls. Outgoing calls change from IDLE to OFFHOOK, so looking at the Phone State maybe is not possible to achieve this.
I think that it could be possible using internal functions, look at this: What does the different Call states in the Android telephony stack represent?
Maybe try to use CallManager? Check out http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/2.3.3_r1/com/android/internal/telephony/CallManager.java. I also found CallManager.java among the SDK files on my computer. The following text from the linked page seems promising:
Register for getting notifications for change in the Call State Call.State This is
called PreciseCallState because the call state is more precise than the Phone.State
which can be obtained using the android.telephony.PhoneStateListener Resulting events
will have an AsyncResult in Message.obj. AsyncResult.userData will be set to the obj
argument here. The h parameter is held only by a weak reference.
1051
1052 public void registerForPreciseCallStateChanged(Handler h, int what, Object obj){
1053 mPreciseCallStateRegistrants.addUnique(h, what, obj);
1054 }
I haven't tried to code anything, so really don't know if it can do what you want, but I am curious to know.
Please pay your attention at:
tm.listen(new PhoneStateListener() {
#Override
public void onCallStateChanged(int state, String incomingNumber) {
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
Log.d(This.LOG_TAG, "RINGING");
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
Log.d(This.LOG_TAG, "OFFHOOK");
break;
case TelephonyManager.CALL_STATE_IDLE:
Log.d(This.LOG_TAG, "IDLE");
break;
default:
Log.d(This.LOG_TAG, "Default: " + state);
break;
}
}
}, PhoneStateListener.LISTEN_CALL_STATE);
Do you see "incomingNumber" argument? Yes, that code just can only detect your phone-call-state when there is an incoming-phone-call to your device.
You could do the following... not very precise but could do the trick:
You use the receiver for the android.intent.action.NEW_OUTGOING_CALL action
When the receiver is called you store somewhere (for instance a static var) the NEW_OUTGOIN_CALL state and the time in ms when this happened (i.e. new Date().getTime())
You use the another receiver for android.intent.action.PHONE_STATE and in the onReceive you do the following:
if (intent.getAction().equals("android.intent.action.PHONE_STATE")) {
TelephonyManager telephony = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
telephony.listen(new PhoneStateListener() {
public void onCallStateChanged(int state, String incomingNumber) {
switch(state) {
case TelephonyManager.CALL_STATE_IDLE:
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
break;
case TelephonyManager.CALL_STATE_RINGING:
break;
}
}
}, PhoneStateListener.LISTEN_CALL_STATE);
}
In the CALL_STATE_OFFHOOK case you check that the last stored state was NEW_OUTGOING_CALL and that the no more than aprox. 10 seconds have passed since the last state change. This means that the phone initiated a call at most 10 seconds ago and that now he is in the offhook state (meaning active call) without passing through idle or ringing. This could mean that the call was answered.
Here your answer is that you have implemented CallStateListener in OutGoingCallReceiver which is wrong. You have to implement CallStateListener in PhoneStateListener
I have also tried this thing in my earlier project, I had faced the same issue, then I solved it like as below. I took 3 classes as below.
AutoCallReceiver: Register the TelephonyManager with PhoneStateListener.LISTEN_CALL_STATE
CallStateListener which listens three states as TelephonyManager.CALL_STATE_IDLE,TelephonyManager.CALL_STATE_OFFHOOK,TelephonyManager.CALL_STATE_RINGING
3.OutGoingCallReceiver which handles out going call
public class OutGoingCallReceiver extends BroadcastReceiver {
/* onReceive will execute on out going call */
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "OutGoingCallReceiver", Toast.LENGTH_SHORT).show();
}
}
public class CallStateListener extends PhoneStateListener {
String number=""; // variable for storing incoming/outgoing number
Context mContext; // Application Context
//Constructor that will accept Application context as argument
public CallStateListener(Context context) {
mContext=context;
}
// This function will automatically invoke when call state changed
public void onCallStateChanged(int state,String incomingNumber)
{
boolean end_call_state=false; // this variable when true indicate that call is disconnected
switch(state) {
case TelephonyManager.CALL_STATE_IDLE:
// Handling Call disconnect state after incoming/outgoing call
Toast.makeText(mContext, "idle", Toast.LENGTH_SHORT).show();
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
// Handling outgoing call
Toast.makeText(mContext, "OFFHOOK", Toast.LENGTH_SHORT).show();
// saving outgoing call state so that after disconnect idle state can act accordingly
break;
case TelephonyManager.CALL_STATE_RINGING:
Toast.makeText(mContext, "RINGING", Toast.LENGTH_SHORT).show();
break;
}
}
}
public class AutoCallReceiver extends BroadcastReceiver {
/* onReceive will execute on call state change */
#Override
public void onReceive(Context context, Intent intent) {
// Instantiating PhoneStateListener
CallStateListener phoneListener=new CallStateListener(context);
// Instantiating TelephonyManager
TelephonyManager telephony = (TelephonyManager)
context.getSystemService(Context.TELEPHONY_SERVICE);
// Registering the telephony to listen CALL STATE change
telephony.listen(phoneListener,PhoneStateListener.LISTEN_CALL_STATE);
}
}
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
<application ...>
<receiver android:name=".OutGoingCallReceiver">
<intent-filter>
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
</intent-filter>
</receiver>
<receiver android:name=".AutoCallReceiver">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
</application>
I'm trying to build an application that logs when I accept and reject calls. Therefor I'm using a PhoneStateListener.
When I start the listener in the onCreate() method it is stopping its activity after some time. As far as I know Android closes the App because it has no focus.
I tried to work around that behavior with starting a service. All the code I wrote works fine and doesn't get killed by android...but the PhoneStateListener doesn't recieve any events.
How I start the Service:
public class RunningService extends IntentService {
/**
* A constructor is required, and must call the super IntentService(String)
* constructor with a name for the worker thread.
*/
public RunningService() {
super("RunningService");
}
/**
* The IntentService calls this method from the default worker thread with
* the intent that started the service. When this method returns,
* IntentService stops the service, as appropriate.
*/
#Override
protected void onHandleIntent(Intent intent) {
//...some code...creating a notification
startForeground(12345, notification);
TelephonyManager telephonyManager = (TelephonyManager) this
.getSystemService(TELEPHONY_SERVICE);
telephonyManager.listen(new PhoneStateListenerImpl(),
PhoneStateListener.LISTEN_CALL_STATE);
while (true) {
...some code to do...until Exit is called by user
}
}
}
The PhoneStateListener with basic output:
public class PhoneStateListenerImpl extends PhoneStateListener {
public PhoneStateListenerImpl() {
super();
Log.v("psListener", "constructor");
}
#Override
public void onCallStateChanged(int state, String incomingNumber) {
switch (state) {
case TelephonyManager.CALL_STATE_IDLE:
Log.v("PhoneStateListener", "IDLE");
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
Log.v("PhoneStateListener", "OFFHOOK");
break;
case TelephonyManager.CALL_STATE_RINGING:
Log.v("State", "Ringing");
break;
default: {
Log.v("Status", "something");
}
}
}
}
I get the Log output frome the Listeners constructor, but whenever something changes (like I'm calling someone) nothing happens.
The same Listener started from onCreate() works fine.
Maybe I'm missing something
I just tried:
I tried to ask the TelephonyManager for the phone state in the while loop of the Service. This works fine. But I guess this is just a dirty workaround.
Has anybody an idea what could be the problem?
you are registering your PhoneStateListener on onHandleIntent instead of that register your listener in onStartCommand or onCreate functions, and make sure you have mentioned following permissions in your project's manifest
I have a requirement wherein I want to detect two kind of events related to Calls in Android
Whenever an outgoing call is made, my application should get to know this along with the called number
When the call is hanged up(due to success/failure), my application should get to know this along with the reason of hangup
Is this possible in Android?
You should create a BroadcastReceiver:
public class CallReciever extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(
TelephonyManager.EXTRA_STATE_RINGING)) {
// Phone number
String incomingNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
// Ringing state
// This code will execute when the phone has an incoming call
} else if (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(
TelephonyManager.EXTRA_STATE_IDLE)
|| intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(
TelephonyManager.EXTRA_STATE_OFFHOOK)) {
// This code will execute when the call is answered or disconnected
}
}
}
You should register you application to listen to these intents in the manifest:
<receiver android:name=".CallReciever" >
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
There is a simpler solution using only TelephonyManager and
PhoneStateListener.You donĀ“t even have to register a BroadcastReceiver.
public class MyPhoneStateListener extends PhoneStateListener {
#Override
public void onCallStateChanged(int state, String incomingNumber) {
switch (state) {
//Hangup
case TelephonyManager.CALL_STATE_IDLE:
break;
//Outgoing
case TelephonyManager.CALL_STATE_OFFHOOK:
break;
//Incoming
case TelephonyManager.CALL_STATE_RINGING:
break;
}
}
}
And to register it:
public static void registerListener(Context context) {
((TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE)).listen(new MyPhoneStateListener(),
PhoneStateListener.LISTEN_CALL_STATE);
}
You need to create a receiver for the following intent actions:
Outgoing call - ACTION_NEW_OUTGOING_CALL
Call hangup - ACTION_PHONE_STATE_CHANGED
I'm starting learning android development, so my knowledge is really limited at the moment.
I'm trying playing with broadcasts, but I'm stuck and I can't understand what I'm doing wrong.
What I'm trying to do it's just show a simple Toast from the broadcast receiver.
The Intent is a custom intent defined in the manifest:
<receiver android:name=".receiver.SendReceiver" android:enabled="true">
<intent-filter>
<action android:name="com.android.terralink.sem.SOCCIA"></action>
</intent-filter>
</receiver>
The receiver is defined like this:
public class SearchReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent){
Toast.makeText(context, "asasa", Toast.LENGTH_SHORT).show();
}
}
In the first action called from the application I do this:
Intent i2 = new Intent(this, SearchReceiver.class);
i2.setAction(CUSTOM_INTENT);
sendBroadcast(i2);
I checked that the Toast code works in the Activity, but not in the broadcast.
It is because the Toast can't be shown in the receiver context?
Also, another question more about android application structure.
If from my Activty I allow the user to insert a string in a text box and submit (button bind), and I want the application do a search in the background and notify the user once the result is ready, is correct do the following?
1) Main Activity with search box
2) Start a Service that fetches the data, send a broadcast
3) The receiver notofy the user and open an Activity that shows the result
Does it make sense do something like that?
Or the notification should be done by the service itself before finish its job?
Thanks
I found out that the problem was in the manifest, when I registered the receiver.
Actually it is possible to show a Toast in the receiver without any issue.
Cheers
You cannot show a Toast in a broadcast receiver.
Android will usually shut down your process once the onReceive() call has finished (for which it only allowed to take max. 10 seconds currently). Since a toast is shown asynchronously, I think its context is killed before it is even displayed.
As an alternative to Toast, you can take a look at the concept of RemoveViews for updating UI in another process from a receiver. Or, launch an activity that shows a toast and closes immediately.
For your question #2, I suggest that you keep the activity running after the search button is clicked and start an AsyncTask for the search, which updates the search results as they come in.
To show toast from a broadcast receiver we can use the following code:
public class ServiceReceiver extends BroadcastReceiver {
Context context;
#Override
public void onReceive(Context context, Intent intent) {
this.context = context;
MyPhoneStateListener phoneListener = new MyPhoneStateListener();
TelephonyManager telephony = (TelephonyManager) context
.getSystemService(Context.TELEPHONY_SERVICE);
telephony.listen(phoneListener, PhoneStateListener.LISTEN_CALL_STATE);
}
private class MyPhoneStateListener extends PhoneStateListener {
#Override
public void onCallStateChanged(int state, String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);
switch (state) {
case TelephonyManager.CALL_STATE_IDLE:
Toast.makeText(context, "Idle call", Toast.LENGTH_LONG).show();
Log.d("***************************DEBUG", "IDLE");
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
Log.d("***************************DEBUG", "OFFHOOK");
break;
case TelephonyManager.CALL_STATE_RINGING:
Toast.makeText(context, "Ringing call", Toast.LENGTH_LONG)
.show();
Log.d("***************************DEBUG", "RINGING");
break;
}
}
}
}