Keep widget BroadcastReceiver alive even if not instantiated from Manifest - android

i have a widget which needs to listen to BATTERY_CHANGED event, however, since this event is protected and cannot be declared from the manifest i create a new BroadcastReceiver from the Application constructor:
public void onCreate() {
super.onCreate();
if (DEBUG) Log.d(TAG, "onCreate()");
// Register receivers
if (receiver == null) {
receiver = new MYReceiver(this);
}
// Create new intentfilter
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
registerReceiver(receiver, intentFilter);
}
Then, from the Receiver i call a static method of the AppWidgetProvider which actually update the widget using RemoteViews. Everything works flawlessy until 1 hour as passed, after that time my Receiver disappears and the widget does not update anymore. I'm testing this on a Droid with 2.2.1 firmware-
What i'm doing wrong? Is this the correct way to update the widget (i just need that event so i don't want to have a service if its not needed). Should i use an AlarmManager to be sure from time to time that my receiver is still there? I can i do this?
Thanks.

I don't have a clue why your receiver got lost after an hour but what about using the AlarmManager to check periodically if it is still there? So you can re-register it if it got lost.

Related

Always check for screen on/off

To implement a simple sleep detection app I need to handle ACTION_SCREEN_OFF and ACTION_SCREEN_ON broadcasts in order to get the timing related to user's sleep (based on device inactivity). However, these broadcasts cannot be put in the manifest; the receiver has to be un-/registered in some app component.
How can I implement that? It seems to me that registering the receiver in, say,
a Service won't do much since after the service is done it should call for unregister. Unless I have a long, persistent service which is not doing anything.
You can create a STIKY service that is registering to a broadcast receiver.
In your broadcast check for on/off state in onReceive method:
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
// screen off
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
// screen on
}
And register like this in your service:
YourBroadcastReceived receiver = new YourBroadcastReceiver();
IntentFilter screenStateFilter = new IntentFilter();
screenStateFilter.addAction(Intent.ACTION_SCREEN_ON);
screenStateFilter.addAction(Intent.ACTION_SCREEN_OFF);
registerReceiver(receiver, screenStateFilter);
Don't forget to unregister after service is killed and always register just one time when service is created.

Disable automatic screen turn-off in Android during call

I have a service which launches a "BroadcastReceiver" after the user has finished booting (ACTION_BOOT_COMPLETED) and when the device goes to sleep (ACTION_SCREEN_OFF). My "BroadcastReceiver" checks when an incoming call is received (TelephonyManager.CALL_STATE_RINGING) and launches a "Service" that records the call. It is working but the problem is that my device turn off display during call when I put the phone to my ear, so the service launches again the "BroadcastReceiver". Is there someone who knows how to solve it?
public class MyService extends Service {
private BroadcastReceiver mReceiver;
#Override
public void onCreate() {
IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
filter.addAction(Intent.ACTION_SCREEN_OFF);
mReceiver = new MyReceiver();
registerReceiver(mReceiver, filter);
}
This should'nt be possible, because the telephone app is in the forground and is triggering the display if it detects an proximity near event. You can maybe set a wakelock and release this afterwards.

onReceive in BroadcastReceiver doesn't get called sometimes

I registered receiver in onCreate, but onReceive sometimes get called, sometimes not.
public class MyReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
Log.v("receiver","get called");
}
}
Here is how I register receiver in onCreate
PROCESS_RESPONSE = getBaseContext().getResources().getString(R.string.serviceResponse);
IntentFilter filter = new IntentFilter(PROCESS_RESPONSE);
filter.addCategory(Intent.CATEGORY_DEFAULT);
receiver = new MyReceiver();
registerReceiver(receiver, filter);
Here is how I send broadcast:
Intent broadcastIntent = new Intent();
PROCESS_RESPONSE=getBaseContext().getResources().getString(R.string.serviceResponse);
broadcastIntent.setAction(PROCESS_RESPONSE);
broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);
sendBroadcast(broadcastIntent);
Try this:
broadcastIntent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
The reason it sometimes works and doesn't work is
because Android 3.0 introduced a launch control security measure that prevents components of stopped applications from being launched via an intent. An application is considered to be in a stopped state if the application has either just been installed and not previously launched, or been manually stopped by the user using the application manager on the device. To get around this, however, a flag can be added to the intent before it is sent to indicate that the intent is to be allowed to start a component of a stopped application.
Quote source
So when you try a fresh install (launching from IDE) the application is considered in the stop state for a while, then later is not. So it sometimes doesn't work when you try to broadcast. Let me know if this works, and of course ensure you have registered the BroadcastReciever (I'm sure you have if it works, at least some of the time).

Dynamically registered BroadCastReceiver cannot Receive Broadcasts after its process is died why?

I am creating widget app that sync data with server i am registering BroadCastReceiver dynamically for receiving SCREEN_ON and SCREEN_OFF broadcasts i registered my BroadCastReceiver in class that extends Application, but the problem is that if the process is running it app receive SCREEN_ON and SCREEN_OFF broadcasts but if process is died then application would not be able to get receive broadcast why? in BroadCastReceiver theory they says app will receive broadcast even if it is not running.
public class ThisApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
Utils.logCat("ThisApplication", "onCreate()");
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
intentFilter.addAction(Intent.ACTION_SCREEN_ON);
registerReceiver(new ScreenOnOffReceiver(), intentFilter);
}
}
public class ScreenOnOffReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
Utils.logCat("Screen ScreenOnOffReceiver", "SCREEN is ON");
}
else
{
Utils.logCat("Screen ScreenOnOffReceiver", "SCREEN is OFF");
}
}
}
1 - You forgot to add the context to your new ScreenOnOffReceiver()
Change it to new ScreenOnOffReceiver(this).
2 - I guess you have an onPause(); method containing unregisterReceiver()?
This makes sure that when your app closes the BroadcastReceiver gets closed or unregistered as well. So it would be better to register your receiver directly using the manifest file. If for some reason you do HAVE to register it dynamically:
Use an if statement to check if your receiver is listening. If it is don't create another one. If it is not create one. If you want to know how(the code) comment below and I will do so)
BroadcastReceiver registered in the AndroidManifest.xml will receive broadcasts even if the process is not running
BroadcastReceiver registered during runtime only exist while the VM is running and will not be called if the process dies.
That is the rule, that is the indented behavior, it is always been like that, you cannot change it.
Said that:
if you want a you can during runtime enable/disable a BroadcastReceiver that is registered in the manifest like in this answer:
Enable and disable a Broadcast Receiver

BroadcastReceiver receives when service is started each time

I have a dynamically registered BroadcastReceiver on a Service. It gets AudioManager.RINGER_MODE_CHANGED_ACTION as IntentFilter. Every time I start the service I get the log message in onReceive() method. It works normally after that. I do not want it to receive once when service is started each time. Could you please tell me what I am missing here?
receiver=new BroadcastReceiver(){
#Override
public void onReceive(Context context, Intent intent) {
Log.d("zil", "degisti");
}
};
IntentFilter filter=new IntentFilter(
AudioManager.RINGER_MODE_CHANGED_ACTION);
registerReceiver(receiver,filter);
The intent you are interested in, AudioManager.RINGER_MODE_CHANGED_ACTION, is "sticky". That means that the system always keeps the last broadcast sent and whenever a BroadcastReceiver is registered that is interested in that Intent, it receives it right away. This is a very useful feature but sometimes it isn't what you want ;-)
I assume that you are only interested in actual "change" events. In this case you need to ignore the "current" event and listen only for any events that happen in the future. Lucky for you, there is a solution:
In 'onReceive()' do the following:
if (isInitialStickyBroadcast()) {
// Ignore this one as we aren't interested in the current state
} else {
Log.d("zil", "degisti");
// Do whatever you want to do with the event here
}
unregisterReceiver(receiver);
this probably wont work because you created an Anonymous inner class implementation of BroadcastReciever. instead create a nested/private class that extends BroacastReceiver in the activity where you want your service started. Then dynamically register and unregister your receivers in the Activity lifecycle callbacks

Categories

Resources