Activity does not get correct bundle - android

I am working with GCM, and this is my onMessage function:
#Override
protected void onMessage(Context context, Intent intent) {
if (intent != null && intent.getExtras() != null) {
try {
String message = intent.getExtras().getString("message");
String userId = intent.getExtras().getString("user_id");
Log.i("","postda user id is:" + userId);
Log.i("","will enter here FRIENDS: ");
generateNotification(context, message, userId);
} catch (Exception e) {
Utils.appendLog("onMessage errror : " + e.getMessage());
Log.i(TAG, e.getMessage(), e);
}
}
}
This is my CreateNotification function:
private static void generateNotification(Context context, String message, String userID) {
Log.i("", "postda user message " + message + ".... userid: " + userID);
String title = context.getString(R.string.passenger_name);
Intent notificationIntent = new Intent(context, PSProfileActivity.class);
notificationIntent.putExtra("id", userID);
Log.i("", "postda ---------- userid: "+ userID);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP| Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent intent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
Log.i("", "postda message: " + message + "....userID " + userID );
PSLocationCenter.getInstance().pref.setDataChanged(context, true);
PSLocationCenter.getInstance().pref.setDataChangedProfile(context, true);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context);
mBuilder.setContentTitle(title).setContentText(message).setSmallIcon(R.drawable.notification_icon);
mBuilder.setContentIntent(intent);
Notification notification = mBuilder.build();
notification.flags |= Notification.FLAG_AUTO_CANCEL;
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(1, notification);
playTone(context);
}
And this is the PSProfileActivity onCreate function:
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_profile);
ButterKnife.inject(this);
mHeader = new ProfileHeader(this, backFromHeader);
mData = new ProfileData(this);
mButtons = new ProfileViewPagerButtons(PSProfileActivity.this, firstPage);
Bundle bundle = getIntent().getExtras();
if(bundle != null) id = bundle.getString("id");
Log.i("", "postda in profile id is:" + id);
if(!id.contentEquals(String.valueOf(PSLocationCenter.getInstance().pref.getUserId(PSProfileActivity.this)))){
findViewById(R.id.action_settings).setVisibility(View.INVISIBLE);
}
Log.i("", "postda in profile id is 2:" + id);
}
And this is my Logcat response:
04-17 15:33:53.650 9699-11695/nl.hgrams.passenger I/﹕ postda user id is:23
04-17 15:33:53.651 9699-11695/nl.hgrams.passenger I/﹕ postda user message alin reddd accepted your friend request..... userid: 23
04-17 15:33:53.651 9699-11695/nl.hgrams.passenger I/﹕ postda ---------- userid: 23
04-17 15:33:53.652 9699-11695/nl.hgrams.passenger I/﹕ postda message: alin reddd accepted your friend request.....userID 23
04-17 15:33:58.812 9699-9699/nl.hgrams.passenger I/﹕ postda in profile id is:28
04-17 15:33:58.814 9699-9699/nl.hgrams.passenger I/﹕ postda in profile id is 2:28
As you can see, I'm sending via the bundle an ID, but the one that I get on the other page, is a totally different id (it's actually the last ID that should have been gotten here). This is really weird, does anyone know why this is happening?

Use unique identitier in the PendingIntent:
int iUniqueId = (int) (System.currentTimeMillis() & 0xfffffff);
PendingIntent.getActivity(context, iUniqueId, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);

You are generating intent with the same id always. You need to pass the unique identifier as the second parameter and also need to add the Flag FLAG_UPDATE_CURRENT so that the extras get updated and you always get the latest extras that you passed .
So you have to generate intent like this :
PendingIntent intent = PendingIntent.getActivity(context, identifier , notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT );
identifier can be anything unique like auto increment variable or current timestamp

The problem may be that you are only using extras to modify the PendingIntent. Try embedding the id in the data field of notificationIntent instead.
From http://developer.android.com/reference/android/app/PendingIntent.html
A common mistake people make is to create multiple PendingIntent objects with Intents that only vary in their "extra" contents, expecting to get a different PendingIntent each time. This does not happen. The parts of the Intent that are used for matching are the same ones defined by Intent.filterEquals. If you use two Intent objects that are equivalent as per Intent.filterEquals, then you will get the same PendingIntent for both of them.

I think you have to use this flag, FLAG_UPDATE_CURRENT.
Like this:
PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
This would refresh the old intents with the new extras that you are passing via bundle and get correct data that matches the ID.

Related

Second button from notification, the bundle I receive in IntentService contains the extras from the first button

So this is the code I use for my intents:
String tag = "#business"; String secondTag = "#personal";
Intent action1Intent = new Intent(context, NotificationActionService.class)
.setAction("tag").putExtra("id", psTrip.getId()).putExtra("tag", tag);
PendingIntent action1PendingIntent = PendingIntent.getService(context, 0,
action1Intent, PendingIntent.FLAG_ONE_SHOT);
Intent action2Intent = new Intent(context, NotificationActionService.class)
.setAction("tag").putExtra("id", psTrip.getId()).putExtra("tag", secondTag);
PendingIntent action2PendingIntent = PendingIntent.getService(context, 0,
action2Intent, PendingIntent.FLAG_ONE_SHOT);
This is how I create the actions:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
RemoteInput remoteInput = new RemoteInput.Builder("Business")
.setLabel("Business")
.build();
Notification.Action action =
new Notification.Action.Builder(R.drawable.btn_tag_trip,
tag, action1PendingIntent)
.addRemoteInput(remoteInput)
.build();
RemoteInput remoteInput2 = new RemoteInput.Builder("Personal")
.setLabel("Personal")
.build();
Notification.Action action2 =
new Notification.Action.Builder(R.drawable.btn_tag_trip,
secondTag, action2PendingIntent)
.addRemoteInput(remoteInput2)
.build();
noti = new Notification.Builder(context)
.setContentTitle(context.getString(R.string.passenger_name))
.setContentText(content).setSmallIcon(R.drawable.notification_icon)
.setContentIntent(pIntent)
.addAction(action)
.addAction(action2).build();
}
Action2 calls action2PendingIntent and action calls action1PendingIntent.
But in my intentService. I have this in my onHandleIntent:
final NotificationManager notifManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notifManager.cancelAll();
String action = intent.getAction();
Log.i("", "Received notification action: " + action);
Bundle bundle = intent.getExtras();
if (bundle != null) {
final String id = bundle.getString("id");
final String tag = bundle.getString("tag");
Log.i("", "Received notification action: id: " + id + " / tag: " + tag);
}
BUT the bundle.getString("tag"); will always return "#business" (the tag of the first action, even if I press the second button.
Why is this happening?
Use the PendingIntent.FLAG_UPDATE_CURRENT above mentioned flags helps in updating pending intent for the activity.
Thanks to #pskink I did manage to make it work, by changing the request code for the second pending intent, like this:
PendingIntent action2PendingIntent = PendingIntent.getService(context, 2,
action2Intent, PendingIntent.FLAG_ONE_SHOT);

Push notifications not opening correct screens

I have an app where I get GCM push notifications in a GcmListenerService(as given in the gcm android sample). Whenever I get the notification, I get some JSON with data related to showing the notification.
Now suppose I get a notification that "someone bookmarked me", for that I get the pk(identifier) of that user and when I click on the notification, it uses the pk received in the push notification to display that user's profile.
The issue : If I get 2 notifications of above mentioned kind, then no matter which notification I click, I always go the profile of the person whose notification I received most recently.
Does getting a notification on top of other, overrides the values of the previous notifications so that only the most recent one is valid? Does that mean I can show only one push notification from an app? I can post the code if that is needed.
Relevant code:
#Override
public void onMessageReceived(String from, Bundle data) {
tinyDB = new TinyDB(this);
if (tinyDB.getBoolean(AppConstants.LOGIN_STATE, false)) {
try {
Log.i("NOTIF", data.toString());
String screen = data.getString("screen");
String dataJson = data.getString("data");
String displayJson = data.getString("display");
String notification_id = data.getString("notif_id");
String priority = data.getString("priority");
String style = data.getString("style");
Gson gson = new GsonBuilder().disableHtmlEscaping().create();
NotificationVal notificationVal = gson.fromJson(displayJson, NotificationVal.class);
String title = notificationVal.getTitle();
String text = notificationVal.getText();
String largeText = notificationVal.getLargeText();
String smallIcon = notificationVal.getSmallIcon();
String largeIcon = notificationVal.getLargeIcon();
Bitmap smallImage = null;
Bitmap largeImage = null;
if (!TextUtils.isEmpty(smallIcon)) {
smallImage = getBitmapFromURL(smallIcon);
}
if ("big_picture".equalsIgnoreCase(style) && (largeImage != null)) {
NotificationCompat.BigPictureStyle notificationStyle = new NotificationCompat.BigPictureStyle();
notificationStyle.setBigContentTitle(title);
notificationStyle.setSummaryText(text);
notificationStyle.bigPicture(largeImage);
Intent intent = NotificationIntentBuilder.get(this, dataJson, screen, smallIcon, largeIcon, notification_id);
TaskStackBuilder stackBuilder = NotificationStackBuilder.get(this, screen, dataJson);
stackBuilder.addNextIntent(intent);
PendingIntent resultPendingIntent =
stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this);
mBuilder.setSmallIcon(R.drawable.white_square);
mBuilder.setAutoCancel(true);
mBuilder.setColor(Color.parseColor("#fac80a"));
mBuilder.setLargeIcon(largeImage);
mBuilder.setContentTitle(title);
mBuilder.setContentText(text);
mBuilder.setContentIntent(resultPendingIntent);
mBuilder.setDefaults(NotificationCompat.DEFAULT_VIBRATE);
mBuilder.setDefaults(NotificationCompat.DEFAULT_SOUND);
mBuilder.setPriority(NotificationCompat.PRIORITY_HIGH);
mBuilder.setStyle(notificationStyle);
mBuilder.setContentIntent(resultPendingIntent);
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (notification_id != null) {
mNotificationManager.cancel(Integer.parseInt(notification_id));
mNotificationManager.notify(Integer.parseInt(notification_id), mBuilder.build());
}
} else {
Log.i("GCM", "Dummy Notification");
}
} catch (Exception e) {
Log.i("NOTIF", "An exception occurred");
}
}
}
Other internal codes:
public class NotificationStackBuilder {
public static TaskStackBuilder get(Context context, String screen, String data) {
if ("IMAGE".equalsIgnoreCase(screen)) {
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
stackBuilder.addParentStack(ImageActivity.class);
return stackBuilder;
} else {
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
stackBuilder.addParentStack(NewHomeActivity.class);
return stackBuilder;
}
}
}
public class NotificationIntentBuilder {
public static Intent get(Context context, String data, String screen, String smallIcon, String largeIcon, String notificationId) {
if ("IMAGE".equalsIgnoreCase(screen)) {
String pk = "";
JSONObject jsonObject = null;
try {
jsonObject = new JSONObject(data);
if (jsonObject.has("pk")) {
pk = jsonObject.getString("pk");
}
} catch (JSONException e) {
e.printStackTrace();
}
Intent intent = new Intent(context, ImageActivity.class);
intent.putExtra("ID", pk);
intent.putExtra("notificationId", notificationId);
return intent;
} else if ("GALLERY".equalsIgnoreCase(screen)) {
String pk = "";
JSONObject jsonObject = null;
try {
jsonObject = new JSONObject(data);
if (jsonObject.has("pk")) {
pk = jsonObject.getString("pk");
}
} catch (JSONException e) {
e.printStackTrace();
}
Intent intent = new Intent(context, GalleryActivity.class);
intent.putExtra("ID", pk);
intent.putExtra("notificationId", notificationId);
return intent;
} else {
return new Intent(context, NewHomeActivity.class);
}
}
}
Edit This issue is not happening with two notifications of different type(opening different activities), it is only happening with notifications opening the same screen.
Edit 1 Here is the value received in the push notification:
Bundle[{google.sent_time=1469254984538, priority=0, screen=IMAGE, data={"pk":650}, style=big_picture, google.message_id=0:1469254984541527%e07f0e28f9fd7ecd, notif_id=4267, display={"large_icon":"https:\/\/d2r0rrogy5uf19.cloudfront.net\/photos\/971c03f8-6a5d-30a3-9e49-0ab416cb8fa0.jpg","small_icon":"","text":"Random hi5'd your photo to 'Diwali'","title":"random","large_text":""}, collapse_key=do_not_collapse}]
This one has notificationId as 4267, now suppose I get another notification for same screen, with notificationId say, 4268, then when I log the notificationId received in the Image screen, I get 4268 on opening both the notifications.
Edit 2 I guess the issue is related to PendingIntent.FLAG_UPDATE_CURRENT. Here is what is written in the documentation:
Flag indicating that if the described PendingIntent already exists, then keep it but replace its extra data with what is in this new Intent.
This is what was happening. The contents of intent extras were getting over-written by the latest notification's intent extras. So, I tried using FLAG_ONE_SHOT, but with that I am able to open the old intent but noting opens when I click the latest intent.
I want both notifications to be on the push notification list and that both of them should the respective screens with different values of intent extras.
You need to have unique request code for each notification or else it will be replaced with new one.
An excerpt from PendingIntent documentation :
The last intent in the array represents the key for the PendingIntent.
In other words, it is the significant element for matching (as done
with the single intent given to getActivity(Context, int, Intent,
int), its content will be the subject of replacement by send(Context,
int, Intent) and FLAG_UPDATE_CURRENT, etc. This is because it is the
most specific of the supplied intents, and the UI the user actually
sees when the intents are started.
So replace the below line:
PendingIntent resultPendingIntent = stackBuilder. getPendingIntent(0,
PendingIntent.FLAG_UPDATE_CURRENT);
Assuming notification_id is unique integer, just replace it like below:
PendingIntent resultPendingIntent =
stackBuilder.getPendingIntent(Integer.parseInt(notification_id)
, PendingIntent.FLAG_UPDATE_CURRENT);

Android: Transferring Data via ContentIntent

I've got a problem with my Android Application. It receives Messages via Google Cloud Messaging and displays a Notification in the Notificationbar. I want to transfer some Data with the Notification. This Data comes via Google Cloud Messaging and should be attached to the Notification.
This is my Code to Display the Notification:
private void setNotification(String strTitle, String strMessage, int intPageId, int intCategorieId)
{
notificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
Intent intentOpen = new Intent(this, NotificationClick.class);
intentOpen.putExtra("pageId", Integer.toString(intPageId));
intentOpen.putExtra("categorieId", Integer.toString(intCategorieId));
intentOpen.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intentOpen, 0);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.launcher_icon)
.setTicker(strTitle)
.setContentTitle(strTitle)
.setStyle(new NotificationCompat.BigTextStyle().bigText(strMessage))
.setContentText(strMessage);
notificationBuilder.setContentIntent(contentIntent);
notificationBuilder.setDefaults(Notification.DEFAULT_ALL);
notificationManager.notify(intCategorieId, notificationBuilder.build());
}
And my Code to get the Variables "intPageId" and "intCategorieId" in a other Activity(witch opens by clicking the Notification) back, is this:
Bundle intentExtras = new Bundle();
intentExtras = getIntent().getExtras();
Toast.makeText(this, "Page To Open: " + intentExtras.getString("pageId"), Toast.LENGTH_LONG).show();
Toast.makeText(this, "Page To Open: " + intentExtras.getString("kategorieId"), Toast.LENGTH_LONG).show();
But in both "Toast" Messages appears "null", or the value that was passed through at the first time, clicking on the Message.
For Example:
At the First time I send: intPageId=1.
The Toast says: "Page To Open: 1".
At the Second time I send: intPageId=2.
The Toast says: "Page To Open: 1".
I'm totally confused.
First Method :
Instead of below line :
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intentOpen, 0);
change it to this :
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intentOpen, PendingIntent.FLAG_UPDATE_CURRENT);
Second Method :
int iUniqueId = (int) (System.currentTimeMillis() & 0xfffffff);
PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(),iUniqueId, intentForNotification, 0);

Android notifications error

Im coding an android app for about 4 months now and im currently getting an error on system notifications.
The problem is that im adding proximity alerts from varius interest points, when it aproaches a specific point, it sends a system notification. But now, when im near of more than one point, it sends the correct amount of notifications but they are all the same, woth same title and text, and im passing different information on the intent.
My code is:
MainActivity:
private void addProximityAlert(double latitude, double longitude, String type, int id, String object) {
Intent intent = new Intent(PROX_ALERT_INTENT);
intent.putExtra("type", type);
intent.putExtra("id", id);
intent.putExtra("object", object);
PendingIntent proximityIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
locationManager.addProximityAlert(
latitude, // the latitude of the central point of the alert region
longitude, // the longitude of the central point of the alert region
POINT_RADIUS, // the radius of the central point of the alert region, in meters
PROX_ALERT_EXPIRATION, // time for this proximity alert, in milliseconds, or -1 to indicate no expiration
proximityIntent // will be used to generate an Intent to fire when entry to or exit from the alert region is detected
);
IntentFilter filter = new IntentFilter(PROX_ALERT_INTENT);
registerReceiver(new ProximityReceiver(), filter);
}
Proximity Receiver:
public class ProximityReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
String key = LocationManager.KEY_PROXIMITY_ENTERING;
Boolean entering = intent.getBooleanExtra(key, false);
int id = intent.getIntExtra("id", 0);
String type = intent.getStringExtra("type");
String name = intent.getStringExtra("object");
Log.d("NOTIFICATION", "NOME: " + name);
Log.d("NOTIFICATION", "ID: " + id);
Log.d("NOTIFICATION", "TYPE:" + type);
if (entering) {
Log.d(getClass().getSimpleName(), "entering");
}else {
Log.d(getClass().getSimpleName(), "exiting");
}
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
Intent notificationIntent = new Intent(context, InterestPoint_Description.class);
notificationIntent.putExtra("id", id);
notificationIntent.putExtra("type", type);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Notification notification = createNotification();
notification.setLatestEventInfo(context, "LisbonRoutes", "You are near " + name + ", touch here to check it out!", pendingIntent);
notificationManager.notify(Config.NOTIFICATION_ID, notification);
Config.NOTIFICATION_ID++;
}
private Notification createNotification() {
Notification notification = new Notification();
notification.icon = R.drawable.icon;
notification.when = System.currentTimeMillis();
notification.flags |= Notification.FLAG_AUTO_CANCEL;
notification.flags |= Notification.FLAG_SHOW_LIGHTS;
notification.defaults |= Notification.DEFAULT_VIBRATE;
notification.defaults |= Notification.DEFAULT_LIGHTS;
notification.ledARGB = Color.WHITE;
notification.ledOnMS = 1500;
notification.ledOffMS = 1500;
return notification;
}
}
I hope i've explained it well :S
Thanks in advance
Your pending intents are overwriting one another because extras do not make them unique.
See http://developer.android.com/reference/android/app/PendingIntent.html
it is important to know when two Intents are considered to be the same for purposes of retrieving a PendingIntent. A common mistake people make is to create multiple PendingIntent objects with Intents that only vary in their "extra" contents, expecting to get a different PendingIntent each time. This does not happen.
Best way to fix this is to set the request code, probably to id
PendingIntent proximityIntent = PendingIntent.getBroadcast(context, id, intent, 0);

Return json object when notification is clicked

I'm building an android app which supports push notifications using phonegap/cordova and this plugin. The plugin has an onMessage() method which is triggered whenever a push notification is received, this method returns a json object to my javascript plugin. However I want this method to return the json only when the notification on status bar is clicked.
This is my onMessage() method:
protected void onMessage(Context context, Intent intent) {
String message = "", title = "", type = "";
int msgctn = 0, schoolid = 0, studentid = 0, contentid = 0;
// Extract the payload from the message
Bundle extras = intent.getExtras();
if (extras != null) {
try
{
message = extras.getString("message");
title = extras.getString("title");
type = extras.getString("type");
msgctn = Integer.parseInt(extras.getString("msgctn"));
schoolid = Integer.parseInt(extras.getString("schoolid"));
studentid = Integer.parseInt(extras.getString("studentid"));
contentid = Integer.parseInt(extras.getString("contentid"));
JSONObject json;
json = new JSONObject().put("event", "message");
json.put("message", message);
json.put("type", type);
json.put("contentid", contentid);
json.put("schoolid", schoolid);
json.put("studentid", studentid);
GCMPlugin.sendJavascript( json );
// Send the MESSAGE to the Javascript application
}
catch( JSONException e)
{
Log.e(ME + ":onMessage", "JSON exception");
}
Intent notificationIntent = new Intent(context, App4.class);
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
.setContentText(message)
.setContentTitle(title)
.setSmallIcon(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB ? R.drawable.icon : android.R.drawable.ic_dialog_info)
.setAutoCancel(true)
.setContentIntent(contentIntent)
.setWhen(System.currentTimeMillis())
//.setDefaults(Notification.DEFAULT_ALL)
.setLights(-16711681, 2000, 1000)
.setNumber(msgctn)
.setSound(Uri.parse("android.resource://"+ getPackageName() + "/" + R.raw.notifsound));
Notification notification = builder.build();
NotificationManager notificationManager = getNotificationManager(context);
notificationManager.notify(1, notification);
}
I had to create a notification object in order to show it on status bar. When the notification is clicked it calls intent App4, this shows the index.html of my app, but I want to execute some javascript function or return some json object to my app using the payload. Maybe I can call other function to do this, not an intent but I'm new on android world and don't know how to do it.
Can anyone help me please?
What you can do is put the JSON data as extras in the notificationIntent Intent that you are creating. You can do this by calling the putExtras() method of your notificationIntent, or do it manually. Whichever way you do it you need to get the data you want into the notificationIntent as extras.
Then when your App4 activity starts you will need catch the Intent in either onNewIntent() or onCreate() and check to see if the Intent or Bundle has the extras that you want. If it does then you create the JSON object and pass it to your javascript application just like you did in the onMessage() method you pasted.
You will also have to remove the code that sends the JSON object to your javascript application in the onMessage() method.
I hope that helps, it should work but I'm away from my computer and can't actually test the code.

Categories

Resources