which broadcast receiver does execute first: dynamic or static? - android

While working with Android, I have one broadcast receiver which registers dynamically as well as statically. So my question is which has max priority to execute.

It depends on the priority set for particular BroadcastReceiver:
If the priority is not set, the receivers will be executed in an arbitrary order.
If the priority is set to the receiver either by using
<intent-filter android:priority="999"> in AndroidManifest.xml
OR
filter.setPriority(999); when registered through code.
Receiver with higher priority will be executed first.

Related

Android: what's the meaning of exported receiver's attribute?

<receiver
android:name="MyReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
I don't understand if it's needed to be notified.
If it were true any app could call my receiver with those actions? So If I make it false the system can send the actions to my receiver?
I don't understand if it's needed to be notified. If it were true any
app could call my receiver with those actions? So If I make it false
the system can send the actions to my receiver?
Actually, others apps cannot "call your receiver". Other apps can just send broadcast Intents. The System will then call all registered receivers.
In general you shouldn't worry about this. Most of these broadcast Intents are protected so that only system apps can broadcast them anyway. An attempt by another app to broadcast BOOT_COMPLETED, for example, would just be ignored. What would happen if your BroadcastReceiver gets triggered by a rogue app because it broadcast CONNECTIVITY_CHANGE? Probably nothing, because your app should check the real connectivity state in onReceive() anyway, and if there isn't any change you can just ignore it.
Also, you don't need to specify android:enabled="true" because this is the default state. You also don't need to specify android:exported="true" because you have an <intent-filter> attached to your <receiver> which automatically sets android:exported to true.
If you set android:exported ="false", implies that the receiver is intended only for application-internal use.
Note: This attribute is not the only way to limit a broadcast receiver's external exposure. You can also use a permission to limit
the external entities that can send it messages
Adding to #SaravInfern's answer. Here is the relevant permission doc for limiting external entities that can send the receiver messages:
https://developer.android.com/training/permissions/restrict-interactions#broadcast-receivers

What is the use of android:exported="true" in BroadcastReceiver

I see that some broadcast receiver use this tag android:exported="true" in Android Manifest.xml to register.
<receiver android:exported="true" android:name="com.flyingsoftgames.googleplayquery.QueryReceiver">
<intent-filter>
<action android:name="com.android.vending.INSTALL_REFERRER" />
</intent-filter>
</receiver>
What exactly the use of android:exported="true" to register broadcast receiver in Android?
From the Developer Guide:
android:exported
Whether or not the broadcast receiver can receive messages from sources outside its application — "true" if it can, and "false" if not. If "false", the only messages the broadcast receiver can receive are those sent by components of the same application or applications with the same user ID.
The default value depends on whether the broadcast receiver contains intent filters. The absence of any filters means that it can be invoked only by Intent objects that specify its exact class name. This implies that the receiver is intended only for application-internal use (since others would not normally know the class name). So in this case, the default value is "false". On the other hand, the presence of at least one filter implies that the broadcast receiver is intended to receive intents broadcast by the system or other applications, so the default value is "true".
This attribute is not the only way to limit a broadcast receiver's external exposure. You can also use a permission to limit the external entities that can send it messages (see the permission attribute).
android:exported
true : broadcast receiver can receive events sent by same or others applications
false‍ : broadcast receiver can receive events sent by same application

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.

Can broadcastreceiver take full control?

I have the following question:
Is it possible to completely override a phone-function when receiving a BroadcastReceiver? For example, is it possible to receive sms and do not let the sms to appear in the notification area?
thanks
Yes it is possible just define your BR like below code. make sure you call abortBroadcast(); method from receiver so it wont allow to further call onReceives of other BRs.
<receiver android:name=".SMSReceiver"
android:exported="true"
android:permission="android.permission.BROADCAST_SMS">
<intent-filter android:priority="1000">
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
Permission
<uses-permission android:name="android.permission.RECEIVE_SMS"></uses-permission>
but it wont guaranteed to work all the time as there may be other apps doing same and could have abortedBroadcast, so there may be chances even your onReceive wont be tringger.
Sometimes. It depends on what type of broadcast it is. Take a look through the docs for BroadcastReceiver:
There are two major classes of broadcasts that can be received:
Normal broadcasts (sent with Context.sendBroadcast) are completely asynchronous. All receivers of the broadcast are run in an undefined order, often at the same time. This is more efficient, but means that receivers cannot use the result or abort APIs included here.
Ordered broadcasts (sent with Context.sendOrderedBroadcast) are delivered to one receiver at a time. As each receiver executes in turn, it can propagate a result to the next receiver, or it can completely abort the broadcast so that it won't be passed to other receivers. The order receivers run in can be controlled with the android:priority attribute of the matching intent-filter; receivers with the same priority will be run in an arbitrary order.
SMS happens to be an ordered broadcast, so in this case if you call abortBroadcast, other receivers with a lower priority will not be called. This will only work if your priority is the highest though, which is not really possible to guarantee, but you can do a reasonable job by just setting a very high priority, perhaps over 9000 might be appropriate. Although the docs do say to not use anything 1000 or over, this is to ensure that the system always gets to handle the broadcasts. In your case though, you really do want to stop the system from handling the broadcast.

Broadcast Receiver Register in Manifest vs. Activity

I need some help to understand when I can expect my broadcast receiver will work when just registered in the manifest versus having to be registered from a running activity or service.
So for example if I register a stand alone receiver with the following intent filter it works without having a service/activity reference to it:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.blk_burn.standalonereceiver"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="10" />
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name" >
<receiver android:name="TestReceiver">
<intent-filter>
<action android:name="android.media.AUDIO_BECOMING_NOISY"/>
</intent-filter>
</receiver>
</application>
</manifest>
However if I replace android.media.AUDIO_BECOMING_NOISY with android.intent.action.HEADSET_PLUG the receiver is not triggered (Android Documentation)
From what I found on this site you have to register this receiver from an activity or service that is already running for it to work (Post).
Can anyone tell me why this does not work when just adjusting your intent filter in the manifest and why you need to have a service running in the background that references/registers the receiver?
Is there a work around so that I can just register my receiver in my app's manifest using an intent filter with android.intent.action.HEADSET_PLUG?
How can do I identify which Broadcast actions from the android documentation need to have a service or activity register them versus just having the right filter in the manifest?
If your receiver is registered in the manifest, and your app is not running, a new process will be created to handle the broadcast. If you register it in code, it's tied to the life of the activity/service you registered it in. For some broadcasts, it doesn't really make sense to create a new app process if it doesn't exist, or there are some security, performance, etc. implications, and thus you can only register the receiver in code.
As for the HEADSET_PLUG broadcast, it seems the idea is that your already running app can get this to do app-specific adjustments to UI, volume, etc. If your app is not running, you shouldn't really care about the headphones being unplugged.
AFAIK, there is no single place this info is summarized for all broadcasts, but each Intent should have a comment in the JavaDoc about how to register and use it, but apparently it's lacking in places. You should be able to compile a list if you grep the Android source tree for Intent.FLAG_RECEIVER_REGISTERED_ONLY.
As usual broadcast receivers can be configured in the manifest fileAndroidManifest.xml. A BroadcastReceiver that is configured in this way is called statically registered.
You can register your receiver in the manifest file by using the element:
<receiver
android:name=".ConnectivityChangeReceiver">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
The nested element is used to specify the event the receiver should react to.
Dyanmic Broadcast Recievers
As an alternative you can register your BroadcastReceiver implementation dynamically in your code. You just need to call the registerReceiver() method on your Context object.
The registerReceiver() method takes two parameters:
The arguments of the registerReceiver() method
receiver : The BroadcastReceiver you want to register
filter : The IntentFilter object that specifies which event your receiver should listen to.
When you register your receiver in this way, it lives for as long as the component livesand Android sends events to this receiver until the creating component itself gets destroyed.
It’s your task to handle the lifecycle correctly. Thus when you add a receiver dynamically, take care to unregister the same receiver in the onPause() method of your Activity!
I suggest to register the receiver in the onResume() method of your Activity and to unregister it in your onPause() method:
#Override
protected void onPause() {
unregisterReceiver(mReceiver);
super.onPause();
}
#Override
protected void onResume() {
this.mReceiver = new ConnectivityChangeReceiver();
registerReceiver(
this.mReceiver,
new IntentFilter(
ConnectivityManager.CONNECTIVITY_ACTION));
super.onResume();
}
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.

Categories

Resources