BroadcastReceiver.onReceive not called, but Activity.onNewIntent do. Why? - java

I am trying to get "DeleteIntent" callback from my notification.
BroadcastReceiver.onReceive not called from PendengIntent, while it works OK when broadcast is launched manually with sendBroadcast(deleteIntent).
It works well when intent target is Activity (hits Activity.onNewIntent) but it is weird to use it since activity goes foreground when message dismissed.
Please, help to get onReceive call to BroadcastReceiver.
It is visible, exported and enabled, located in the same package.
MyCancelReceiver class
public class MyCancelReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
}
}
Android manifest
<activity android:name=".MainActivity" android:launchMode="singleTask">
<MyCancelReceiver" android:enabled="true" android:exported="true">
<intent-filter>
<action android:name="notification_cancelled"/>
</intent-filter>
</receiver>
MainActivity
private MyCancelReceiver mReceiver;
#Override
public void onStart() {
super.onStart();
IntentFilter filter = new IntentFilter();
filter.addAction("notification_cancelled");
mReceiver = new MyCancelReceiver();
registerReceiver(mReceiver, filter);
}
#Override
public void onStop() {
super.onStop();
unregisterReceiver(mReceiver);
}
Notification creation:
Intent cancelIntent = new Intent(getApplicationContext(), MyCancelReceiver.class);
cancelIntent.setAction("notification_cancelled");
cancelIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent deleteIntent = PendingIntent.getActivity(getApplicationContext(), 0, cancelIntent, PendingIntent.FLAG_CANCEL_CURRENT);
Notification not = new Notification.Builder(getApplicationContext(), Util.ANDROID_CHANNEL_ID)
.setContentTitle(messageTitle)
.setContentText(messageBody)
.setSmallIcon(R.drawable.default)
.setAutoCancel(true)
.setDeleteIntent(deleteIntent)
.setContentIntent(contentIntent)
.build();
NotificationManager notificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0, not);
Thank you in advance.

It's because when you start your activity, onStart() gets called and you will get a callback in onReceive() as soon as the activity is launched. But when you click your notification onStart won't be called as the activity is already created, In this case, onStart wont be called. Try registering in onResume(), I am pretty sure it will work.

Problem solved using an answer from this thread Click on android notification icon does not trigger broadcast receiver
Explicit intent replaced with implicit one.
Intent cancelIntent = new Intent("notification_canceled");

Related

How do I detect if device is charging from background

I have searched thick and thin through the Developer notes for android and am unable to find out how to perform a specific action when a device is plugged in, and perform another action when unplugged.
I have attempted to set a Broadcast Receiver like below however it will not run:
<receiver android:name=".PowerConnectionReceiver">
<intent-filter>
<action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
<action android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
</intent-filter>
</receiver>
I understand that from API 26 and up, you can no longer receive some broadcasts registered in the manifest, and must register them dynamically.
I need to have this run in the background but can't figure out how? This article updated in 2019 (after api 26) implies that I should be able to do it.
The charging status can change as easily as a device can be plugged in, so it's important to monitor the charging state for changes and alter your refresh rate accordingly.
The BatteryManager broadcasts an action whenever the device is connected or disconnected from power. It's important to receive these events even while your app isn't running particularly as these events should impact how often you start your app in order to initiate a background update so you should register a BroadcastReceiver in your manifest to listen for both events by defining the ACTION_POWER_CONNECTED and ACTION_POWER_DISCONNECTED within an intent filter.
My end goal is to call the broadcast receiver whenever device is plugged in or unplugged.
How would I go about implementing this?
The best way to accomplish this is by having a service run in the background so that you can receive the broadcast from android without the user using the app.
Start by registering a service in your manifest file.
<Service android:name=".serviceName"/>
Now create your class with the same name as registered in the manifest above, this class must extend Service.
public class BackgroundService extends Service {
private static final int NOTIF_ID = 1;
private static final String NOTIF_CHANNEL_ID = "AppNameBackgroundService";
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId){
//Add broadcast receiver for plugging in and out here
ChargeDetection chargeDetector = new ChargeDetection(); //This is the name of the class at the bottom of this code.
IntentFilter filter = new IntentFilter();
filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
filter.addAction(Intent.ACTION_POWER_CONNECTED);
filter.addAction(Intent.ACTION_POWER_DISCONNECTED);
this.registerReceiver(chargeDetector, filter);
startForeground();
return super.onStartCommand(intent, flags, startId);
}
private void startForeground() {
createNotificationChannel();
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
notificationIntent, 0);
startForeground(NOTIF_ID, new NotificationCompat.Builder(this,
NOTIF_CHANNEL_ID) // don't forget create a notification channel first
.setOngoing(true)
.setSmallIcon(R.mipmap.final_icon)
.setContentTitle(getString(R.string.app_name))
.setContentText("Background service is running")
.setContentIntent(pendingIntent)
.build());
}
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel serviceChannel = new NotificationChannel(
NOTIF_CHANNEL_ID,
"Foreground Service Channel",
NotificationManager.IMPORTANCE_DEFAULT
);
NotificationManager manager = getSystemService(NotificationManager.class);
manager.createNotificationChannel(serviceChannel);
}
}
}
class ChargeDetection extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
//Now check if user is charging here. This will only run when device is either plugged in or unplugged.
}
}
}
You need to register this receiver from code
You could run a WorkManager to run once every 15 minutes (the minimum is once every 15 minutes)
register the receiver, check if it's charging
unregister the receiver

BroadcastReceiver not being called when pressing Notification Button

Inside the onCreate method of my Service I create a notification by doing the following:
String channelId = "001";
String channelName = "myChannel";
NotificationChannel channel = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_NONE);
channel.setLightColor(Color.BLUE);
channel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (manager != null) {
manager.createNotificationChannel(channel);
Notification notification;
Intent myIntent = new Intent("alarmReceiver");
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, myIntent, 0);
Notification.Action action = new Notification.Action.Builder(
Icon.createWithResource(this, R.drawable.ic_stop_black_24dp),
"action string",
pendingIntent).build();
//Modify notification badge
notification = new Notification.Builder(getApplicationContext(), channelId).setOngoing(true)
.setSmallIcon(R.mipmap.ic_launcher)
.setCategory(Notification.CATEGORY_SERVICE)
.addAction(action)
.build();
startForeground(101, notification);
}
The alarmReceiver in the Intent above is registered in my manifest as shown below (I did the following after seeing this question):
<receiver android:name=".AlarmReceiver">
<intent-filter>
<action android:name="alarmReceiver" />
</intent-filter>
</receiver>
and here is my AlarmReceiver class:
public class AlarmReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.e("onReceive - ","was called");
}
}
The notification is shown, as well as the button, but when I press the button nothing happens.
I'm not sure what I'm doing wrong. Any help would greatly be appreciated.
Set PendingIntent to foreground service, And potentially add a flag:
FLAG_UPDATE_CURRENT
PendingIntent pendingIntent = PendingIntent.getForegroundService(this, 0, myIntent, FLAG_UPDATE_CURRENT);
Your broadcast is Implicit, so if you want to use getBroadcast() it may be best to Explicitly declare the receiver by providing the intent with the componentName of the receiver.
eg:
intent.setComponent(new ComponentName("packagename","fully qualified class name"));
Have you declared the service in your manifest?

Broadcast receiver not firing

I'm programming an application that will fire a specific method once it hits a certain date / time. However, my broadcast reciever is not firing...i can see that the alarm is set.
my method within an activity:
private void setAlarm(Date date){
Intent activate = new Intent(this, Alarm.class);
AlarmManager alarms ;
Calendar cal = new GregorianCalendar();
cal.setTimeInMillis(date.getTime());
PendingIntent alarmIntent = PendingIntent.getBroadcast(this, 0, activate, 0);
alarms = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
Log.d("ALARM","Setting alarm");
alarms.set(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(), alarmIntent);
Log.d("ALARM","Setting time "+cal.getTimeInMillis());
}
My BroadcastReciever:
public class Alarm extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.d("ALARM", "RING RING");
}
}
My manifest within the <application> tag:
<receiver android:name=".Alarm" android:process=":remote" >
<intent-filter>
<action android:name="com.package.feature.subpackage.arrangealarm.ALARM_ACTION"/>
</intent-filter>
</receiver>
Does anyone have any idea why this is not firing?
There seems to be nothing wrong with your code (I copied the snippet and had Android Studio generate a BroadcastReceiver for which I set android:process=":remote" just like you do).
When I run the app, the BroadcastReceiver fires but I can only see the respective Logcat entry when I select "No Filters" in the Logcat settings (on the right side), not when I choose "Show only selected application".
This happens because you use android:process=":remote". The BroadcastReceiver will run in another process than the "main" application process, so the "RING RING" will appear under another process id.

Android: writing to realm database from notification

I am building an app and ran into a problem that I couldn't find an answer to.
I have a realm database that I use to store some very simple information. Now what I want to do is every day at a set time prompt the user with a notification with a few buttons on it. And depending on what button the user clicks, I want to write a different value to the realm database. PREFERABLY without opening the app. Is this possible?
Thanks in advance!
You can do it in this way.
First, create a Notification with actions on it.
Intent intentLike = new Intent("MY_ACTION");
intentLike.putExtra("KEY","LIKE");
PendingIntent likePendingIntent = PendingIntent.getBroadcast(context,0,intentLike,PendingIntent.FLAG_UPDATE_CURRENT);
Intent intentShare = new Intent("MY_ACTION");
intentShare.putExtra("KEY","SHARE");
PendingIntent sharePendingIntent = PendingIntent.getBroadcast(context,1,intentShare,PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.notification_icon)
.setContentTitle("My notification")
.setContentText("Hello World!")
.addAction(R.drawable.notification_action_like, "Like", likePendingIntent)
.addAction(R.drawable.notification_action_share, "Share", sharePendingIntent);
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// mId allows you to update the notification later on.
mNotificationManager.notify(mId, mBuilder.build());
Now create a BroadcastReceiver class to receive values.
public class LikeShareReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String receivedValue = intent.getExtra("KEY");
if (receivedValue.equals("LIKE")) {
//update like in Realm database.
}else if (receivedValue.equals("SHARE")) {
//update share in Realm database.
}
}
}
Add this BroadcastReceiver in the manifest file.
<receiver android:enabled="true" android:name="LikeShareReceiver">
<intent-filter>
<action android:name="MY_ACTION" />
</intent-filter>
</receiver>
How this will work?
When a user clicks on an action button it will trigger a broadcast with an intent having values in it. BroadcastReceiver will receive this broadcast and update the database accordingly.
Note:addAction() method will only work with api level >=4.1

BroadcastReceiver not receiving boolean value after AlarmManager finishes set time

I am using a BroadcastReceiver to enable a button when it is triggered. I have an AlarmManager that runs for a certain amount of time. When the time has elapsed, it sends a broadcast like this:
Intent i = new Intent("polarCap1Status");
i.putExtra("polarCap1Stat", true);
LocalBroadcastManager.getInstance(context).sendBroadcast(i);
I use this code to receive the broadcast:
//broadcast receiver to allow button to be clicked again
mMessageReceiver1 = new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent)
{
clickOnOff1 = intent.getBooleanExtra("polarCap1Stat", false);
polarCap1.setEnabled(clickOnOff1);
updateScores();
resources.edit().putBoolean("pc1Set", false).commit();
}//end onReceive function
};
LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(mMessageReceiver1, new IntentFilter("polarCap1Status"));
I have the receiver setup in my manifest like so:
<receiver android:name="com.twentytwentythree.sab.SetupTimerPC1" >
<intent-filter>
<action android:name="polarCap1Status" />
</intent-filter>
</receiver>
SetupTimerPC1 is the name of the class that is sending the broadcast. It is sending it to another class called runGraphics.
Please let me know if you need any more information.
Edit:
I added an intent-filter to the receiver in the manifest but it has not changed anything.

Categories