How reliable are Broadcast Receivers across different brand phones? - android

I have manifest declared Broadcasts for android.intent.action.PHONE_STATE and android.intent.action.NEW_OUTGOING_CALL. I tested my app after I removed it from Recent apps screen. I tested it on two phones:
MOTO G4 Play(Nougat)- After I removed my app from Recent apps screen on this phone I was receiving broadcasts.
ASUS(Lollipop)- After I removed my app from Recent apps screen on this phone I was not receiving broadcasts.
One way after reading such questions on SO I got is that I can do it by starting a sticky service so what it will do is not terminate my process and I will continue to get broadcasts.
What should I do to ensure that I receive broadcasts on every phone without using a service ?
Edit-1:I register my broadcasts as follows in Manifest
`
<receiver android:name=".PhonecallReceiver">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE"
android:enabled="true"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.NEW_OUTGOING_CALL"
android:enabled="true"/>
</intent-filter>
</receiver>
`
#Override
public void onReceive(Context context, Intent intent) {
Log.e("onReceive ","Called"); //This is how I check whether broadcast was called or not
//... other code
}

Think of notification broad cast that can be used to generate notification for your app, so broadcast is pretty reliable.
You are using manifest declared broad cast so theoretically, you should be able to receive broadcast regardless of whether your app is in foreground or background ( similar behavior was expected in all phone since your app targets same API). But there has been cases where mobile devices has ignored/bug some of the contract as a result some expected behavior breaks. It is very likely that similar thing happened in your ASUS based test.
From the broadcast manager documentation ,
If you declare a broadcast receiver in your manifest, the system
launches your app (if the app is not already running) when the
broadcast is sent.
However there is exception .Android has some updates on this behavior recently to restrict some of this features.
Note: If your app targets API level 26 or higher, you cannot use the manifest to declare a receiver for implicit broadcasts (broadcasts that do not target your app specifically), except for a few implicit broadcasts that are exempted from that restriction. In most cases, you can use scheduled jobs instead.
So what I believe is you should be receiving all broadcasts as long as you target API level less than 26 regardless of your app being active or not. Moving forward to API 26 or greater, you will receive broadcast regardless only if it is explicit OR exempted broadcast as per above quote.
What you encountered is probably that device specific issue which was not supposed to happen. Try testing in few more devices to rule this out.
You may want to read this for more clarification.
p.s. try not using error logging for info/debug like Log.e("onReceive ","Called");

Related

LocationManager.PROVIDERS_CHANGED_ACTION will not work on API 26 and higher

I am using following code to get location on/off event.
<receiver
android:name=".receivers.GpsReceiver"
android:enabled="true">
<intent-filter>
<action android:name="android.location.PROVIDERS_CHANGED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
I am developing geofence based app. Based on Re-register geofences only when required we have to re register the geofences after the app has received a GEOFENCE_NOT_AVAILABLE alert. This typically happens after NLP (Android's Network Location Provider) is disabled.
By using this broadcast receiver I re-registered the geofences when Android's Network Location Provider is enabled.
But from API level 26 this broadcast receiver will never work. See
Background Execution Limits.
So how can I achieve the same task in API 26 and higher?
Note : I need to re-register the geofences even when app is in the background.
You could switch to registering you receivers dynamically by Context.registerReceiver(), but IMHO there is no reliable way to get them registered "forever", because the system is going to terminate your process anyway on certain conditions.
Sure, you could re-register them by using e.g. white listed broadcast receivers, AlarmManager, JobScheduler etc. But this is not the best way in terms of battery and other resource consumption. Actually this is the reason, why Google disabled the implicit broadcasts.
The point is: By disabling implicit broadcasts in Oreo Google forces you to use some kind of recurring job to to do things like this. As the result, you don't need to listen for the NLP state updates, you just set your geofences with GeofencingClient.addGeofences (if NLP is enabled) in your recurring job over and over again.
as mentioned in the article you've linked, there's no way on Android API 26 to listen to implicit broadcasts like
<action android:name="android.location.PROVIDERS_CHANGED" />
if the app is killed or isn't currently running in background.
The only thing what you can do is to register the broadcast receiver on runtime, as stated in the migration guide.
What I did is calling registerReceiver in the application class in onCreate and unregister it in onTerminate.
class MyApplication : Application() {
private val gpsReceiver = MyBroadcastReceiver()
override fun onCreate() {
super.onCreate()
registerReceiver(gpsReceiver, IntentFilter("android.location.PROVIDERS_CHANGED"))
}
override fun onTerminate() {
super.onTerminate()
unregisterReceiver(gpsReceiver)
}
}
Hopefully, this could help you!
maybe you should try use background service and wakelock for long-running in the background when app closed/killed or screen off.
it's works for me :)

Mobilock app starts before BOOT_COMPLETED broadcast... How is it possible?

There is a kiosk app called Mobilock. This app starts way faster (Almost 5 seconds before) than my own app which starts with BOOT_COMPLETED broadcast.
My own app has the highest priority which is max value of integer. So this is not about the priority.
These guys have found a way to start their application 5 second sooner than BOOT_COMPLETED broadcast.
Has anyone got an idea about what they are doing?
Oh my god! I've luckily found it. :)
This Page Says : Apps must register their components with the system before they can run during Direct Boot mode or access device encrypted storage. Apps register with the system by marking components as encryption aware. To mark your component as encryption aware, set the android:directBootAware attribute to true in your manifest.
Encryption aware components can register to receive a ACTION_LOCKED_BOOT_COMPLETED broadcast message from the system when the device has been restarted. At this point device encrypted storage is available, and your component can execute tasks that need to be run during Direct Boot mode, such as triggering a scheduled alarm.
You just need to put
android:directBootAware="true"
So the code in manifest is;
<receiver
android:directBootAware="true" >
...
<intent-filter>
<action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
</intent-filter>
</receiver>
Listen also to android.intent.action.QUICKBOOT_POWERON and android.intent.action.LOCKED_BOOT_COMPLETED.
It seems to be device-dependant, which broadcast is sent first.

Boot completed Broadcast receiver is not working for dynamic registration

I created a broadcast receiver and registered in in manifest using following approach it is working fine
static way registering broadcast receiver (working fine)
<receiver
android:name="DeviceRestartListener"
android:enabled="true"
android:exported="false" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</category> -->
</intent-filter>
</receiver>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
But when i tried to register the broadcast receiver programmatic (instead of static way) using following way it doesnt work
Programmetic registering (not working)
DeviceRestartListener dataBroadcastReceiver = new DeviceRestartListener();
IntentFilter filter = new IntentFilter();
filter.addAction(
"android.intent.action.BOOT_COMPLETED")
//registerReceiver(dataBroadcastReceiver, filter); //DOESNT WORK
registerReceiver(dataBroadcastReceiver, filter, "android.permission.RECEIVE_BOOT_COMPLETED", null); //DOESNT WORK
No compilation and run time error. But the receiver is not receiving broadcast after device restarts
Thanks
All the Broadcast receivers will not work even when they are statically declared in manifest or registered dynamically using Application context. for example Intent actions like
Intent.ACTION_SCREEN_OFF
and
Intent.ACTION_SCREEN_ON
have to be registered dynamically. These actions will not be fired when they are declared in manifest. some Intent actions like
Intent.ACTION_TIME_CHANGED;
Intent.ACTION_TIME_TICK;
Intent.ACTION_TIMEZONE_CHANGED;
will be fired when are registered dynamically through context whose window token is not null.(like Activity or Dialog).
similar to this, some of the Intent actions like
Intent.ACTION_BOOT_COMPLETED
will work only when they are registered statically using manifest
Register receiver in code
When we register a receiver in code, we must unregister it when the app gets destroy (actually, when the Activity or Service that register it, gets destroy).
Register receiver in manifest
When we declare it in the manifest, you make it available even if you app is not running.
When to use which method to register
Which method to use for registering your BroadcastReceiver depends on what your app does with the system event. I think there are basically two reasons why your app wants to know about system-wide events:
Your app offers some kind of service around these events
Your app wants to react graciously to state changes
Examples for the first category are apps that need to work as soon as the device is booted or that must start some kind of work whenever an app is installed. Battery Widget Pro or App2SD are good examples for these kinds of apps. For this type you must register the BroadcastReceiver in the Manifest file.
Examples for the second category are events that signal a change to circumstances your app might rely on. Say your app depends on an established Bluetooth connection. You have to react to a state change – but only when your app is active. In this case there is no need for a statically registered broadcast receiver. A dynamically registered one would be more reasonable.
There are also a few events that you are not even allowed to statically register for. An example for this is the Intent.ACTION_TIME_TICK event which is broadcast every minute. Which is a wise decision because a static receiver would unnecessarily drain the battery.

Broadcast receiver not receiving intent

I have two apps that I have complete control over. Both are signed with the same cert and both use the exact same intent filter. One sends the broadcast from a fragment, the other is suppose to receive it and do something. This however is not working:
Strings.FILTER_INIT_REGISTER = "com.app.FILTER_INIT_REGISTER"
Intent intent = new Intent(Strings.FILTER_INIT_REGISTER);
getActivity().sendBroadcast(intent);
I have registered the receiver in the Manifest app tag for the app containing the ReportingReceiver class:
<receiver
android:name=".receivers.ReportingReceiver"
android:exported="true"
>
<intent-filter>
<action android:name="com.app.FILTER_INIT_REGISTER" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
Curious why the ReportingReceiver class is not getting the intent call?
If your application only has a service and receivers then this won't work in Android 3.1 and later. The reason is that the system will not send broadcast Intents to application that are in the STOPPED STATE. An application is in the STOPPED STATE when it is first installed. It is removed from the STOPPED STATE when the user manually starts the application for the first time. It is returned to the STOPPED STATE if the user forces the application to stop using the application manager tool.
Since your application has no Activities, there is no way for the user to "start" it. Therefore it will never come out of the stopped state.
See http://developer.android.com/about/versions/android-3.1.html#launchcontrols
As Android Addict says in his comment to David Wasser's answer ... there is a way around this behaviour.
Just add the following flag to the calling Intent. This will ensure that you also reach broadcast receivers from "stopped" applications.
http://developer.android.com/reference/android/content/Intent.html#FLAG_INCLUDE_STOPPED_PACKAGES
You can read more about this Android 3.1 change here
http://developer.android.com/about/versions/android-3.1.html#launchcontrols
and here
http://code.google.com/p/android/issues/detail?id=18225

Android: Event ACTION_POWER_CONNECTED is not sent to my BroadcastReceiver

I want to do something after the the phone is put into charger. So I
created ChargingOnReciever:
public class ChargingOnReceiver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
context.startActivity(someActivity);
Log.d(TAG, "Phone was connected to power");
}
}
and I want my receiver to listen to android.intent.action.ACTION_POWER_CONNECTED, so I put this into manifest:
<reciever android:name=".ChargingOnReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
</intent-filter>
</reciever>
But ChargingOnReceiver is apparently not started when I put my G1 to charger
(connect to my notebook via USB cable). Any help is much appreciated.
It's receiver, not reciever! It took me 5 hours to find this stupid bug. I think that the Android Eclipse plugin should do some syntax checking in the manifest xml.
For anyone trying to register receiver for "android.intent.action.ACTION_POWER_CONNECTED" and "android.intent.action.ACTION_POWER_DISCONNECTED" , I would like to add :
As part of the Android 8.0 (API level 26) Background Execution Limits,
apps that target the API level 26 or higher can no longer register
broadcast receivers for implicit broadcasts in their manifest.
However, several broadcasts are currently exempted from these
limitations. Apps can continue to register listeners for the exempted
broadcasts, no matter what API level the apps target.
The above two broadcasts are no longer in the list of these exempted broadcasts. Please refer the documentation below :
https://developer.android.com/guide/components/broadcast-exceptions
Do not start an activity from a BroadcastReceiver.
Have you examined LogCat at the time you plug in the USB cable to see if there are any logged messages that might explain your problem?

Categories

Resources