Widget - Intent stays the same when receiving - android

I add contact pictures to a widget dynamical. This is my code for this part:
for (int x = 0; x < this.appWidgetIds.length; x++){
int id = this.appWidgetIds[x];
RemoteViews rv = new RemoteViews(this.context.getPackageName(), R.layout.widget);
for (int i = 0; i < maxCount; i++){
String lookupKey = sortedItems.get(i).getLookupKey();
Tools.ToLog("LOOKUPKEY=" + lookupKey);
Bitmap bmp = Contact.getContactPicture(this.context, lookupKey);
if (bmp != null){
Intent intent = new Intent(context, ContactsWidget.class);
intent.setAction(ACTION_WIDGET_RECEIVER);
intent.putExtra(ITENT_LOOKUPKEY, lookupKey);
Tools.ToLog("LOOKUPKEY - IDENT=" + intent.getStringExtra(ITENT_LOOKUPKEY));
RemoteViews itemView = new RemoteViews(this.context.getPackageName(), R.layout.widget_itemview);
itemView.setImageViewBitmap(R.id.widget_ImageView, bmp);
PendingIntent actionPendingIntent = PendingIntent.getBroadcast(this.context, 0, intent, 0);
itemView.setOnClickPendingIntent(R.id.widget_ImageView, actionPendingIntent);
rv.addView(R.id.widgetContainer, itemView);
}
}
appWidgetManager.updateAppWidget(id, rv);
}
I tested the Lookupkey and the lookupkey from the intent over the log and it works on this side (variable lookupKey == intent.getStringExtra(ITENT_LOOKUPKEY)). When I now receive the intent because I clicked on a contact picture the intent extra info is always the same. No matter which of the contact pictures I clicked. This is the receive code:
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ACTION_WIDGET_RECEIVER)) {
String lookupKey = intent.getStringExtra(ITENT_LOOKUPKEY);
Toast.makeText(context, "Lookup Key: " + lookupKey, Toast.LENGTH_SHORT).show();
//Contact.openContact(this.context, lookupKey);
}
super.onReceive(context, intent);
}
It's always the lookupKey from the first added contact. Do I have to clear the intent somehow before adding another contact in the first function or what is the problem?

You only have one PendingIntent.
Quoting the documentation:
If the creating application later re-retrieves the same kind of PendingIntent (same operation, same Intent action, data, categories, and components, and same flags), it will receive a PendingIntent representing the same token if that is still valid
Since you have the same operation (getActivity()) and the same Intent routing pieces each time, there is only one PendingIntent.
Rather than setting the action to be ACTION_WIDGET_RECEIVER, make it be unique for each that you are creating in your loops.

Related

android alarm not getting received by the application

I am facing consistency issue while setting alarms inside my application wherein the alarm gets delivered sometimes but other times the pending intent does not gets delivered to my application.
The way I am trying to test is by changing my local device time and check if I am getting the alarm or not.
I can see the alarm getting triggered from the alarm manager because this log comes up
V AlarmManager: Triggering alarm #0: 0 when =1508253750804 package=com.x.xoperation =*walarm*:com.x.x/x.AlarmReceiver
Does android control the delivery of an alarm based upon whether the application is in the background or not? Any insights around this area would really help.
Code For AlarmManager
public static void SetNotification(int id, long delayMs, String title, String message, String ticker, int sound, int vibrate,
int lights, String largeIconResource, String smallIconResource, int bgColor, String bundle, String dataString)
{
Context currentActivity = UnityPlayer.currentActivity;
AlarmManager am = (AlarmManager)currentActivity.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(currentActivity, AlarmReceiver.class);
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.putExtra("ticker", ticker);
intent.putExtra("title", title);
String arr[] = new String[]{id+"", delayMs+"", title, message, ticker, sound+""};
String fStr = "";
for (String temp:arr
) {
fStr += temp+":";
}
Log.d(Constants.TAG, "Input message = "+fStr);
intent.putExtra("message", message);
intent.putExtra("id", id);
intent.putExtra("color", bgColor);
intent.putExtra("sound", sound == 1);
intent.putExtra("vibrate", vibrate == 1);
intent.putExtra("lights", lights == 1);
intent.putExtra("l_icon", largeIconResource);
intent.putExtra("s_icon", smallIconResource);
intent.putExtra("bundle", bundle);
intent.putExtra("dataString", dataString);
PendingIntent pendingIntent = PendingIntent.getBroadcast(currentActivity,
id, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
am.cancel(pendingIntent);
long finalTime = System.currentTimeMillis() + delayMs;
am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,finalTime, pendingIntent);
Log.d(Constants.TAG, "event fired finalTime = "+ finalTime);
}
Is this because of the doze and app standby which android has introduced ? or is because of some issue on our side.

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 Notifications, loads only the latest intent when there are more than one notifications

I have an app which has 4 layers/stack, something like,
HomePage >> DetailPage >> MapPage >> ChatPage
I managed to create notifications whenever I received different chat messages (note that each conversation has its unique id, say ChatId)
for different conversation, I will create a notification using ChatId as the requestCode in the pendingIntent
The problem I am facing is that, whenever I received more than 1 notification, say ChatId1 comes first, followed by ChatId2. Then when I clicked on the ChatId1's notification, it will launch the latest intent which is ChatId2, making the conversations loaded in ChatPage are conversations of ChatId2.
Question is, how can I make it so that, when I clicked on ChatId1's notification, it loads messages of ChatId1, and when click on ChatId2, it loads messages of ChatId2.
Below is the snippet of the code where I create my notifications
public void createLocalNotification(String meetingIdLong, String countryCode, String phoneNumber, String contactName, String chatMessage) {
// Prepare intent which is triggered if the
// notification is selected
Intent intent = new Intent(this, ChatLog.class);
long L = Long.parseLong(meetingIdLong);
int a = Integer.parseInt(meetingIdLong);
intent.putExtra("meetingId", L);
Intent intent1 = new Intent(this, HomePage.class);
Intent intent2= new Intent(this, MeetingDetailPage.class);
intent2.putExtra("meetingId", L);
Intent intent3 = new Intent(this, MapPage.class);
intent3.putExtra("meetingId", L);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addParentStack(ChatLog.class);
stackBuilder.addNextIntent(intent1);
stackBuilder.addNextIntent(intent2);
stackBuilder.addNextIntent(intent3);
stackBuilder.addNextIntent(intent);
PendingIntent pIntent = stackBuilder.getPendingIntent(a, PendingIntent.FLAG_UPDATE_CURRENT);
String notificationSound = _defPrefs.getString("pref_notification_tone", "");
NotificationCompat.Builder noti = new NotificationCompat.Builder(this)
.setContentTitle(contactName)
.setContentText(chatMessage)
.setSmallIcon(R.drawable.noti_smallicon)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.noti_smallicon))
.setSound(Uri.parse(notificationSound))
.setDefaults(Notification.DEFAULT_VIBRATE)
.setNumber(++numberMsg)
.setAutoCancel(true)
.setContentIntent(pIntent);
NotificationCompat.InboxStyle inboxStyle = new NotificationCompat.InboxStyle();
String[] events = new String[6];
events [numberMsg - 1] = new String(chatMessage);
// Sets a title for the Inbox style big view
inboxStyle.setBigContentTitle(contactName);
inboxStyle.setSummaryText(numberMsg + " new message(s)");
for (int i=0; i < events.length; i++) {
inboxStyle.addLine(events[i]);
}
noti.setStyle(inboxStyle);
String isChatOpen, isChatOpenId;
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
isChatOpen = preferences.getString("isChatOpen","");
isChatOpenId = preferences.getString("isChatOpenId","0");
if (!isChatOpenId.equals(meetingIdLong))
{
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationManager.notify(a, noti.build());
}
}
Use
intent.setAction(Long.toString(System.currentTimeMillis()));
for each your Intent you want to be unique. Its just a dummy action, but it helps.

MMS intent with multiple phone numbers attached

I am using the below code to call an MMS intent :
{
Intent mmsIntent = new Intent(Intent.ACTION_SEND);
mmsIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mmsIntent.putExtra("address", temp);
mmsIntent.putExtra("sms_body", msgstr);
mmsIntent.putExtra(Intent.EXTRA_STREAM, mediaUri);
}
Here 'temp' is the string containing multiple numbers and differentiated with ';'. It's working fine when we use this code for only a single number but when i add multiple numbers it doesn't attached to the messaging app. I have tried the same thing with ',' to separate the phone numbers but it also doesn't work. Any help is appreciated.
Intent mmsIntent= new Intent(Intent.ACTION_SENDTO,Uri.parse("smsto:9858254511;9858526521"));
mmsIntent.putExtra("sms_body", msgstr);
mmsIntent.putExtra(Intent.EXTRA_STREAM, mediaUri);
startActivity(smsIntent);
Add a semicolon delimited list of phone numbers to "smsto:" as the URI in the Intent constructor. Also refer this LINK
protected void sendMsg(Context context, SmsMessage smsMessage) {
SmsManager smsMgr = SmsManager.getDefault();
ArrayList<string> smsMessageText = smsMgr.divideMessage(smsMessage.getMsgBody());
PendingIntent sentPI = PendingIntent.getBroadcast(context, 0, new Intent("SMS_SENT"), 0);
PendingIntent deliveredPI = PendingIntent.getBroadcast(context, 0, new Intent("SMS_DELIVERED"), 0);
int AddresseesPerMessage = 10;
StringBuilder builder = new StringBuilder();
String delim = "";
for (ContactItem c:smsMessage.getAddresseeList()) {
// For every phone number in our list
builder.append(delim).append(c.getPhoneNumber().toString());
delim=";";
if (((smsMessage.getAddresseeList().indexOf(c)+1) % AddresseesPerMessage) == 0 || smsMessage.getAddresseeList().indexOf(c)+1 == smsMessage.getAddresseeList().size()) {
// using +1 because index 0 mod 9 == 0
for(String text : smsMessageText){
// Send 160 bytes of the total message until all parts are sent
smsMgr.sendTextMessage(builder.toString(), null, text, sentPI, deliveredPI);
}
builder.setLength(0);
delim="";
}
}
}
use this code...i hope its useful to you.

How to tie specific pending intents to specific buttons on specific widgets on a multi-widget.. appwidget?

I have a Widget i am working on, that allows the user to have more then one instance of the widget on his screen. Each Widget id maintains its own configuration file. However for some odd reason my code that is responsible for setting up the buttons individually for each widget id is not working, only the first widget id is linked to each individual widget. below is the code that is responsible. Can anyone see where the problem is?
private void TieClicks(Context context){
RemoteViews rViews;
PendingIntent editPendingIntent= null;
// Intent updateintent = new Intent(context,SyncNoteWidget.class);
// updateintent.setAction(SyncNote_Action_Widget_Update);
// PendingIntent pendingupdateintent = PendingIntent.getBroadcast(context, 0, updateintent, 0);
// rViews.setOnClickPendingIntent(R.id.widgettextview , pendingupdateintent);
//
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
int[] ids = appWidgetManager.getAppWidgetIds(new ComponentName(context, SyncNoteWidget.class));
for (int i =0;i< ids.length;i=i+1){
int wId = ids[i];
rViews = new RemoteViews(context.getPackageName(),R.layout.widget);
editPendingIntent = makeControlPendingIntentActivity(context, wId);
Log.v("syncnote", "tieing " + String.valueOf(wId));
rViews.setOnClickPendingIntent(R.id.widgeteditbutton , editPendingIntent);
appWidgetManager.updateAppWidget(wId, rViews);
editPendingIntent= null;
}
}
private PendingIntent makeControlPendingIntentActivity(Context context,int appWidgetId) {
Intent active = new Intent(context, EditNote.class);
active.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK );
active.setAction(com.ntu.way2fungames.syncnote.SyncNoteWidget.SyncNote_Action_Edit);
active.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
return(PendingIntent.getActivity(context, 0, active, 0 ));
}
The problem was that for some reason "PendingIntent.getActivity" was re-using the first PendingIntent.. God knows why. The fix is below, simply add some random data to the call.
private PendingIntent makeControlPendingIntentActivity(Context context,int appWidgetId) {
Intent active = null;
active = new Intent(context, EditNote.class);
active.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK );
active.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK );
active.setAction(com.ntu.way2fungames.syncnote.SyncNoteWidget.SyncNote_Action_Edit);
active.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
PendingIntent pi =PendingIntent.getActivity(context,(int)(Math.random()*10000), active, 0 );
Log.v("syncnote", "PI: "+pi.toString());
return(pi);
}
It would help if you included the log entries you're creating with:
Log.v("syncnote", "tieing " + String.valueOf(wId));
That could answer the important question:
How many values are in: int[] ids ?
What is in R.layout.widget ?
A picture of your widgets would help too. A picture is worth a thousand words...

Categories

Resources