Hello currently I have setup a application which allows the user to set an alarm. When this alarms reaches it designated time it will then send a notification to the user. Now currently each time this notification is activated it sends a static message e.g. "You have a notification". I want to be able to change this notifications title to the alarms name which I have stored inside of SQLOPENHELPER when the user made the alarm.
I have also given each alarm a specific ID which is the current time in milliseconds and then also stored this inside of my SQL. Now I know you require a new ID for each notification but how would I do this and relate it back to my SQL?
I have included a small diagram just to clarify what I'm doing and my current alarm and broadcast receiver...
Diagram................
Set alarm.....
// id - relates to the custom id given to that alarm
// receiver - is our intent
pendingIntent = PendingIntent.getBroadcast(v.getContext(), id, receiver, PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager.set(AlarmManager.RTC_WAKEUP, myCalendar.getTimeInMillis(), pendingIntent);
// Intent array list is used to store multiple alarms
intentArrayList.add(pendingIntent);
Broadcast receiver...
NotificationManager notificationManager = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE);
Intent moveActivity = new Intent(context, AlarmActivity.class);
moveActivity.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
// Works with moveActivity to move the user back to main application.
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, moveActivity, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
.setContentIntent(pendingIntent)
.setContentTitle("title")
.setContentText("text")
.setSmallIcon(R.mipmap.ic_launcher)
.setAutoCancel(true);
notificationManager.notify(0, builder.build());
// Notification ID has been left at 0 because I don't know what to do as this point and after trying to figure it out for 2 days I thought I should ask.
//// UPDATE
Main Activity
I have implemented a put extra just under my intent Array List
receiver.putExtra("title", id);
Broadcast
Bundle bundle = intent.getExtras();
if (bundle != null) {
pass = bundle.getString("title");
//I have put my notification in this section
}
I tested it by putting "pass" which is the String for retrieving the put extra into the title of my notification and it comes up blank?
Update your receiver intent as below to pass the ALARM_ID:
Intent receiver = new Intent(getApplicationContext(), Receiver.class);
receiver.putExtra("KEY_ALARM_ID", ALARM_ID); // ALARM_ID = id
In PendingIntent.getBroadcast(), Use ALARM_ID as requestCode.
PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, ALARM_ID, receiver, PendingIntent.FLAG_UPDATE_CURRENT );
Always use different requestCode for different notification to get
correct result.
In notify() method, use ALARM_ID as id:
notificationManager.notify(ALARM_ID, builder.build());
Notification id should be unique within your application. If a
notification with the same id has already been posted by your
application and has not yet been canceled, it will be replaced by the
updated information.
In your BroadcastReceiver class onReceive() method get the ALARM_ID:
#Override
public void onReceive(Context context, Intent intent)
{
int alarmId= intent.getExtras().getInt("KEY_ALARM_ID");
// Do something with alarmId
}
Hope this will solve your problem.
// Main activity
receiver.putExtra("title", id);
pendingIntent = PendingIntent.getBroadcast(v.getContext(), id, receiver, PendingIntent.FLAG_UPDATE_CURRENT);
alarmManager.set(AlarmManager.RTC_WAKEUP, myCalendar.getTimeInMillis(), pendingIntent);
intentArrayList.add(pendingIntent);
Broadcast
Bundle bundle = intent.getExtras();
int pass = bundle.getInt("title" , 1);
Thanks psKink you gave me the kick I needed
Related
I have an app which associates some entities with a unique ID and notifies about the entities to the user, which I'm gonna use notificationID to be the same as entity ID.
I have built a notification with a dismiss action based on the following sample solution exactly without any modification.
So far things are going well until I try to create 2 notifications with different ID using the sample.
A problem arises in that the dismiss button only receives the notificationID of the first notification:
The first notification behaves normally as expected.
But the second notification's getExtra() in BroadcastReceiver takes the notificationID of the FIRST notification instead and cancelling the notification just keeps cancelling the first notification.
My create Notification function, I just call this function twice with different IDs:
void createNoti(int NOTIFICATION_ID){
Intent buttonIntent = new Intent(context, ButtonReceiver.class);
buttonIntent.putExtra("notificationId", NOTIFICATION_ID);
PendingIntent btPendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, buttonIntent, 0);
NotificationCompat.Builder mb = new NotificationCompat.Builder(getBaseContext());
mb.addAction(R.drawable.ic_Action, "My Action", btPendingIntent);
manager.notify(NOTIFICATION_ID, mb.build());
}
BroadcastReceiver class:
public class ButtonReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
int notificationId = intent.getIntExtra("notificationId", 0);
NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
manager.cancel(notificationId);
}
}
I believe the issue is in passing in 0 into PendingIntent:
PendingIntent btPendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, buttonIntent, 0);
I had the same issue until I started passing in the notification id as the 2nd argument; so instead of passing in 0, pass in the id of the notification:
PendingIntent btPendingIntent = PendingIntent.getActivity(getApplicationContext(), NOTIFICATION_ID, buttonIntent, 0);
After I made that change, I noticed that when clicking on individual notifications (especially notifications in a group) everything worked as intended.
I am seriously confused now, I have been reading several SE examples and they all seem to be doing slightly different things.
What i want to do: Is have a single Activity called NotificationActivity, when I click on a notification it must open that activity and provide the activity with a DeviceId. I don't want to override or update any pending activities. Each activity should be its own intent.
There should only be once instance of NotificationActivity.
here is the code I have so far:
MyGcmListenerService:
Intent intent = new Intent(this, NotificationActivity.class);
intent.setAction(Intent.ACTION_VIEW);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
//ADD My Extras
intent.putExtra(CommonBundleAttributes.CONNECTING_ACTIVITY_DEVICE_ID, content.DeviceId);
intent.putExtra(CommonBundleAttributes.CONNECTING_ACTIVITY_DEVICE_TYPE_ID, content.DeviceTypeId);
intent.putExtra(CommonBundleAttributes.CONNECTING_ACTIVITY_DEVICE_NAME, content.DeviceName);
//
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle(content.DeviceName)
.setContentText("Notification")
.setAutoCancel(true)
.setSound(ingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
.setGroup("Mi:" + content.DeviceId)
.setContentIntent(pendingIntent);
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(NotificationID++, notificationBuilder.build());
and my NotificationActivity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_notification);
deviceId = getIntent().getExtras().getLong(CommonBundleAttributes.CONNECTING_ACTIVITY_DEVICE_ID, -1);
deviceName = getIntent().getExtras().getString(CommonBundleAttributes.CONNECTING_ACTIVITY_DEVICE_NAME, "");
deviceTypeId = getIntent().getExtras().getInt(CommonBundleAttributes.CONNECTING_ACTIVITY_DEVICE_TYPE_ID, 0);
What am I missing here/ I think I am getting mixed up with all the different flags and launcher types.
If there is already an NotificationActivty in memory, I want to close it and open a new one with the latest intent. If there are 3 notifications on the users phones, and they click on all three. it must open the NotificationActivty for the last clicked Notification.
There must be an issue with my pending intent?
In NotificationActivity, you collect int or long value using following code i.e.
notificationID = getIntent().getExtras().getInt(CommonBundleAttributes.CONNECTING_ACTIVITY_NOTIFICATIONID, 0);
then please pass a proper value with putExtra() i.e. if collect int then pass Integer.parseInt(content.DeviceId) or collect long then pass Long.parseLong(content.DeviceId)
hope it's helpful to you
In Notification class add this line
intent.putExtra(CommonBundleAttributes.CONNECTING_ACTIVITY_NOTIFICATIONID, NotificationID);
In NotificationActivity
notificationID = getIntent().getExtras().getInt(CommonBundleAttributes.CONNECTING_ACTIVITY_NOTIFICATIONID, 0);
I want to be able to have a button that copies the text from a notification to the clipboard. The notification is sent through the google's GCM service.
The first time the notification arrives when I press the "copy" button everything is fine and the text goes into the clipboard by the service that the button sends an intent to. The second time a notification arrives with different text when I press the "copy" button the content of the first notification goes into the clipboard instead of the new one. When I debug the code, it seems that the intent that's calling the service has the new content, but the service that puts it into the clipboard runs with the parameters of the old notification, as if the same session of the service is awaken with the old intent.
Any clue why this is happening?
// Called by the GCM notification handler
private void sendNotification(String msg) {
mNotificationManager = (NotificationManager)
this.getSystemService(Context.NOTIFICATION_SERVICE);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,new Intent(this, MainActivity.class), 0);
Intent notificationIntent = new Intent(this, clipboardService.class);
notificationIntent.putExtra("tool",msg);
PendingIntent serviceIntent = PendingIntent.getService(this, 0, notificationIntent, 0);
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_stat_gcm)
.setContentTitle("Here's your text!")
.setStyle(new NotificationCompat.BigTextStyle()
.bigText(msg))
.setContentText(msg)
.addAction(R.drawable.ic_stat_gcm, "Copy", serviceIntent); // <--- The intent will have the right (new) value on the second run
mBuilder.setContentIntent(contentIntent);
mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
}
This is the service that the notification actions calls to:
public class clipboardService extends IntentService {
public clipboardService() {
super("clipboardService");
}
#Override
protected void onHandleIntent(Intent intent) { //This intent will have the values of the first intent to fire, instead of the updated one.
String msg = (String) intent.getExtras().get("tool");
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("2android",msg);
clipboard.setPrimaryClip(clip);
}
Although it is very late to answer your question, but recently I faced the same issue and Google led to me this unanswered question. So here is my understanding if in future someone dig this up.
This is because PendingIntent uses cached intent extras from previous instance of the intent unless you explicitly tell it not to. There are two ways to do that...
Use FLAG_CANCEL_CURRENT or FLAG_UPDATE_CURRENT (best in your case) as flag while constructing the PendingIntent. The first flag will automatically dismiss the previous PendingIntent and create a completely new one and the second one will only update the extras for the PendingIntent and save the overhead of creating a completely new one.
PendingIntent.getService(this, 0, notificationIntent,
FLAG_CANCEL_CURRENT | FLAG_UPDATE_CURRENT);
Pass an unique requestCode to the PendingIntent constructor everytime. This will generate unique pending intents for everytime so that you can access the extras associated with a particular intent later. I believe this is not required in your case.
PendingIntent.getService(this, UNIQUE_ID, pi, 0);
I'm currently doing some notifications for my app. Now I've successfully created a notification but problem is that each of my notification doesn't pass different extras on click.
Well what happen is that I only have a loop that calls the createNotification method per loop and also I assign different ID's for those for the notification to appear in different stack.
here's my code:
private void createNotification(String record_name, String file_path, String status, int id) {
/*must pass:
* record_name, (get the record name in DB using the id create a new query method)
* record_status, (simple part just match if equivalent to ready to download for the JSON data then show notif if true)
* record_path *full path* (this one can be get using the record name itself add the path and extension name)*/
/*this will jump from the current activity into the target activity class just do some workarounds here*/
Intent intent = new Intent(this, RecordEditActivity.class);
intent.putExtra("record_name", record_name);
intent.putExtra("record_path", file_path);
intent.putExtra("record_status", status);
PendingIntent pIntent = PendingIntent.getActivity(this,0, intent, 0);
/*build the notification here this is only supported for API 11. Since we've targeted API 11 there will be no problem on this*/
NotificationCompat.Builder notify = new NotificationCompat.Builder(this)
.setContentTitle(record_name + " is ready for download")
.setContentText("Click to view or download recording")
.setAutoCancel(true)
.setSmallIcon(R.drawable.notif_icon)
.setLargeIcon(BitmapFactory.decodeResource(this.getResources(), R.drawable.ic_launcher))
.setTicker("Echo: your file is ready for download")
.setContentIntent(pIntent);
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
if(Build.VERSION.SDK_INT<16){
/*build notification for HoneyComb to ICS*/
notificationManager.notify(id, notify.getNotification());
}if(Build.VERSION.SDK_INT>15){
/*Notification for Jellybean and above*/
notificationManager.notify(id, notify.build());
}
}
I think the problem is in the PendingIntent part since I don't know which flags should I use for this but I'm not that sure about it.
Got it! what needed is for me to assign an ID for my pendingIntent requestCode what I did is assign the same ID I used for my notificationManager.
More info here.
Just use this one line of code-
PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
And for more detail see this answer:
GCM android Push Notification shows old message always. Intent received incorrect
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.