Not able to identify id for item clicked on notification was for unique id which is working out well,now for the same even with different id when i click on notifications i get unique invoice id ,which i am passing to a webservice to get its invoice details,even though its fetching data for that id,the itemActivity page is showing previous details only,how will i update the page with new contents ?
Send Notification code is
public class SampleSchedulingService extends IntentService {
public SampleSchedulingService() {
super("SchedulingService");
}
List<GetReminder> newReminderList;
int invoiceId=0;
String remMes;
InvoiceData1 data1;
int InvM_Id;
public static final String TAG = "Scheduling Demo";
// An ID used to post the notification.
public static int NOTIFICATION_ID = 1;
private NotificationManager mNotificationManager;
NotificationCompat.Builder builder;
#Override
protected void onHandleIntent(Intent intent) {
// BEGIN_INCLUDE(service_onhandle)
// The URL from which to fetch content.
Log.d("MyService", "About to execute MyTask");
//
newReminderList=WebService.invokeGetReminderWS("GetReminder",41);
if(newReminderList!=null){
for(int i=0;i<newReminderList.size();i++) {
sendNotification(newReminderList.get(i).getRemMessage(),newReminderList.get(i).getInvM_Id());
}
}
// Release the wake lock provided by the BroadcastReceiver.
SampleAlarmReceiver.completeWakefulIntent(intent);
// END_INCLUDE(service_onhandle)
}
// Post a notification indicating whether a doodle was found.
private void sendNotification(String msg, int invM_id) {
try {
Intent notificationIntent = new Intent(this, ItemActivity.class);
notificationIntent.setAction(Intent.ACTION_MAIN);
notificationIntent.addCategory(Intent.CATEGORY_LAUNCHER);
data1=WebService.InvoiceDetailForExeedDiscount1(invM_id);
notificationIntent.putExtra("invoiceList", data1);
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent contentIntent = PendingIntent.getActivity(this, NOTIFICATION_ID, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
mNotificationManager = (NotificationManager)
this.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle(getString(R.string.invoice_alert))
.setStyle(new NotificationCompat.BigTextStyle()
.bigText(msg))
.setContentText(msg);
mBuilder.setContentIntent(contentIntent);
mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
NOTIFICATION_ID++;}
catch (IOException e) {
} catch (XmlPullParserException e) {
}
}
}
and itemActivity i am reading data like
public class ItemActivity extends Activity implements View.OnClickListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final boolean customTitleSupported =
requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
setContentView(R.layout.itemlist);
if(customTitleSupported){
getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE,R.layout.item);
}
InvoiceData1 invoiceList = (InvoiceData1) getIntent().getSerializableExtra("invoiceList");
}
its like when we come out of the application and click on second notification,its just blandly showing the invoice details of previous one,der is no call going on to fetch data for clicked on.
As you are using FLAG_ACTIVITY_SINGLE_TOP flag in your PendingIntent you must also implement onNewIntenet() method in ItemActivity to properly handle this launch mode. As per documentation:
This is called for activities that set launchMode to "singleTop" in
their package, or if a client used the FLAG_ACTIVITY_SINGLE_TOP flag
when calling startActivity(Intent). In either case, when the activity
is re-launched while at the top of the activity stack instead of a new
instance of the activity being started, onNewIntent() will be called
on the existing instance with the Intent that was used to re-launch
it.
An activity will always be paused before receiving a new intent, so
you can count on onResume() being called after this method.
Note that getIntent() still returns the original Intent. You can use
setIntent(Intent) to update it to this new Intent.
so it should be sufficient to move some code from your onResume() and limit onNewIntent() implementation to single setIntent() call.
Related
My app repeatedly loads data from a server. Among those data are messages.
Whenever new messages are loaded, the MainActivity is called on an Interface's callback method onMessagesReceived(int numOfMessages).
The app has only one Activity and every screen is implemented as a Fragment. Switching of Fragments is managed by a dedicated Navigator class.
My problem is the handling of the user tapping on the Notification. When the user taps on the Notification, the message list should be shown.
public class MainActivity extends AppCompatActivity implements MessageListener {
private static final int MESSAGE_NOTIFICATION_ID = 101010;
private static final String EXTRA_SHOW_MESSAGES = "SHOW_MESSAGES";
private Navigator mNavigator;
#Override
onMessagesReceived(int numOfMessages) {
Intent intent = new Intent(this, MainActivity.class);
testIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
testIntent.putExtra(EXTRA_SHOW_MESSAGES, true);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "testChannel")
.setSmallIcon(R.drawable.ic_message_notification)
.setContentTitle("New messages!")
.setContentText("You got " + numOfMessages + " new messages")
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setContentIntent(pendingIntent);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
notificationManager.notify(MESSAGE_NOTIFICATION_ID, builder.build());
}
#Override
protected void onResume() {
super.onResume();
Bundle extras = getIntent().getExtras();
if (extras != null && extras.containsKey(EXTRA_SHOW_MESSAGES)) {
if (extras.getBoolean(EXTRA_SHOW_MESSAGES)) {
mNavigator.openMessageList();
}
}
}
}
At the moment, the MainActivity shows up, when the app is in background, but in onResume, the Bundle returns as null.
When the app is in the foreground, nothing happens at all.
I want to achieve on a click on the Notification:
- When the user is inside the app, the MessageList Fragment should be opened
- When the user is not inside the app, it should be started before opening the MessageList Fragment
Can someone give me a hint, how to proceed from here? Maybe using Intents isn't the right solution here?
You can use intents just put some boolean extras in intent an just check the value in main activity if that extra value is true then call your method.
After some more digging on Intents and Notifications, I finally came up with a solution.
public class MainActivity extends AppCompatActivity implements MessageListener {
private static final int MESSAGE_NOTIFICATION_ID = 101010;
private static final String EXTRA_SHOW_MESSAGES = "SHOW_MESSAGES";
private Navigator mNavigator;
#Override
onMessagesReceived(int numOfMessages) {
Intent intent = new Intent(this, MainActivity.class);
testIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
testIntent.putExtra(EXTRA_SHOW_MESSAGES, true);
PendingIntent pendingIntent = PendingIntent.getActivity(
this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "testChannel")
.setSmallIcon(R.drawable.ic_message_notification)
.setContentTitle("New messages!")
.setContentText("You got " + numOfMessages + " new messages")
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setContentIntent(pendingIntent);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
notificationManager.notify(MESSAGE_NOTIFICATION_ID, builder.build());
}
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
this.setIntent(intetnt)
Bundle extras = intent.getExtras();
if (extras != null && extras.containsKey(EXTRA_SHOW_MESSAGES)) {
if (extras.getBoolean(EXTRA_SHOW_MESSAGES)) {
mNavigator.openMessageList();
}
}
}
}
I moved my code, reading the new Intent, to onNewIntent. This method gets called, when an Activity gets a new Intent and before onResume. This triggers regardless of the Activity being in the foreground or not. I also set this new Intent to be the Activities Intent with setIntent, otherwise the Intent that initialy started my Activity, is called by getIntent().
I am showing a notification from a library attached to my project, when clicked on the notification, the notification takes to an Activity (ReceivingActivity). Activity opens after clicking the notification ,but the extras attached to it are not received.
Notification triggering code - I call sendNotification when i receive a gcm message and Notification code is in the library
public static final int NOTIFICATION_ID = 1;
private NotificationManager mNotificationManager;
NotificationCompat.Builder builder;
private void sendNotification(Bundle extras) {
mNotificationManager = (NotificationManager)
this.getSystemService(Context.NOTIFICATION_SERVICE);
Intent redirectIntent = new Intent(this, Class.forName("com.xyz.kljdf.ReceivingActivity"));
redirectIntent.putExtra("key", "value"); // These extras are not received in ReceivingActivity onCreate(), see the code below
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
redirectIntent, 0);
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(((Context)this).getResources().getIdentifier("icon", "drawable", getPackageName()))
.setContentTitle(extras.getString(PushConstants.TITLE))
.setStyle(new NotificationCompat.BigTextStyle()
.bigText(extras.getString(PushConstants.ALERT)))
.setContentText(extras.getString(PushConstants.ALERT));
mBuilder.setContentIntent(contentIntent);
mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
}
Checking the extras in the ReceivingActivity...
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_receiving);
Log.i("extras..... ######", getIntent().getExtras().toString()); //NPE here
}
I need help in figuring out how to pass the extras and receive them correctly.
Make sure the PendingIntent is actually passing the data when it's called. See this answer for an explanation: https://stackoverflow.com/a/3851414/1426565
For anyone else, if you're positive the intent already exists and is just brought to the front, the new Intent's data won't be passed to it by default. You can override onNewIntent(Intent) in order to get around that:
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent); // Set the new Intent's data to be the currently passed arguments
}
I have been searching a lot of questions and answers in stackoverflow. I am still not able to solve my problem.
I set broadcast for a particular time.
I receive the broadcast perfectly in another class 'AlarmReceiver.java' which creates notification on receiving broadcast.
But I pass a string through an intent that calls a class 'AlarmResponder.java' on pressing the notification.
The class is getting called.
I receive the String data i passed through the intent only for the first time.
Next time I dont get anything. getextras() gives me null .
If i change the ID of the notification in NotificationManager.notify(1, mBuilder.build()); as
NotificationManager.notify(2, mBuilder.build()); it works .
But always it works only once
Please help me
public class AlarmReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
CharSequence reminderText = intent.getCharSequenceExtra("reminderText");
if (reminderText != null && reminderText != "") {
Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
Ringtone r = RingtoneManager.getRingtone(context, notification);
r.play();
//Toast.makeText(context, intent.getCharSequenceExtra("reminderText"), Toast.LENGTH_LONG).show();
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle(reminderText)
.setContentText("its time buddy");
// Creates an explicit intent for an Activity in your app
Intent resultIntent = new Intent(context, AlarmResponder.class);
resultIntent.putExtra("reminderText", reminderText);
resultIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
// The stack builder object will contain an artificial back stack for the
// started Activity.
// This ensures that navigating backward from the Activity leads out of
// your application to the Home screen.
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
// Adds the back stack for the Intent (but not the Intent itself)
stackBuilder.addParentStack(AlarmResponder.class);
// Adds the Intent that starts the Activity to the top of the stack
stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent =
stackBuilder.getPendingIntent(
0,
PendingIntent.FLAG_UPDATE_CURRENT
);
mBuilder.setContentIntent(resultPendingIntent);
NotificationManager mNotificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
// mId allows you to update the notification later on.
mNotificationManager.notify(1, mBuilder.build());
}
}
}
and the AlarmResponder class is
public class AlarmResponder extends Activity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
onNewIntent(getIntent());
}
#Override
public void onNewIntent(Intent intent){
Bundle extras = intent.getExtras();
if(extras != null){
if(extras.containsKey("reminderText"))
{
setContentView(R.layout.alarm_responder);
TextView reminderText = (TextView) findViewById(R.id.reminderText);
// extract the extra-data in the Notification
String msg = extras.getString("reminderText");
reminderText.setText(msg);
}
}
}
}
Problem
When the user presses Send "Button 1"(scroll down to see the construction of the app) a new Notification is created from the RefreshService. If the user presses this notification a MainActivity instance gets started and receives a String with the value Button 1 over the Intent.
This value gets displayed.
When the user presses now the Send "Button 2" a new Notification is created from the RefreshService. If the user presses this notification a MainActivity instance gets started and receives a String ALSO with the value Button 1 over the Intent.
So as you can guess, normally there should be the value Button 2.
When the first Button the user pressed was Send "Button 2" then there would allways Button 2 be sent.
The only sollution to get the value of the second button is to restart the phone and pressing the second button first. Even force close doesn't work.
I know that I also can change the UI in another way. But I need this approach in a app where I need to restart the 'MainActivity' with another Intent so the approach should be the same.
Construction
A Activity called MainActivity
A IntentService called RefreshService
MainActivity
public class MainActivity extends Activity implements View.OnClickListener {
public static final String RECEIVED = "received";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
((TextView)findViewById(R.id.textView_received)).setText(getIntent().getStringExtra(RECEIVED));
findViewById(R.id.button_1).setOnClickListener(this);
findViewById(R.id.button_2).setOnClickListener(this);
}
#Override
public void onClick(View v) {
Intent intent = new Intent(this, RefreshService.class);
if(v.getId() == R.id.button_1){
intent.putExtra(RECEIVED, "Button 1");
Toast.makeText(this,"Sent \"Button 1\"",Toast.LENGTH_LONG).show();
}
else if(v.getId() == R.id.button_2){
intent.putExtra(RECEIVED, "Button 2");
Toast.makeText(this,"Sent \"Button 2\"",Toast.LENGTH_LONG).show();
}
startService(intent);
}
}
RefreshService
public class RefreshService extends IntentService {
public RefreshService() {
super("RefreshService");
}
#Override
protected void onHandleIntent(Intent intent) {
String received = intent.getStringExtra(MainActivity.RECEIVED);
Intent notificationIntent = new Intent(this, MainActivity.class);
notificationIntent.putExtra(MainActivity.RECEIVED, received);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this).setContentTitle("IntentServiceRefresh").setContentText(received).setSmallIcon(R.drawable.ic_notification_small).setContentIntent(pendingIntent);
Notification notification = builder.build();
// Hide the notification after it's selected
notification.flags |= Notification.FLAG_AUTO_CANCEL;
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0, notification);
}
}
App Layout
My suspicion is that, since the only thing changing in the Intent is the extras, the PendingIntent.getActivity(...) factory method is simply re-using the old intent as an optimization.
In RefreshService, try:
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT);
See:
http://developer.android.com/reference/android/app/PendingIntent.html#FLAG_CANCEL_CURRENT
I'm using an android notification to alert the user once a service is finished (success or failure), and I want to delete local files once the process is done.
My problem is that in the event of failure - I want to let the user a "retry" option. and if he chooses not to retry and to dismiss the notification I want to delete local files saved for the process purposes (images...).
Is there a way to catch the notification's swipe-to-dismiss event?
DeleteIntent:
DeleteIntent is a PendingIntent object that can be associated with a notification and gets fired when the notification gets deleted, ether by :
User specific action
User Delete all the notifications.
You can set the Pending Intent to a broadcast Receiver and then perform any action you want.
Intent intent = new Intent(this, MyBroadcastReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this.getApplicationContext(), 0, intent, 0);
Builder builder = new Notification.Builder(this):
..... code for your notification
builder.setDeleteIntent(pendingIntent);
MyBroadcastReceiver
public class MyBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
.... code to handle cancel
}
}
A fully flushed out answer (with thanks to Mr. Me for the answer):
1) Create a receiver to handle the swipe-to-dismiss event:
public class NotificationDismissedReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
int notificationId = intent.getExtras().getInt("com.my.app.notificationId");
/* Your code to handle the event here */
}
}
2) Add an entry to your manifest:
<receiver
android:name="com.my.app.receiver.NotificationDismissedReceiver"
android:exported="false" >
</receiver>
3) Create the pending intent using a unique id for the pending intent (the notification id is used here) as without this the same extras will be reused for each dismissal event:
private PendingIntent createOnDismissedIntent(Context context, int notificationId) {
Intent intent = new Intent(context, NotificationDismissedReceiver.class);
intent.putExtra("com.my.app.notificationId", notificationId);
PendingIntent pendingIntent =
PendingIntent.getBroadcast(context.getApplicationContext(),
notificationId, intent, 0);
return pendingIntent;
}
4) Build your notification:
Notification notification = new NotificationCompat.Builder(context)
.setContentTitle("My App")
.setContentText("hello world")
.setWhen(notificationTime)
.setDeleteIntent(createOnDismissedIntent(context, notificationId))
.build();
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(notificationId, notification);
Another Idea:
if you create a notification normally you also need the actions one, two or 3 of them. I've created a "NotifyManager" it creates all notifications i need and also receive all Intent calls.
So i can manage all the actions AND also the catch the dismiss event at ONE place.
public class NotifyPerformService extends IntentService {
#Inject NotificationManager notificationManager;
public NotifyPerformService() {
super("NotifyService");
...//some Dagger stuff
}
#Override
public void onHandleIntent(Intent intent) {
notificationManager.performNotifyCall(intent);
}
to create the deleteIntent use this (in the NotificationManager):
private PendingIntent createOnDismissedIntent(Context context) {
Intent intent = new Intent(context, NotifyPerformMailService.class).setAction("ACTION_NOTIFY_DELETED");
PendingIntent pendingIntent = PendingIntent.getService(context, SOME_NOTIFY_DELETED_ID, intent, 0);
return pendingIntent;
}
and THAT i use to set the delete Intent like this (in the NotificationManager):
private NotificationCompat.Builder setNotificationStandardValues(Context context, long when){
String subText = "some string";
NotificationCompat.Builder builder = new NotificationCompat.Builder(context.getApplicationContext());
builder
.setLights(ContextUtils.getResourceColor(R.color.primary) , 1800, 3500) //Set the argb value that you would like the LED on the device to blink, as well as the rate
.setAutoCancel(true) //Setting this flag will make it so the notification is automatically canceled when the user clicks it in the panel.
.setWhen(when) //Set the time that the event occurred. Notifications in the panel are sorted by this time.
.setVibrate(new long[]{1000, 1000}) //Set the vibration pattern to use.
.setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.mipmap.ic_launcher))
.setSmallIcon(R.drawable.ic_white_24dp)
.setGroup(NOTIFY_GROUP)
.setContentInfo(subText)
.setDeleteIntent(createOnDismissedIntent(context))
;
return builder;
}
and finally in the same NotificationManager is the perform function:
public void performNotifyCall(Intent intent) {
String action = intent.getAction();
boolean success = false;
if(action.equals(ACTION_DELETE)) {
success = delete(...);
}
if(action.equals(ACTION_SHOW)) {
success = showDetails(...);
}
if(action.equals("ACTION_NOTIFY_DELETED")) {
success = true;
}
if(success == false){
return;
}
//some cleaning stuff
}