onReceive of BroadcastReceiver not working.
I am trying different ways.
Here is my current code.
Activity code
BroadcastReceiver _receiver;
public static final String SMS_RECEIVED_ACTION =
"android.provider.Telephony.SMS_RECEIVED";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
IntentFilter _intentFilter = new IntentFilter(SMS_RECEIVED_ACTION);
_intentFilter.setPriority(1234567);
registerReceiver(_receiver,_intentFilter);
_receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context,"Hello",Toast.LENGTH_LONG).show();
}
};
}
manifest file
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.SEND_SMS"></uses-permission>
Create your _receiver before registering it
_intentFilter.setPriority(999);
_receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context,"Hello",Toast.LENGTH_LONG).show();
}
};
registerReceiver(_receiver,_intentFilter);
The priority should be bigger than -1000 and smaller than 1000
Documentation
android:priority
The priority that should be given to the parent component with regard to handling intents of the type described by the filter. This attribute has meaning for both activities and broadcast receivers:
It provides information about how able an activity is to respond to an intent that matches the filter, relative to other activities that could also respond to the intent. When an intent could be handled by multiple activities with different priorities, Android will consider only those with higher priority values as potential targets for the intent.
It controls the order in which broadcast receivers are executed to receive broadcast messages. Those with higher priority values are called before those with lower values. (The order applies only to synchronous messages; it's ignored for asynchronous messages.)
Use this attribute only if you really need to impose a specific order in which the broadcasts are received, or want to force Android to prefer one activity over others.
The value must be an integer, such as "100". Higher numbers have a higher priority. The default value is 0. The value must be greater than -1000 and less than 1000.
Related
I implemented an BroadcastReceiver for Android-Platform to detect whenether the Devices Battery is being Charged or not. Unfortunately, it doesn't seem to work on my Device which has Android 10 installed (Android 10 is my minimum requirement for the App).
I need this BroadcastReceiver to be triggered even if the App is not running. Therefore an Implicit broadcast would be an excellent choice instead of register an BroadcastReceiver while the App is running.
Permissions set within "AndoirdManifest.xml"
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.BATTERY_STATS" />
My PowerConnectedBroadcastReceiver looks like this:
[BroadcastReceiver(Enabled = true, Exported = true)]
[IntentFilter(new[] { Intent.ActionPowerConnected, Intent.ActionPowerDisconnected, Intent.ActionDockEvent, Intent.ActionBatteryChanged }, Priority = (int)IntentFilterPriority.HighPriority)]
public class PowerConnectedBroadcastReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
Console.WriteLine($"PowerConnectedBroadcastReceiver received an intent: {intent}");
}
}
What am I doing wrong?
Any Kind of advise would be appreciated.
From Broadcast Receivers docs
Apps that target Android 8.0 (API level 26) or higher may not statically register for an implicit broadcast. Apps may still statically register for an explicit broadcast. There is a small list of implicit broadcasts that are exempt from this restriction. These exceptions are described in the Implicit Broadcast Exceptions guide in the Android documentation. Apps that are interested in implicit broadcasts must do so dynamically using the RegisterReceiver method. This is described next.
Dynamic registration
[BroadcastReceiver(Enabled = true, Exported = true)]
public class PowerConnectedBroadcastReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
Console.WriteLine($"PowerConnectedBroadcastReceiver received an intent: {intent}");
}
}
PowerConnectedBroadcastReceiver receiver;
IntentFilter intentFilter;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
receiver = new();
intentFilter = new(Intent.ActionPowerConnected);
intentFilter.AddAction(Intent.ActionPowerDisconnected);
intentFilter.AddAction(Intent.ActionDockEvent);
intentFilter.AddAction(Intent.ActionBatteryChanged);
intentFilter.Priority = (int)IntentFilterPriority.HighPriority;
}
protected override void OnResume()
{
base.OnResume();
RegisterReceiver(receiver, intentFilter);
}
protected override void OnPause()
{
UnregisterReceiver(receiver);
base.OnPause();
}
Edit
As the broadcast receiver is managed inside the activity it has the life cycle of the activity, if you want it to keep running for some reasons even if the app is not running, then i believe you should register/unregister it inside a foreground service.
Related questions:
Android keep BroadcastReceiver in background
How to keep broadcast receiver running in background?
Extra
Failing on un-register the broadcast receiver when the activity is terminated, will result in a leak. UnregisterReceiver() is called in OnPause rather than OnDestry() because the latter is not guaranteed to be called.
Android Activity onDestroy() is not always called and if called only part of the code is executed
In my application I have registered a broadcast receiver for an implicit broadcast by another application protected with permission :
<receiver
android:name=".receiver.MyReceiver"
android:exported="true"
android:permission="owner.custom.permission">
<intent-filter>
<action android:name="owner.custom.broadcast"/>
</intent-filter>
</receiver>
In MyReceiver#onReceive() I am invoking a JobIntentService MyService using enqueueWork():
public class MyReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
Log.i(TAG, "Received the broadcast");
MyService.enqueueWork(context, getServiceIntent(context));
}
private Intent getServiceIntent(final Context context) {
final Intent intent = new Intent(context, MyService.class);
intent.putExtra("someKey", true);
return intent;
}
}
I have the following method in MyService :
public static void enqueueWork(final Context context, final Intent work) {
enqueueWork(context, MyService.class, 111, work);
}
Now whenever owner.custom.broadcast is broadcast, MyReceiver is not triggered and I can see the following logs :
07-23 03:56:29.755 3335 3361 W BroadcastQueue: Background execution not allowed: receiving Intent { act=owner.custom.broadcast flg=0x10 } to com.amazon.myApp/.receiver.MyReceiver
Now the thing is I am listening to another such 3rd party implicit broadcast with a different broadcast receiver and invoking MyService over there and it works fine. I am also listening for BOOT_COMPLETED broadcast in a yet another broadcast receiver and invoking MyService over there and it works fine there too.
What are the possible causes for this error which would help me identify if I'm missing something.
UPDATE :
I am now just trying to get the broadcast receiver to trigger but I am still getting the same error. I am trying with nothing but a log line in the receiver :
public class MyReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
Log.i(TAG, "Received the broadcast");
}
}
Android O limits the implicit broadcast, you can't execute a background service in the receiver.
However, it only limits the static receivers, you can register your receiver in the code to trigger your service.
Of course, in some case, you don't want to do it "programmatically", then you should check the error case, from this link http://androidxref.com/8.1.0_r33/xref/frameworks/base/services/core/java/com/android/server/am/BroadcastQueue.java#1275 (Line:1275), I find the error (not sure if this is the same as your system version).
We can see there are few conditions to access to this code block, we analyze them one by one, all we want to do is make the condition equals false:
(r.intent.getFlags()&Intent.FLAG_RECEIVER_EXCLUDE_BACKGROUND) != 0
It means if we don't want the background to receive the intent the condition will be true, and usually, we don't add this flag because we want the background to receive the broadcast, go ahead.
r.intent.getComponent() == null
It should not be null in any of our case, go ahead.
r.intent.getPackage() == null
Same above, go ahead.
r.intent.getFlags()&Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND) == 0
It means we cannot have a flag called Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND, I think we can try this, but you will see this in the Intent class:
/**
* If set, the broadcast will always go to manifest receivers in background (cached
* or not running) apps, regardless of whether that would be done by default. By
* default they will only receive broadcasts if the broadcast has specified an
* explicit component or package name.
*
* NOTE: dumpstate uses this flag numerically, so when its value is changed
* the broadcast code there must also be changed to match.
*
* #hide
*/
public static final int FLAG_RECEIVER_INCLUDE_BACKGROUND = 0x01000000;
It's hidden, but you can just hardcode the integer in your project, now add this flag to your intent to try if your code is work.
intent.addFlags(0x01000000)
Good luck :)
Note: this solution will NOT resolve to receive the system implicit broadcast to run background tasks.
This is an old question, but I found a solution which worked for me.
As mentioned here
Context-registered receivers receive broadcasts as long as their
registering context is valid. For an example, if you register within
an Activity context, you receive broadcasts as long as the activity is
not destroyed. If you register with the Application context, you
receive broadcasts as long as the app is running.
I had to remove the receiver declaration in the Manifest completely and register my receiver during runtime, using the Application context!
IntentFilter filter = new IntentFilter("owner.custom.broadcast");
getContext().getApplicationContext().registerReceiver(new MyReceiver(), filter);
and then
public class MyReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
context.unregisterReceiver(this);
// ....
}
}
Try this
I faced a similar problem year ago, I'm not pretty sure of this, but since its not allowed for background execution then execute it in foreground using Foreground Service, you can achieve that by starting a service that is connected to a notification, then in your service you can trigger your broadcast and that should work.
I hope my answer helps you.
I'm not sure why this solution worked (maybe someone else can elaborate on why) but I was able to get my broadcast receiver to trigger by declaring the permission in my Manifest itself and and also using the same. Find the code changes below :
<permission
android:name="owner.custom.permission"
android:protectionLevel="signatureOrSystem">
</permission>
.
.
.
<uses-permission android:name="owner.custom.permission" />
I want a service to monitor the calls I dial, and to perform a specific task parallel to a specific call.
Example. I call 123 from the dialer and a specific task gets triggered at that time.
But if I dial some other number then nothing should happen.
How can I implement such a thing?
You can use BroadcastReceiver for ACTION_NEW_OUTGOING_CALL
public class OutgoingBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent. getAction (). equals (Intent. ACTION_NEW_OUTGOING_CALL)) {
String number=intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
Log.e("Number=", number);
if (number.equals("123")) {
// do your magic here
}
}
}
And don't forget and using permission:
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
For instance some example here, a phone running 2 or more apps, calling onReceive().
Has android some kind of task order to run all thouse #Overrides by ordered sequence? Probably yes, then in which order, app importance?
App1 & App2:
App1:
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String message = intent.getStringExtra("message");
Log.d("receiver", "Got message: " + message);
}
};
App2:
private BroadcastReceiver mMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String message = intent.getStringExtra("message");
deleteMessageFromInbox(message); // or just something that can conflict other Instance
}
};
You can define the order that intents are handled using the android:priority attribute of BroadcastReceivers. When an intent can be handled by multiple receivers, Android generates an ordered list (based on the priority of each receiver) and delivers the intent sequentially.
So in your case, when you register the receivers (via registerReceiver(BroadcastReceiver receiver, IntentFilter filter), all you have to do is assign a higher priority (via a call to setPriority(int priority)) to the intent filter in App1 than to the filter in App2 to make sure that App1 receives the intent before App2.
There is also an old article in the Android developers blog that gives you examples about how to implement this mechanism efficiently.
public class MainActivity extends Activity {
public TextView batteryTxt;
private BroadcastReceiver receiver;
BroadcastReceiver mybroadcast = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
int batterylevel = intent.getIntExtra("level", 0);
batteryTxt.setText("Battery Level: " + Integer.toString(batterylevel) + "%");
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
batteryTxt = (TextView) findViewById(R.id.textView1);
IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
registerReceiver(mybroadcast, filter);
}
}
Eventhough i have not used intent.putExtra() in above program, how intent.getIntExtra("level", 0) is working?
It's an IntentFilter, which sends an Intent to the BatteryManager to check ACTION_BATTERY_CHANGED. The BatteryManager then calls intent.putIntExtra to put the int that you're reciving in the Intent.
The intent is what your BroadcastReceiver receives from the system, when the action "ACTION_BATTERY_CHANGED" is performed. It's the information about battery level in this case, and "0" is the default value (in case there isn't extra named "level"). The intent is not created by any activity in this app.
You need to read the documentation on BroadcastReceivers and Intents.
http://developer.android.com/reference/android/content/BroadcastReceiver.html
http://developer.android.com/reference/android/content/Intent.html
Essentially these two mechanisms act as Android's preferred method of transferring state between applications and processes.
In short:
Broadcast Receivers are registered for Intents, and whenever an intent is "Fired" or "Launched" which corresponds to the "Mime-Type" for which your intent is registered, that Broadcast Receiver will be activated. At this time your Broadcast Receiver will be given the opportunity to handle state passed to it via the intent which was sent.
In your case:
You have created a Broadcast Receiver which is registered (presumably) for the Battery Service intents. That means every time the battery service sends out an Intent to all interested parties you'll receive an a message. The Battery Service includes in it's intent certain data which is useful to an application,service or process which is interested in the state of the Battery. In this case it is the "level".