Call Receiver makes my app "force close" - android

it all works fint till i answer the phone call,then a few seconds later and i get a "force close" message...any idea what is wrong?
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
TelephonyManager telephony = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
PhoneStateListener imPhoneListener = new PhoneStateListener();
telephony.listen(imPhoneListener, PhoneStateListener.LISTEN_CALL_STATE);
Bundle bundle = intent.getExtras();
String phoneNr= bundle.getString("incoming_number");
Intent intent1=new Intent("android.intent.action.Checker");
intent1.putExtra("phoneNr", phoneNr);
context.startActivity(intent1);
}
oh and by the way, how can i promise that my call reciver always work first even if the app is in the background?

TelephonyManager telephony = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
PhoneStateListener imPhoneListener = new PhoneStateListener();
telephony.listen(imPhoneListener, PhoneStateListener.LISTEN_CALL_STATE);
Without seeing the logcat it's hard to say for certain but you shouldn't be doing the above.
TelephonyManager is a system service and calling listen(...) is registering a permanent reference to your imPhoneListener object.
A BroadcastReceiver exists only as long as the code in onReceive() is being executed. This means once onReceive() exits, your imPhoneListener is no longer a valid object but TelephonyManager still holds a reference to it.
When you answer the phone call, you change the phone 'state' and the TelephonyManager will attempt to notify the non-existent imPhoneListener object. Something has to break here.
Get rid of those three lines as they effectively do nothing of any purpose for your BroadcastReceiver anyway - I'm not even sure what you're trying to acheive there.

Related

How to make sure the Broadcast Receiver is disconnected

I wrote a simple Broadcast Receiver which catches incoming calls and starts activity with the caller's number:
package com.example.nrsearch;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Log;
public class CallReceiver extends BroadcastReceiver {
public CallReceiver() {
}
public Context context;
#Override
public void onReceive(Context context, Intent intent) {
Log.i("CallReceiverBroadcast", "onReceive() is called. ");
this.context = context;
TelephonyManager teleMgr = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
PhoneStateListener psl = new PhoneStateListener() {
#Override
public void onCallStateChanged(int state, String incomingNumber) {
Log.i("CallReceiverBroadcast", "onCallStateChanged() is called. ");
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
Log.i("CallReceiverBroadcast", "Incoming call caught. Caller's number is " + incomingNumber + ".");
startNumberDisplayActivity(incomingNumber);
}
}
};
teleMgr.listen(psl, PhoneStateListener.LISTEN_CALL_STATE);
teleMgr.listen(psl, PhoneStateListener.LISTEN_NONE);
}
public void startNumberDisplayActivity(String incomingNumber) {
Intent i = new Intent(context, MainActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
i.putExtra("incomingNumber", incomingNumber);
context.startActivity(i);
}
}
However, after the first incoming call I feel like my device's battery starts to drain pretty quickly. I'm afraid that some process still prevents my Broadcast Receiver from disconnecting (I mean my Broadcast Receiver may be running forever). So, is there something in my code that could cause such a behavior and does this line really stops the TelephonyManager from listening for call state changes: teleMgr.listen(psl, PhoneStateListener.LISTEN_NONE); or should I do it some other way?
EDIT: I'm almost sure that this class causes battery drain, because now I'm testing battery life with my app uninstalled and it's much lower than previous when this app was installed and broadcast receiver was called. I can't swear that this class is the cause of the drain but the battery consumption difference is clearly visible with and without this app. Could somebody look at this code and say what could cause the battety drain? Thanks in advance!
in the method
#Override
public void onPause() {
super.onPause();
mActivity.unregisterReceiver(myReceiver);
}
You can put this other places, but that's a good one. DO your registration in onResume.
Also please read the broadcastreceiver docs, they don't work the way you seem to believe they do:
http://developer.android.com/reference/android/content/BroadcastReceiver.html
Basically the receiver lifecycle is:
Receiver Lifecycle
A BroadcastReceiver object is only valid for the duration of the call
to onReceive(Context, Intent). Once your code returns from this
function, the system considers the object to be finished and no longer
active.
This has important repercussions to what you can do in an
onReceive(Context, Intent) implementation: anything that requires
asynchronous operation is not available, because you will need to
return from the function to handle the asynchronous operation, but at
that point the BroadcastReceiver is no longer active and thus the
system is free to kill its process before the asynchronous operation
completes.
In particular, you may not show a dialog or bind to a service from
within a BroadcastReceiver. For the former, you should instead use the
NotificationManager API. For the latter, you can use
Context.startService() to send a command to the service.
Edit:
As per your comments - the concern about the BroadcastReceiver eating battery life isn't real. The receiver only lasts as long as it takes to run the code in it's on receiver method. At that point Android will clean it up as it deems nescesary. If anything in your code is breaking this it would be:
this.context = context;
/// these three lines
TelephonyManager teleMgr = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
.....
teleMgr.listen(psl, PhoneStateListener.LISTEN_CALL_STATE);
teleMgr.listen(psl, PhoneStateListener.LISTEN_NONE);
since you create a object and then try to listen on it.
However you should really read the docs:
anything that requires
asynchronous operation is not available,
Which is EXACTLY what you are doing in your code - attaching to a service and and waiting for its asyncronous response. This isn't acceptable in a BroadcastReceiver, and is clearly indicated in the docs at this point:
In particular, you may not show a dialog or bind to a service from
within a BroadcastReceiver.

Broadcast Receiver Dual Sim

I have a dual sim android phone. I am using a custom broadcast receiver which reads incoming messages with no problem. I wonder if there is a way to find out which sim received the message.
You can get the active sim's info by using TelephonyManager. FOr example, it's serial number.
TelephonyManager telephoneMgr = (TelephonyManager) ctx.getSystemService(Context.TELEPHONY_SERVICE);
String simSerial = telephoneMgr.getSimSerialNumber();
You could also get the line1Number, if your network operator has put your number in there, you could compare it to the number you got on the to> field in the SMS message.
String phoneNumber = telephoneMgr.getLine1Number();
Hope it helps
I had some really hard time with this problem and finally I found a solution, although i tested it only above api level 22.
You have to take a look at the extra information in the received intent. In my case there are two keys in the extra Bundle of the intent which are useful: "slot" and "subscription".
Here is the example:
public class IncomingSms extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
// Retrieves a map of extended data from the intent.
Bundle bundle = intent.getExtras();
int slot = bundle.getInt("slot", -1);
int sub = bundle.getInt("subscription", -1);
/*
Handle the sim info
*/
}
}
I did not find documentation about this so this could be device/manufacturer dependent, i can imagine that the keys are diferent or something like that.
You can verify this by dumping the key set of the bundle:
Set<string> keyset = bundle.keySet();

How to determine the phone number of a current caller in a stand-alone application

I'd like to build an Android application that can contact the current caller via a pre-determined text message. Sending a text message is simple enough but determining the phone number of the current caller in a stand-alone application is the challenge. Is the there an easy way to divine the phone number so I can send them a message while still on the call?
Of course there are manual ways to do this: write down the number, key it into a new text message, enter the message. But I want to define the message up front and be able to "send it to current caller".
#Override
public void onReceive(Context context, Intent intent) {
TelephonyManager telephony = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
PhoneCallStateListener customPhoneListener = new PhoneCallStateListener(context);
telephony.listen(customPhoneListener, PhoneStateListener.LISTEN_CALL_STATE);
helper = new ContactDatabaseHelper(context);
list = helper.getAllContacts();
try{
incomingNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
if (list.size() != 0){
for ( int i = 0, size = list.size(); i < size; i++ ){
if (PhoneNumberUtils.compare(incomingNumber, list.get(i).getContactNumber())){
ToastMsg.showToast(context,list.get(i).getContactName()+" Calling");
}
}
}
}catch (Exception e) {
// TODO: handle exception
}
}
public class PhoneCallStateListener extends PhoneStateListener{
private Context context;
public PhoneCallStateListener(Context context){
this.context = context;
}
#Override
public void onCallStateChanged(int state, String incomingNumber) {
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
break;
case PhoneStateListener.LISTEN_CALL_STATE:
}
super.onCallStateChanged(state, incomingNumber);
}
}
For your sistuation the best I can think of is to use PhoneStateListener. It contains onCallStateChanged handler. One of the arguments is a String containing the incoming phone number.
Source:
http://developer.android.com/reference/android/telephony/PhoneStateListener.html
Ctrl + F and type in "Incoming" and you will find everything you need to know.
EDIT: To make sure you're app starts on the startup of your phone, just add a BroadcastReciever. How to start an Application on startup?
Register a BroadcastReceiver in your manifest that listens to ACTION_PHONE_STATE_CHANGED.
Broadcast intent action indicating that the call state (cellular) on
the device has changed.
The EXTRA_STATE extra indicates the new call state. If the new state
is RINGING, a second extra EXTRA_INCOMING_NUMBER provides the incoming
phone number as a String.
Requires the READ_PHONE_STATE permission.
This was a sticky broadcast in version 1.0, but it is no longer
sticky. Instead, use getCallState() to synchronously query the current
call state.
This way you don't need the user to launch your app before receiving a call.

Android SIM change

Is it possible to detect SIM number using TelephonyManager in android at boot startup ,using Service at bootup...
TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
String ss=tm.getSimSerialNumber();
You need to register a broadcast receiver for the boot completion action i.e android.intent.action.BOOT_COMPLETED
in onReceive of this receiver you can start your service get SIM number with below code lines
TelephonyManager telephoneMgr = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
String phoneNumber = telephoneMgr.getLine1Number();
Also need to have permission for reading phone number as READ_PHONE_STATE in manifest file.
you can start service from broadcast receiver as -
public class BootListener extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent arg1) {
Intent intent = new Intent(context,Myservice.class);
context.startService(intent);
}
}

Intent & BroadcastReceiver

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

Categories

Resources