Which Intents/Broadcasts could be "sticky" in Android? - android

Where can I find information which Intent/Broadcast can be sticky?
Example of a sticky broadcast sent via the operating system is ACTION_BATTERY_CHANGED. When I call registerReceiver() for that action with a null BroadcastReceiver — I get the Intent that was last Broadcast for that action.
Whenever I find the last value by:
//In Activity
val batteryIntent = registerReceiver(null, IntentFilter(Intent.ACTION_BATTERY_CHANGED)); //sticky
val level = batteryIntent?.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
val scale = batteryIntent?.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
This Intent: AudioManager.ACTION_HEADSET_PLUG works too, but some Intents don't work: LocationManager.MODE_CHANGED_ACTION, Intent.ACTION_POWER_CONNECTED BluetoothDevice.ACTION_ACL_CONNECTED, ... I know, some don't make sense, but result of these Intents are always null, even if there has been a change, why?
For ACTION_BATTERY_CHANGED there is information: "This is a sticky broadcast ..." in doc, but for ACTION_HEADSET_PLUG no.
Is exist any restriction or split to sticky / non-sticky or list which Intents work as sticky?
Why do some Intents work and others don't?
Thank you.

Where can I find information which Intent/Broadcast can be sticky?
Look at the source code for the Android version of interest, searching for sendStickyBroadcast().
Is exist any restriction or split to sticky / non-sticky or list which Intents work as sticky?
Sticky broadcasts are sent using sendStickyBroadcast(). Technically, it is not tied to a specific Intent.

Related

How to receive intents flagged FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT

In Android 5.0 onwards, HidService.java includes following function:
private void broadcastReport(BluetoothDevice device, byte[] report, int rpt_size) {
Intent intent = new Intent(BluetoothInputDevice.ACTION_REPORT);
intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device);
intent.putExtra(BluetoothInputDevice.EXTRA_REPORT, report);
intent.putExtra(BluetoothInputDevice.EXTRA_REPORT_BUFFER_SIZE, rpt_size);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
sendBroadcast(intent, BLUETOOTH_PERM);
}
I am not able to find any documentation on this flag in the intent. How should I receive this broadcast intent in my app?
==============
Edited content deleted and formed into new question here
This constant is not documented in the Intent API docs because it is not intended for public use.
Here is a description from the android source code I found that describes it. (line 3018)
FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
public static final int FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
If set, when sending a broadcast before boot has completed only registered receivers will be called -- no BroadcastReceiver components will be launched. Sticky intent state will be recorded properly even if no receivers wind up being called. If FLAG_RECEIVER_REGISTERED_ONLY is specified in the broadcast intent, this flag is unnecessary.
This flag is only for use by system sevices as a convenience to avoid having to implement a more complex mechanism around detection of boot completion.
Emphasis mine.

Knowing about Sticky intent in Android

In android there are 3 kinds of Intents,
Intent,
Sticky Intent,
Pending intent.
so What is sticky intent?
Intent - is a message passing mechanism between components of Android, except for Content Provider. You can use Intent to start any
component.
Sticky Intent - Sticks with Android, for future broadcast listeners. For example if BATTERY_LOW event occurs then that Intent
will stick with Android so that any future requests for
BATTERY_LOW, will return the Intent.
Pending Intent - If you want some one to perform any Intent operation at future point of time on behalf of you, then we will use
Pending Intent.
An intent that is used with sticky broadcast, is called as sticky intent.
This intent will stick with android system for future broadcast receiver requests.
OR
sendStickyBroadcast() performs a sendBroadcast(Intent) known as sticky, i.e. the Intent you are sending stays around after the broadcast is complete, so that others can quickly retrieve that data through the return value of registerReceiver(BroadcastReceiver, IntentFilter). In all other ways, this behaves the same as sendBroadcast(Intent). One example of a sticky broadcast sent via the operating system is ACTION_BATTERY_CHANGED. When you call registerReceiver() for that action -- even with a null BroadcastReceiver -- you get the Intent that was last broadcast for that action. Hence, you can use this to find the state of the battery without necessarily registering for all future state changes in the battery.
Pending Intent: Pending Intent is actually an object which wraps an Intent to do some future work by another app.
It lets us pass a future Intent to another application and allows that application to execute that Intent as if it had the same permissions as our application, whether or not our application is still around when the Intent is eventually invoked.
A PendingIntent is generally used in cases were an AlarmManager needs to be executed or for Notifications. A PendingIntent provides a mean for applications to work, even after their process exits.
PendingIntent uses the following methods to handle the different types of intents:
PendingIntent.getActivity() : Retrieve a PendingIntent to start an Activity
PendingIntent.getBroadcast() : Retrieve a PendingIntent to perform a Broadcast
PendingIntent.getService() : Retrieve a PendingIntent to start a Service
Example :
Intent intent = new Intent(this, SomeActivity.class);
// Creating a pending intent and wrapping our intent
PendingIntent pendingIntent = PendingIntent.getActivity(this, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
try {
// Perform the operation associated with our pendingIntent
pendingIntent.send();
} catch (PendingIntent.CanceledException e) {
e.printStackTrace();
}
Intent: Intent is basically a message passing mechanism between different components of Android, except for Content Provider. You can use intent to start any component in Android.
Sticky Intent: These are the Intents which sticks with Android for future broadcast listener.
Sticky Intent is also a type of Intent which allows communication between a function and a service sendStickyBroadcast(), performs a sendBroadcast(Intent) known as sticky, the Intent you are sending stays around after the broadcast is complete, so that others can quickly retrieve that data through the return value of registerReceiver(BroadcastReceiver, IntentFilter). In all other ways, this behaves the same as sendBroadcast(Intent).
One example of a sticky broadcast sent via the operating system is ACTION_BATTERY_CHANGED. When you call registerReceiver() for that action — even with a null BroadcastReceiver — you get the Intent that was last Broadcast for that action. Hence, you can use this to find the state of the battery without necessarily registering for all future state changes in the battery.
Intent : Intent is an asynchronous message which is use to communicate between the components in android , except Content Provider.
for example you can start activity by
startActivity(Intent intent);
Sticky Intent : sticky intents are associated with the android system for the future broadcast events.
Pending Intent : Those intent which you want to trigger at some time in future when you application is not alive.
An intent that is used with sticky broadcast, is called as sticky intent. This intent will stick with android system for future broadcast receiver requests.
Sticky Intent allows a communication between function and a service sendStickyBroadcast() performs a sendBroadcast(Intent) know as sticky, the Intent you are sending stays around after the broadcast is complete so that others can quickly retrieve that data through the return value of registerReceiver(BroadcastReceiver, IntentFilter). In all other ways, this works the same as sendBroadcast(Intent).

About sticky intent ACTION_BATTERY_CHANGED

I'm using this code:
Intent i = getApplicationContext().registerReceiver(null, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
and as far as I understand i should be null if ACTION_BATTERY_CHANGED didn't occur, but it is never null and always returns me the same data.
It worked fine when I used a broadcast receiver. Do I need to delete the Intent after receiving it?
As soon as you register sticky intents will always deliver you last broadcasted data. So that is the reason you are always recieving data
Sticky=property of adhering
result=which intent adhered with os called sticky intent
Normally you send broadcast a receiver using sendBroadcast(Intent) But When you are calling this method sendStickyBroadcast(Intent) it means that A broadcast Intent can be specified to be sticky in which case it will be retained by the system after it has been sent. But by default Intent.ACTION_BATTERY_CHANGED intent is sticky.
read the full post here http://iphoidtech.com/uncategorized/what-is-stcky-intent/

Android: How can I completely abort/remove sticky broadcast

We can remove an ordered broadcast with abortBroadcast(), is there a way to completely remove a sticky ordered broadcast?
removeStickyBroadcast is exactly what you need:
public abstract void removeStickyBroadcast (Intent intent)
Since: API Level 1
Remove the data previously sent with sendStickyBroadcast(Intent), so that it is as if the sticky broadcast had never happened.
You must hold the BROADCAST_STICKY permission in order to use this API. If you do not hold that permission, SecurityException will be thrown.
Parameters
intent The Intent that was previously broadcast.
http://developer.android.com/reference/android/content/Context.html#removeStickyBroadcast(android.content.Intent)

Does a Android BroadcastReceiver need to have an Intent-Filter tag?

I have been able to get my BroadcastReceiver running with this:
<receiver
android:name=".AlarmReceiver"
android:enabled="true"
android:exported="false">
</receiver>
As you can see no <intent-filter>. It gets called correctly with the right Intent extras. But I have been looking around and I am confused as to whether I need one or not? I do have a setAction() method called on my Intents but to make them unique from others to ensure a specific issue with notifications, not actually using that action's string. But what exactly is the correlation? Thanks in advance.
Intent intent = new Intent(this.getContext(), AlarmReceiver.class);
intent.setAction("com.something"+System.currentTimeMillis());
//... extras are here
PendingIntent pi = PendingIntent.getBroadcast(this.getContext(), 123, intent, PendingIntent.FLAG_CANCEL_CURRENT|Intent.FILL_IN_DATA);
AlarmManager alarm = (AlarmManager)getContext().getSystemService(Activity.ALARM_SERVICE);
alarm.set(AlarmManager.RTC_WAKEUP, time.getTimeInMillis(), pi);
Using that with what I have in the manifest file works.
EDIT
I found this on the Android Developers blog, and it states this:
Implicit Intents only specify “what” they should match, using actions, categories, data,
MIME types, and so on. The exact components that they will find are only determined at
run-time, by the Package Manager matching it against the current applications.
Explicit Intents specify a single explicit “who” they should match, through a
ComponentName. Regardless of whatever else is in the Intent, it is only associated with
the exact manifest package name and class name as given in its ComponentName.
I am still slightly confused with this explanation, but it seems to be the closest thing to what I should be doing. So I am sure I am using an implicit intent. Question is, is it ok that I am leaving out <intent-filter>? I am matching it to a specific class. There may not be an actual action tying them together, perse, but is the class enough?
<intent-filter> is required when you want to start your receiver using implicit intents, if you are always using explicit intents to start your broadcast receiver then intent-filters are not required.
see this SO Post.
The entire way a broadcast receiver works is it involves using an Intent Filter to catch specific broadcast intents that are sent within the system. So if you give the receiver no intent filter, then NOTHING will be sent to it and its code will never execute.
Please read the documentation of Intent and learn how Intent allows IPC.
Update
Also its possible that without any declarations it could be receiving all public broadcasts and the way your code handles it.. is it ignores all the broadcasts except the ones it cares about. I've never done that this kind of implementation because I follow the standard. Which is to declare either as a dynamic listener (Programatic) or a static listener (XML declaration), where the dynamic listener would have its Intent Filter set in code.

Categories

Resources