Supply pending intent to class from notification in Android - android

I am creating an notification by sending GCM message to my app using this code
private static void generateNotification(Context context, int type, String title, String message) {
Intent notificationIntent;
int icon = R.drawable.ic_launcher;
java.util.Random v = new java.util.Random();
int id = v.nextInt(1000);
long when = System.currentTimeMillis();
NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationCompat.Builder notification = new NotificationCompat.Builder(context);
notificationIntent = new Intent(context, Home.class);
notificationIntent.putExtra(CommonUtilities.TITLE_ALERT, title);
notificationIntent.putExtra(CommonUtilities.EXTRA_MESSAGE, message);
notificationIntent.putExtra(CommonUtilities.TYPE, type);
notificationIntent.putExtra(CommonUtilities.ID, id);
// set intent so it does not start a new activity
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent intent = PendingIntent.getActivity(context, type, notificationIntent, PendingIntent.FLAG_ONE_SHOT);
Notification notification_view = notification.setContentTitle(title)
.setContentText(message).setContentIntent(intent)
.setSmallIcon(icon).setWhen(when)
.setVibrate(new long[] { 1000 }).build();
notification_view.flags |= Notification.FLAG_AUTO_CANCEL;
// Play default notification sound
notification_view.defaults |= Notification.DEFAULT_SOUND;
// notification_view.sound = Uri.parse("android.resource://" +
// context.getPackageName() + "your_sound_file_name.mp3");
// Vibrate if vibrate is enabled
notification_view.defaults |= Notification.DEFAULT_VIBRATE;
manager.notify(id, notification_view);
}
and receiving this pending intent using receiver
private final BroadcastReceiver mHandleMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if(!intent.hasExtra(CommonUtilities.TYPE)){
Log.v("msg", "intent vars not received");
return;
}
int type = intent.getExtras().getInt(CommonUtilities.TYPE);
String title = intent.getExtras().getString(CommonUtilities.TITLE_ALERT);
String newMessage = intent.getExtras().getString(CommonUtilities.EXTRA_MESSAGE);
String[] msgArr = newMessage.split(",");
Log.v("message", newMessage);
}
};
But my activity is not performing the action and showing me log. I have registered my receiver with a custom intent using
registerReceiver(mHandleMessageReceiver, new IntentFilter(CommonUtilities.DISPLAY_ACTION));
How can I find the error?
Edit
If application receives a notification while it is on foreground then notifications are received well but if the activity is not running or it is finished and I invoke it on notification click nothing happened

The code you have in generateNotification will only create a notification, not a broadcast.
Your Receiver won't ever receive anything because your'e never broadcasting. To utilize the receiver in the way you're using it you need to write code similar to this
public static final String DISPLAY_ACTION = "package.name.DISPLAY_MESSAGE";
public static final String EXTRA_MESSAGE = "message";
public static void displayMessage(Context context, String message) {
Intent intent = new Intent(DISPLAY_ACTION);
intent.putExtra(EXTRA_MESSAGE, message);
context.sendBroadcast(intent);
}
EDIT
I would add this code above to your CommonUtilities class, you also need to add this line to your generateNotification method
CommonUtilities.displayMessage(context, message);//this will then send your broadcast to the receiver.
EDIT - Show notification message when app is opened
I'm using similar functionality in my app. I saved the notification in a database as unread when it has been received by GCM and then alerted the user, as soon as the app is opened i checked for unread notifications and if found invoked the displayMessage method to show the user the missed notifications. After that I delete the notification from the db.

You wrote:
If application receives a notification while it is on foreground then
notifications are received well but if the activity is not running or
it is finished and I invoke it on notification click nothing happened
If you register your receiver from your activity by calling:
registerReceiver(mHandleMessageReceiver, new IntentFilter(CommonUtilities.DISPLAY_ACTION));
then you have registered the receiver using the context of the activity. That means that when the activity is finished, the registered receiver will be removed and destroyed (to prevent memory leaks).
If you want your receiver to be run even if your app is not running, then you need to register the receiver in the manifest, by adding an appropriate intent filter to your <receiver> definition:
<intent-filter>
<!-- use the correct name string for CommonUtilities.DISPLAY_ACTION) -->
<action android:name="blah.blah.blah.DISPLAY_ACTION"/>
</intent-filter>

Related

Send broadcast on notification click

I have an application which is basically a webview and GCM notifications. I want to achieve the following thing: If the user is in the app and receives a notification, when he clicks the notification I want the webview to load the url provided in the notification.
I'm trying to accomplish this by using broadcast receiver but it doesn't work.
I dynamically register the receiver in the MainActivity:
private void registerNotificationReceiver() {
final IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_LOAD_URL_FROM_NOTIFICATION);
Log.i(TAG, "registerNotificationReceiver()");
this.receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "notification received");
}
};
super.registerReceiver(this.receiver, filter);
}
And in the GCM Listener I'm using PendingIntent.getBroadast():
final Intent broadcastIntent = new Intent(MainActivity.ACTION_LOAD_URL_FROM_NOTIFICATION);
PendingIntent intent = PendingIntent.getBroadcast(getApplicationContext(), 0, broadcastIntent, PendingIntent.FLAG_UPDATE_CURRENT);
notificationBuilder.setContentIntent(intent);
notification = notificationBuilder.build();
notification.flags |= Notification.FLAG_AUTO_CANCEL;
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(1, notification);
I don't understand why onReceive in the MainActivity class is not called. The message "notification received" is not displayed.
Can you help me? Thank you :)
I cannot find right now the reason but there's a security reason. Latest Android versions won't allow you to trigger a listener from "kind-of" remote process without it being explicit.
The intent you broadcast MUST be explicit for it to work. Explicit means that you have to explicitly call the component that will handle the intent (the receiver). So this receiver must be declared in its own class and in the manifest as a <receiver>.
Follow this guy's example in the section Explicit Broadcast Intents http://codetheory.in/android-broadcast-receivers/
and thy will be done.

Handle GCM notification Android

I am developing an app wich receives GCM notifications to alert the user about promotions and stuff like that.
So far i have managed to send and receive notifications. Here is my code:
public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
ComponentName comp = new ComponentName(context.getPackageName(), GCMNotificationIntentService.class.getName());
startWakefulService(context, (intent.setComponent(comp)));
setResultCode(Activity.RESULT_OK);
}
}
public class GCMNotificationIntentService extends IntentService {
public static final int notifyID = 1337;
NotificationCompat.Builder builder;
public GCMNotificationIntentService() {
super("GcmIntentService");
}
#Override
protected void onHandleIntent(Intent intent) {
Bundle extras = intent.getExtras();
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
String messageType = gcm.getMessageType(intent);
if (!extras.isEmpty()) {
sendNotification(extras.getString("type"),extras.getString("msg"));
}
GcmBroadcastReceiver.completeWakefulIntent(intent);
}
private void sendNotification(String type, String msg) {
Intent resultIntent = new Intent(this, SplashActivity.class);
resultIntent.putExtra("type", type);
resultIntent.putExtra("msg", msg);
PendingIntent resultPendingIntent = PendingIntent.getActivity(this, 0,resultIntent, PendingIntent.FLAG_ONE_SHOT);
NotificationCompat.Builder mNotifyBuilder;
NotificationManager mNotificationManager;
mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotifyBuilder = new NotificationCompat.Builder(this)
.setContentTitle("x")
.setContentText(msg)
.setSmallIcon(R.drawable.ic_launcher);
mNotifyBuilder.setContentIntent(resultPendingIntent);
int defaults = 0;
defaults = defaults | Notification.DEFAULT_LIGHTS;
defaults = defaults | Notification.DEFAULT_VIBRATE;
defaults = defaults | Notification.DEFAULT_SOUND;
mNotifyBuilder.setDefaults(defaults);
mNotifyBuilder.setAutoCancel(true);
mNotificationManager.notify(notifyID, mNotifyBuilder.build());
}
}
The problem is that i don't know how (or where) to show a message alert.
Searching on the web, i found an implementation where the message was shown even when the app was closed, but i only need to show the message on the app, for example: when the app is open or when the app is closed and the user opens it.
The Android notification framework is designed to show notifications irrespective of whether or not your app is open. Notifications are shown in the notification bar on the top and do not show within your activity screen.
If you do not want to show notifications when the app is not running, you can do something like have a variable isRunning and set it to true in onResume() of an activity and false in onPause() of an activity. This way, you now have a reference to find out if the app is running or not. If isRunning is false, then you can save the notifications that you are receiving in the background into a SharedPreferences or database - you will do this without using the Notification framework. If the app is open, then you can show a message alert - either using the Notification framework if that is what you intend to do or use an AlertDialog.

Sync Activity with broadCast Receiver issue

I wanna sync my Activity with Google cloud Messaging.
When GCM message Receives Its own receiver get the message and create notification and then broadcast my custom message to activity receiver.
In other hand my Activity has own dynamically registered BroadcastReceiver that Receives my cusom messsages.
now this is a situation:
when app is open, without clicking on notification, my activity
receiver receives the message and shows.
but when activity is closed after clicking on notification noting
receives and app just opens.
I tried may ways like:
register a class BroadCast receiver On maifest. but I cannot sync it with my activity. cause I found that outer Receiver can sysnc with activity just with putextra and then my activity should close and then open again to can get extras!
try to broadcast my custom message again on creates notification, but it seems wont work cause I need to broad cast on NotificationClick not onCreate notification.
finnaly I tried to Register this internal reciver dynamically on another part of but It cannot reachable.
so if you get my problem what is the best way of solving?
this is my in activity receiver:
private final BroadcastReceiver mHandleMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.i("LOG", "unreciver");
String newMessage = intent.getExtras().getString(EXTRA_MESSAGE);
// Waking up mobile if it is sleeping
WakeLocker.acquire(getApplicationContext());
/**
* Take appropriate action on this message
* depending upon your app requirement
* For now i am just displaying it on the screen
* */
//Showing received message
//lblMessage.append(newMessage + "\n");
Log.i("LOG", "unreciver messsage:"+newMessage);
//Toast.makeText(getApplicationContext(), "New Message: " + newMessage, Toast.LENGTH_LONG).show();
loadReciverDialog(newMessage);
// Releasing wake lock
WakeLocker.release();
}
};
this is the part of service that receive message from GCM and Create notification:
#Override
protected void onMessage(Context context, Intent intent) {
Log.i(TAG, "Received message");
String message = intent.getExtras().getString("price");
Log.i("LOG", "GCM service Message "+message);
displayMessage(context, message);
// notifies user
generateNotification(context, message);
}
private static void generateNotification(Context context, String message) {
Log.i("LOG", "genetaret notify");
int icon = R.drawable.ic_launcher;
long when = System.currentTimeMillis();
NotificationManager notificationManager = (NotificationManager)
context.getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new Notification(icon, message, when);
String title = context.getString(R.string.app_name);
Intent notificationIntent = new Intent(context, MainActivity.class);
// set intent so it does not start a new activity
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP |
Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent intent =
PendingIntent.getActivity(context, 0, notificationIntent, 0);
notification.setLatestEventInfo(context, title, message, intent);
notification.flags |= Notification.FLAG_AUTO_CANCEL;
// Play default notification sound
notification.defaults |= Notification.DEFAULT_SOUND;
//notification.sound = Uri.parse("android.resource://" + context.getPackageName() + "your_sound_file_name.mp3");
// Vibrate if vibrate is enabled
notification.defaults |= Notification.DEFAULT_VIBRATE;
notificationManager.notify(0, notification);
}
}
and this part display message:
static void displayMessage(Context context, String message) {
Intent intent = new Intent(DISPLAY_MESSAGE_ACTION);
intent.putExtra(EXTRA_MESSAGE, message);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
Log.i("LOG", "commonutils msg="+message);
context.sendBroadcast(intent);
}
I finally solve this problem in this way:
I kept the in-Activity Broadcast Receiver and made a function for checking if Extras exist my codes under OnReceive functions works.
after create notification put message to extra for Main Activity to get them
so my app get message in two way:
when app is opens message will gave with receiver
when app is closed message will gave to app by extra
but I wanna know if there is a better way to work with one Receiver.

GCM: messages by IntentService.sentBroadcast are not received if application is not visible

I'm trying to implement a GCM client & server architecture. Everything works fine so far.
Except: When my activity is closed and I get a new notification by GCM, the notification is displayed in the notification bar. So far, so good. But when I click on the notification, my activity is opened but the onReceive event of my BroadcastReceiver is not triggered. :(
If the Activity is open, the onReceive is triggered perfectly.
Do you know, what's wrong here?
Cheers
Chris
So this is my service:
package xy;
import ...;
public class GcmIntentService extends IntentService
{
private NotificationManager mNotificationManager;
NotificationCompat.Builder builder;
public GcmIntentService()
{
super("GcmIntentService");
}
#Override
protected void onHandleIntent(Intent intent)
{
Bundle extras = intent.getExtras();
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
String messageType = gcm.getMessageType(intent);
if (!extras.isEmpty()) { // has effect of unparcelling Bundle
final int notificationID = (int) (Math.random() * 100000000);
if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR.equals(messageType)) {
sendNotification("GCM notification: Send error", extras.toString(), notificationID);
} else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED.equals(messageType)) {
sendNotification("Deleted messages on server", extras.toString(), notificationID);
// If it's a regular GCM message, do some work.
} else if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType)) {
sendNotification(extras.getString(Utils.TICKER_TITLE_MESSAGE_KEY), extras
.getString(Utils.TICKER_TEXT_MESSAGE_KEY), notificationID);
Intent intentToBroadCast = new Intent(Utils.DISPLAY_MESSAGE_ACTION);
intentToBroadCast.putExtra(Utils.MESSAGE_EXTRA_BUNDLE_KEY, extras);
intentToBroadCast.putExtra(Utils.NOTIFICATION_ID_KEY, notificationID);
sendBroadcast(intentToBroadCast);
}
}
// Release the wake lock provided by the WakefulBroadcastReceiver.
GcmBroadcastReceiver.completeWakefulIntent(intent);
}
private void sendNotification(final String aTitle, final String aText, final int aNotificationID)
{
mNotificationManager = (NotificationManager) this
.getSystemService(Context.NOTIFICATION_SERVICE);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this,
DemoActivity.class), 0);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this).setSmallIcon(
R.drawable.ic_stat_gcm).setContentTitle(aTitle).setStyle(
new NotificationCompat.BigTextStyle().bigText(aText)).setContentText(aText);
mBuilder.setContentIntent(contentIntent);
mNotificationManager.notify(aNotificationID, mBuilder.build());
}
}
And here's the Receiver in my activity, which is to display the incoming message:
public class GcmResultReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
Bundle extras = intent.getBundleExtra(Utils.MESSAGE_EXTRA_BUNDLE_KEY);
String s = extras.getString(Utils.CONTENT_TITLE_MESSAGE_KEY) + "\n"
+ extras.getString(Utils.CONTENT_TEXT_MESSAGE_KEY);
mDisplay.setText(s);
int notificationID = intent.getIntExtra(Utils.NOTIFICATION_ID_KEY, -1);
if (-1 != notificationID) m_SentNotificationIDs.add(notificationID);
if (m_IsVisible) {
clearNotifications();
}
}
};
Everything was copied and adapted from the GCM example from the Google Android tutorial.
The BroadcastReceiver is triggered before the notification is displayed in the notification bar. It contains the code that displays the notification and opens the activity when it is tapped (unless it is starting an intent service that does that work).
Therefore, if you see the notification, it means the BroadcastReceiver was triggered.
You don't need an additional BroadcastReceiver for passing the notification data from the first receiver to your app. If you wish to pass the notification data to the Activity that is being launched when the notification is tapped, you can pass it to the intent used to launch that activity.
Suppose you change your sendNotification call to:
sendNotification(extras, notificationID);
Then you can implement it like this:
private void sendNotification(Bundle extras, final int aNotificationID)
{
mNotificationManager = (NotificationManager) this
.getSystemService(Context.NOTIFICATION_SERVICE);
Intent demoIntent = new Intent(this, DemoActivity.class);
demoIntent.putExtras (extras);
demoIntent.putExtra (Utils.NOTIFICATION_ID_KEY, notificationID);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, demoIntent, 0);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this).setSmallIcon(
R.drawable.ic_stat_gcm).setContentTitle(extras.getString(Utils.TICKER_TITLE_MESSAGE_KEY)).setStyle(
new NotificationCompat.BigTextStyle().bigText(extras.getString(Utils.TICKER_TEXT_MESSAGE_KEY))).setContentText(extras.getString(Utils.TICKER_TEXT_MESSAGE_KEY));
mBuilder.setContentIntent(contentIntent);
mNotificationManager.notify(aNotificationID, mBuilder.build());
}
This way your DemoActivity will get the notification id and all the extras holding the data of the notification.
You can access them in your activity's onCreate (or perhaps it would be better to do it in onResume, in case your Activity is already started).

How to detect if a notification has been dismissed?

Is there any way in Android to detect when a user swipes a notification to the left and deletes it? I'm using an alarmmanager to set a repeating alert and I need my repeating alert to stop when the notification is cancelled by the user. Here's my code:
Setting the repeating alert:
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, c.getTimeInMillis(), repeatFrequency, displayIntent);
My notification code:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Get the notification ID.
int notifID = getIntent().getExtras().getInt("Reminder_Primary_Key");
//Get the name of the reminder.
String reminderName = getIntent().getExtras().getString("Reminder_Name");
//PendingIntent stores the Activity that should be launched when the user taps the notification.
Intent i = new Intent(this, ViewLocalRemindersDetail.class);
i.putExtra("NotifID", notifID);
i.putExtra("notification_tap", true);
//Add FLAG_ACTIVITY_NEW_TASK to stop the intent from being launched when the notification is triggered.
PendingIntent displayIntent = PendingIntent.getActivity(this, notifID, i, Intent.FLAG_ACTIVITY_NEW_TASK);
NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
Notification notif = new Notification(R.drawable.flag_red_large, reminderName, System.currentTimeMillis());
CharSequence from = "Here's your reminder:";
CharSequence message = reminderName;
notif.setLatestEventInfo(this, from, message, displayIntent);
//Pause for 100ms, vibrate for 250ms, pause for 100ms, and vibrate for 500ms.
notif.defaults |= Notification.DEFAULT_SOUND;
notif.vibrate = new long[] { 100, 250, 100, 500 };
nm.notify(notifID, notif);
//Destroy the activity/notification.
finish();
}
I know I need to call alarmManager.cancel(displayIntent) in order to cancel my repeating alarm. However, I don't understand where to put this code. I need to cancel the repeating alert ONLY when the user has tapped on the notification or dismissed it. Thanks for your help!
I believe that Notification.deleteIntent is what you are looking for. The doc says:
The intent to execute when the notification is explicitly dismissed by the user, either with the "Clear All" button or by swiping it away individually. This probably shouldn't be launching an activity since several of those will be sent at the same time.
To all those future people out there -- you can register a broadcast receiver to listen for notification delete inents.
Create a new broadcast receiver:
public class NotificationBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action == null || !action.equals(Config.NotificationDeleteAction)) {
return;
}
// Do some sweet stuff
int x = 1;
}
}
Register the broadcast receiver within your application class:
"If your app targets API level 26 or higher, you cannot use the manifest to declare a receiver for most implicit broadcasts (broadcasts that do not target your app specifically)."
Android Documentation.
registerReceiver(
new NotificationBroadcastReceiver(),
new IntentFilter(Config.NotificationDeleteAction)
);
You probably noticed the static variable Config.NotificationDeleteAction. This is a unique string identifier for your notification. It typically follows the following {namespace}{actionName} convention:
you.application.namespace.NOTIFICATION_DELETE
Set the delete intent on your notification builder:
notificationBuilder
...
.setDeleteIntent(createDeleteIntent())
...
Where, createDeleteIntent is the following method:
private PendingIntent createDeleteIntent() {
Intent intent = new Intent();
intent.setAction(Config.NotificationDeleteAction);
return PendingIntent.getBroadcast(
context,
0,
intent,
PendingIntent.FLAG_ONE_SHOT
);
}
Your registered broadcast receiver should receive the intent when your notification is dismissed.
You can also use an Activity PendingIntent, which may be simpler to implement if you have an Activity that can handle the dismissal, because you don't have to create and configure a broadcast receiver.
public static final String DELETE_TAG = "DELETE_TAG";
private PendingIntent createDeleteIntent(Context context) {
Intent intent = new Intent(context, MyActivity.class);
intent.putExtra(DELETE_TAG, true);
return PendingIntent.getActivity(
context,
0,
intent,
PendingIntent.FLAG_ONE_SHOT
);
}
MyActivity would receive the intent in its onCreate(), and in this example, could look for the DELETE_TAG extra to recognize it.

Categories

Resources