I have an app hooked with push notifications. When the user click on the notification, I want a broadcast receiver to be triggered instead of an activity.
I looked at these threads and looks like this is perfectly possible and common.
Android Notification Action is not fired (PendingIntent)
Send broadcast on notification click
However I can't get it to work. I see the notification, but when I click on it and it never triggers my Broadcast receiver.
Here what I have tried:
I created a custom receiver:
public class NotificationOnClickReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, Intent intent) {
Log.d(Constants.Engine.LOGGER_TAG_GCM,
NotificationOnClickReceiver.class.toString() + " triggered");
}
}
I registered this receiver dynamically on my global Application (not activity)
mNotificationOnClickReceiver = new NotificationOnClickReceiver();
IntentFilter intentFilterOnClick = new IntentFilter(Constants.Engine.BROADCAST_RECEIVER_FILTER_NOTIFICATION_ONCLICK);
getApplicationContext().registerReceiver(mNotificationOnClickReceiver, intentFilterOnClick);
Log.e(Constants.Engine.LOGGER_TAG_DBG, "mNotificationOnClickReceiver = " + mNotificationOnClickReceiver.toString());
The filter is just a string constant (I wonder if this is the problem)
public static final String BROADCAST_RECEIVER_FILTER_NOTIFICATION_ONCLICK = "push_notification.onclick";
Receiver intent setup:
// When the user taps on the notification bar, this is the receiver that I want to be called
Intent pushNotificationIntent;
Log.e(Constants.Engine.LOGGER_TAG_DBG, "Notification called!");
pushNotificationIntent = new Intent(this, NotificationOnClickReceiver.class);
// Not sure if this causing the problem
pushNotificationIntent.setAction(Constants.Engine.BROADCAST_RECEIVER_FILTER_NOTIFICATION_ONCLICK);
// ensures that each notification and intent are unique
int uniqueCode = new Random().nextInt(Integer.MAX_VALUE);
PendingIntent pendingIntent = PendingIntent.getBroadcast(
context,
uniqueCode,
pushNotificationIntent, // Receiver Intent
PendingIntent.FLAG_CANCEL_CURRENT);
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context)
.setSmallIcon(mIconId)
.setContentTitle(context.getString(R.string.myString))
.setContentText("My GCM Alert!")
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
From the logs, things seem to work except that my Broadcast receiver never gets called:
02-22 15:47:47.092 16863-16863/com.myapp.test E/MYAPP_DBG: mNotificationOnClickReceiver = mytest.broadcastreceivers.NotificationOnClickReceiver#d78f559
02-22 15:47:53.312 16863-17038/com.myapp.test E/MYAPP_DBG: Notification called!
If anyone has this working, can you point me out a sample code? I don't see where my bug is.
thank you!
This would appear to be the problem:
pushNotificationIntent = new Intent(this, NotificationOnClickReceiver.class);
You're actually creating an explicit Intent for the broadcast PendingIntent. Explicit Intents do not work with dynamically registered Receivers, as they target a Receiver class, rather than an instance.
You'll need to use an implicit Intent instead, which you can do by simply instantiating the Intent with the action String, rather than a Context and Class. For example:
pushNotificationIntent = new Intent(Constants.Engine.BROADCAST_RECEIVER_FILTER_NOTIFICATION_ONCLICK);
Please note that if your app's process is killed before the Notification is clicked, that dynamically registered Receiver instance will die, too, and the Notification's broadcast won't really do anything.
Depending on the desired behavior, it might be preferable to instead statically register your Receiver class in the manifest, and stay with the explicit Intent. Doing this will allow your app to receive the Notification broadcast even if its process has been killed.
To do that, you'd just need to add a <receiver> element for your NotificationOnClickReceiver in the manifest.
<receiver android:name="NotificationOnClickReceiver" />
Though you can still set an action on that broadcast Intent, you don't need an <intent-filter> for it here, as the explicit Intent is directly targeting the class anyway. If the Receiver is only for that one function, you don't necessarily need the action, and can just remove that altogether.
You can then remove the code you have in step 2, as you'd no longer need the dynamically registered instance.
To send a broadcast use this sendBroadcast(new Intent("NotificationClicked"));
Now to recieve the broadcast, mention this in your manifestunder application tag
<receiver android:name=".NotificationOnClickReceiver" >
<intent-filter>
<action android:name="NotificationClicked" >
</action>
</intent-filter>
</receiver>
Related
This is my requirement.
I have an application which can be force kill by user. I want this application to receive broadcast from other app to execute some task even it is forced kill.
I am trying to make another app with service which will send a broadcast in event 1 mins to my first application.
My first application should receive this broadcast even it is forced kill.
This is what I am trying to do.
in First app:
BroadcastReceiver dummy = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.e("broadcast Received","broadcast Received");
}
};
IntentFilter filter = new IntentFilter("com.action.blockapp");
registerReceiver(dummy,filter);
In my second app.
Intent intent = new Intent("com.action.blockapp");
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
intent.setPackage("com.example.myapplication2");
sendBroadcast(intent);
I am not able to receive the broadcast when my app is forced kill.
Please suggest.
My point . You need to declare revice in the service running in the background. Your specific revice declared in the manifest<receiver android:name=".service.NotifyReceiver" />
</application>
When the service is run. You can get notifications from revice like below
Intent intent1 = new Intent(context, NotifyReceiver.class);
intent1.setAction(action);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent1, PendingIntent.FLAG_UPDATE_CURRENT);
Hope to help you!
You have registered your BroadcastReceiver dynamically, in code. When your app is force stopped, that code is no longer running and your BroadcastReceiver no longer exists. It is no longer registered.
You will need to create a proper class that extends BroadcastReceiver and create a manuifest entry <receiver> for that with an <intent-filter> that matches the broadcast Intent you are broadcasting.
I'm developing an app which needs to run some code (Networking) whenever an SMS is received.
In API 25 and lower it's fine, I register an implicit receiver in Manifest file and start my service in the specified class which extended BroadcastReceiver. In API 26 however you cannot register android.provider.Telephony.SMS_RECEIVED in a receiver since it won't work.
From Android documentation:
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.
I've read several articles like this one on medium. There are solutions like JobScheduler or Explicit Receiver, however the first one is used for changes in network state and I couldn't find a way to trigger the job on SMS_RECEIVED event and the second one is valid until your activity is up and running.
Because of the nature of my application I need to listen for incoming SMS whether the app is running or not. How to do that in API 26+?
Edit
Maybe the code in JobInfoBuilder doc on android website could help. It monitors the changes in the photos on a device and start the job on change. However I cannot find a proper Uri to do the same with the SMS (not even sure if it's possible to monitor SMS via ContentObserver)
Since there are lots of ways to do the job in android O, I post this answer and mention my approach to solve the problem. Obviously by problem I mean the general problem not the SMS_RECEIVED receiver itself.
I start a foreground service and in there I register a dynamic or explicit receiver to listen to the incoming calls (for instance):
In MainActivity.java:
String action = "START"
final Intent intent = new Intent(this, CallMonitorService.class);
intent.setAction(action);
startService(intent);
In CallMonitorService.javas onCreate() method where I have BroadcastReceiver callExplicitReceiver as a field:
final IntentFilter intentFilter = new IntentFilter();
intentFilter.setPriority(2147483647);
intentFilter.addAction("android.intent.action.PHONE_STATE");
this.callExplicitReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
// do the stuff here
}
}
};
registerReceiver(callExplicitReceiver, intentFilter);
and then in onStartCommand():
if (intent.getAction().equals("START")) {
Intent callServiceNotificationIntent = new Intent(this, MainActivity.class);
callServiceNotificationIntent.setFlags(
Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent
.getActivity(this, CALL_SERVICE_REQUEST_CODE,
callServiceNotificationIntent, CALL_SERVICE_FLAG);
Notification notification = new NotificationCompat.Builder(this)
.setContentTitle(CALL_NOTIFICATION_CONTENT_TITLE)
.setTicker(CALL_NOTIFICATION_TICKER)
.setContentText(CALL_NOTIFICATION_CONTENT_TEXT)
.setSmallIcon(R.drawable.ic_info_outline_black_24dp)
.setContentIntent(pendingIntent)
.setOngoing(true)
.build();
startForeground(CALL_NOTIFICATION_ID, notification);
}
and finally:
#Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(callExplicitReceiver);
}
I think of this as a good approach since the user is notified of the running service because of the undismissable notification and that's what android Oreo wants, however through a button in the app user could stop the service and the monitoring receiver as a direct result of destroying service (I cleared that part of code).
I think for now you are safe as SMS_RECEIVED_ACTION is present in the current exempted implicit broadcast list. Also, upon receiving the system broadcast you can either start a foreground service or schedule a job (to perform network operation in your case). Moreover, I am also using the same action and upon testing it seems to work okay.
I am trying to create a notification where I add button to it that would basically do some action. I know I can do the following
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(con)
.setSmallIcon(image)
.setContentTitle("title")
.addAction(icon, title, intent)
My questions are:
1) Is adding button supported in API 5.0+ ONLY or also in 4.x? I read different answers about it
2) The action seems to be associated with opening an activity. Is there away I can have it so when you click on a button it takes an action without having to open the activity (Either through broadcast receiver or some other way)? As far as I know Intent opens activities.
Thank you so much
It will work in Android 4.1 and later. See official doc.
If you want to do action with out any UI update(i.e., showing any activity), I suggest send a pending intent(which will trigger a broadcast receiver) as a parameter for notification action
i) Create a BroadcastReceiver named MyBroadcastReceiver
ii) Add your action in BroadcastReceiver's onReceive method
iii) Create a PendingIntent
Intent mIntent = new Intent(this,MyBroadcastReceiver.class);
PendingIntent mPendingIntent = PendingIntent.getBroadcast(this, 0, mIntent , 0);
iv) Add it to Notification
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(con)
.setSmallIcon(image)
.setContentTitle("title")
.addAction(icon, title, mPendingIntent)
1) Is adding button supported in API 5.0+ ONLY or also in 4.x?
It will work in Android 4.1 and later. See official doc.
2)...As far as I know Intent opens activities.
Yes, you can use BroadcastReceiver or Service for executing logic that doesn't involve UI. First of all, you can build intent to launch activity, broadcast receiver, or service. Secondly, the third argument of NoticiationCompat.Builder#addAction is PendingIntent, not an Intent. You can use PendingIntent.getService to create an PendingIntent for service, for instance.
http://developer.android.com/reference/android/app/PendingIntent.html#getService(android.content.Context, int, android.content.Intent, int)
I need to send broadcast from my one application to another applicaion.. any help!
my application package are 1)com.demo.database and 2)com.demo.list
Intent themesIntent = new Intent(ThemesManager.THEMES_UPDATED);
themesIntent.putExtra("package", packageName);
ctx.sendBroadcast(themesIntent);
not working..
Edits :
<receiver android:name="com.sample.ThemesUpdatedReceiver">
<intent-filter>
<action android:name="com.sample.THEMES_UPDATED"/>
</intent-filter>
</receiver>
#Ajit: Hi, Since Android API 3.0 [API level 11], If an application has never been started even once, then it's BroadcastReceiver can't receive events.As, in your case, your app has no launcher activity, so may be it is the case that causes rejection of event.
Along with that please try using below approach:
You have passed that constant value while creating Intent object. Instead pass it in method intent.setAction();
Hope this helps.
I figured that every sent broadcast is received by all applications except when you setPackage to the sending intent for specific package broadcast.
I am not receiving broadcast because my another app is not launched(that doesn't have launcher activity).
If you're going to broadcast, it generally follows you have a sender and receiver. You've posted what looks like the sender ..
sender (where ever you're sending from):
Intent toret = new Intent();
toret.setAction("com.myapp.foo");
toret.putExtra("bar", "fizzbuzz");
sendBroadcast(toret);
receiver (in eg onResume())
IntentFilter intentFilter = new IntentFilter("com.myapp.foo");
BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// ... do something with the intent
}
// register the receiver
this.registerReceiver(receiver , intentFilter);
Sender always sends, receiver needs to register to listen for the intent.
I'm trying to create a background service that every "X" minutes consult a webservice and if response "ok" generate a Notification on the notification Bar
I'm not sure if is a android service o Broadcast receiver the thing that I need
Thank anyways
Please, don't pull a page from web-service every X minutes -- this drains battery a lot, use Google Cloud Messaging (former C2DM -- Cloud To Device Messaging) instead to get your information updates -- it's very lightweight and very efficient and shares one existing data connection for all applications.
NotificationManager seems to be what you are looking for.
First of all you need a broadcast receiver (inside its own class, plus a bit of code in the manifest) that reacts to the USER_PRESENT action (when user unlocks screen) or the BOOT_COMPLETED (when cellphone finishes loading the OS and all other stuff). Boot activates the Broadcast, the broadcast starts the service. Inside the onStartCommand() method of your service, you run your connection to the webservice every X minutes. Your service should Implement AsyncTask to connect to the Web service. In the onCompleted() method of that task, you call the notifications.
MANIFEST:
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<receiver android:name="classes.myReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<service android:name="classes.myService">
</service>
CLASS:
public class myReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context ctx, Intent intent) {
Intent service = new Intent(ctx, myService.class);
if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)||intent.getAction().equals(Intent.ACTION_USER_PRESENT)||intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
ctx.startService(service);
}
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
ctx.stopService(service);
}
}
}
SAMPLE NOTIFICATION
private void showNotification() {
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationBuilder = new NotificationCompat.Builder(this);
notificationBuilder.setContent(getNotificationContent());
notificationBuilder.setOngoing(true);
notificationBuilder.setTicker("Hello");
notificationBuilder.setSmallIcon(R.drawable.notif_icon);
mNotificationManager.notify(R.id.notification_layout, notificationBuilder.build());
}
private RemoteViews getNotificationContent() {
RemoteViews notificationContent = new RemoteViews(getPackageName(), R.layout.keyphrase_recogniser_notification);
notificationContent.setTextViewText(R.id.notification_title, "title");
notificationContent.setTextViewText(R.id.notification_subtitle, "subtitle");
return notificationContent;
}
This is a broad guide, if you need more specific code let us know.