I'm trying to run an activity through a notification and event onCreate I would like to "redirect". To this add a thought on information in the Intent class. An important feature is that the class that generates the notification is performed through a service. I retrieve the context from getApplicationContext method provided by the class android.app.Application. Whenever I call method getExtras() is returning null. What am I doing wrong?
public class OXAppUpdateHandler {
private void addNotification(Context context, int iconID,
CharSequence tickerText, CharSequence title, CharSequence content) {
CharSequence notificationTicket = tickerText;
CharSequence notificationTitle = title;
CharSequence notificationContent = content;
long when = System.currentTimeMillis();
Intent intent = new Intent(context, MainActivity_.class);
intent.setFlags(
Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.putExtra(OPEN_UPDATE_ACTIVITY_KEY, 1);
PendingIntent pendingIntent =
PendingIntent.getActivity(context, 0, intent, 0);
NotificationManager notificationManager =
(NotificationManager) context.getSystemService(
Context.NOTIFICATION_SERVICE);
Notification notification =
new Notification(iconID, notificationTicket, when);
notification.setLatestEventInfo(context, notificationTitle,
notificationContent, pendingIntent);
notificationManager.notify(NOTIFICATION_ID, notification);
}
public static boolean isUpdateStart(Intent intent) {
Bundle bundle = intent.getExtras();
boolean result = bundle != null &&
bundle.containsKey(OPEN_UPDATE_ACTIVITY_KEY);
if (result) {
bundle.remove(OPEN_UPDATE_ACTIVITY_KEY);
}
return result;
}
}
#EActivity(R.layout.activity_main)
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (OXAppUpdateHandler.isUpdateStart(getIntent())) {
startActivity(new Intent(this, UpdateActivity_.class));
}
}
}
I'm going to lean out the window and guess that your problem is here:
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
You are passing intent to getActivity() and expecting that you will get back a PendingIntent that matches your Intent and includes your extras. Unfortunately, if there is already a PendingIntent floating around in the system that matches your Intent (without taking into consideration your Intent extras) then getActivity() will return you that PendingIntent instead.
To see if this is the problem, try this:
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
This says that if there is already a PendingIntent that matches your Intent somewhere in the system that it should replace the extras with the ones in your intent parameter.
(1) Check here to make sure you are using the put/get extras correctly as I don't see the code where you are adding data the intent.
(2) It looks like you are not calling get intent and get extra and, as a result, not actually getting anything from the bundle (assuming that information extists). If you are checking for a boolean value you should get the data you place in the bundle as follows:
Bundle bundle = getIntent().getExtras();
if (bundle.getBooleanExtra("WHATEVER"){
//whatever you want to do in here
}
Related
I want to open a specific tab, based on code. It works if I do this via a normal button.
The way it works:
public void toSomewhere (View view) {
Intent intent = new Intent(this, SomewhereActivity.class);
intent.putExtra("FirstTab", 2);
startActivity(intent);
}
Intent i = getIntent();
int tabToOpen = i.getIntExtra("FirstTab", -1);
if (tabToOpen!=-1) {
// Open the right tab
}
else {
// Other tab
}
The way I want it to work through notifications (at this moment I have this code which sends a notification, but doesn't give the .putExtra through):
public static void NotificationIntent(String title, String message) {
Intent notificationIntent = new Intent(currentContext, SomewhereActivity.class);
**notificationIntent.putExtra("FirstTab", 2);**
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent intent = PendingIntent.getActivity(currentContext, 0, notificationIntent, 0);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(currentContext)
.setContentTitle(title)
.setContentIntent(intent)
.setContentText(message)
.setAutoCancel(true)
.setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE | Notification.DEFAULT_LIGHTS);
NotificationManager mNotificationManager = (NotificationManager) currentContext.getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(0, mBuilder.build());
}
Does anyone know how to fix this, so it will work also with a notification post?
Use an FLAG_UPDATE_CURRENT
From docs :
Flag indicating that if the described PendingIntent already exists, then keep it but replace its extra data with what is in this new Intent. For use with getActivity(Context, int, Intent, int), getBroadcast(Context, int, Intent, int), and getService(Context, int, Intent, int).
This can be used if you are creating intents where only the extras change, and don't care that any entities that received your previous PendingIntent will be able to launch it with your new extras even if they are not explicitly given to it.
Code :
Intent notificationIntent = new Intent(getApplicationContext(), viewmessage.class);
notificationIntent.putExtra("NotificationMessage", notificationMessage);
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingNotificationIntent = PendingIntent.getActivity(getApplicationContext(),notificationIndex,notificationIntent,PendingIntent.FLAG_UPDATE_CURRENT);
notification.flags |= Notification.FLAG_AUTO_CANCEL;
notification.setLatestEventInfo(getApplicationContext(), notificationTitle, notificationMessage, pendingNotificationIntent);
In Activity in onNewIntent method :
#Override
public void onNewIntent(Intent intent){
Bundle extras = intent.getExtras();
String notificationMessage = extras.getString("NotificationMessage", "UNDEFINED");
}
also forward call in onCreate :
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
onNewIntent(getIntent());
}
What I am trying to do is to sent a Notification to Wear with a PendingIntent to open a simple Activity of which TextView is set by an Intents Extra (String). The problem is, that the Extras seems to be empty.
Here is my Code for the MainActivity:
public class MainActivity extends ActionBarActivity {
public static final String KEY = "eu.paliga.creatinganotification.Key";
public static final String MSG = "welcome back";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent viewIntent = new Intent(MainActivity.this, ViewEventActivity.class);
viewIntent.putExtra(KEY, MSG);
PendingIntent viewPendingIntent = PendingIntent.getActivity(MainActivity.this, 0, viewIntent, 0);
NotificationCompat.Builder notificationBuilder =
new NotificationCompat.Builder(MainActivity.this)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("trying")
.setContentText("to figure it out")
.setContentIntent(viewPendingIntent);
NotificationManagerCompat notificationManager =
NotificationManagerCompat.from(MainActivity.this);
notificationManager.notify(0, notificationBuilder.build());
}
});
}
....
}
and for the Activity that is started by the Intent:
public class ViewEventActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_viewintent);
Intent intent = getIntent();
if (intent.hasExtra(MainActivity.KEY)) {
String msg = intent.getStringExtra(MainActivity.KEY);
Log.d("MyTag", msg);
((TextView)findViewById(R.id.textView2)).setText(msg);
}
}
}
When you use PendingIntent.getActivity(MainActivity.this, 0, viewIntent, 0) (specifically, the 0 as the last parameter), extras do not get replaced per the PendingIntent overview:
Because of this behavior, 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. 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.
They go into details on how to deal with them, although the most common solution is to replace your call with:
PendingIntent.getActivity(MainActivity.this, 0, viewIntent,
PendingIntent.FLAG_UPDATE_CURRENT)
Where FLAG_UPDATE_CURRENT denotes that the system should update the extras in the PendingIntent.
I am implementing one sdk where when user click on notification then certain activity will be open.I am just wondering how can i pass different -different activity on intent.Here is my sample code:-
void fireNotification(Context _context, String appname,
String appdescription) {
Intent resultIntent = new Intent(_context, ResultActivity.class);
try {
PendingIntent contentIntent = PendingIntent.getActivity(_context,0, resultIntent,PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder = new NotificationCompat.Builder(_context);
}
Please suggest me how can pass different activity in intent.
I assume that you wanted to load another Activity instead of ResultActivity, you could just change the ResultActivity.class to the class name of the other activity.
If you are looking to have the ability to determine which activity to load after user taps on the notification, you can create a new Activity that will determine which Activity to load after it launches, kinda like an Activity to "redirect" the screen.
Try this..
void fireNotification(Context _context, String appname,
String appdescription) {
Intent resultIntent = null;
if(something)
resultIntent = new Intent(_context, SomeActivity1.class);
else
resultIntent = new Intent(_context, SomeActivity2.class);
try {
PendingIntent contentIntent = PendingIntent.getActivity(
_context,
0,
resultIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder = new NotificationCompat.Builder(
_context);
}
Here is some code I use to create notifications. It uses the v4 Compatibility library.
As you can see you have to recreate the PentingIntent if you want to change the Activity to be launched. There is nothing wrong with cancelling and reissuing the intent as I have done. If you dont have allowing ticket text user likely not even notice it. Also, note that I know the compatibility builder lets you assign custom views but this crashes for me every time, directly assigning it seems more stable.
public static void setupNotification(Context context) {
if (mNotificationManager == null) {
mNotificationManager = (NotificationManager) context.getSystemService(Service.NOTIFICATION_SERVICE);
}
mNotificationManager.cancel(R.layout.main);
int icon = R.drawable.ic_stat_notify_connected;
String tickerText = context.getString(R.string.TickerText);
createNotification(context, tickerText, icon);
mNotificationManager.notify(R.layout.main, mNotification);
}
private static void createNotification(Context context, String tickerText, int icon) {
Intent notificationIntent = new Intent();
notificationIntent = new Intent(context, NotificationOptionsActivity.class);
String contentTitle = context.getString(R.string.MessageTitle);
PendingIntent contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, Intent.FLAG_ACTIVITY_NEW_TASK);
if (mNotification == null) {
mNotification = new NotificationCompat.Builder(context.getApplicationContext()).setContentTitle(contentTitle).setSmallIcon(icon).setContentIntent(contentIntent).build();
mNotification.flags |= Notification.FLAG_ONGOING_EVENT;
RemoteViews contentView = new RemoteViews(context.getApplicationContext().getPackageName(), R.layout.notification_custom_layout);
mNotification.contentView = contentView;
} else {
mNotification.contentIntent = contentIntent;
}
}
Note: You have to use Intent.FLAG_ACTIVITY_NEW_TASK nothing else will work.
You can remove the code for the custom view if you don't have a custom view.
If you do have a custom view, you can set values in it as follows:
mNotification.contentView.setTextViewText(R.id.noti_user, user);
//default image
mNotification.contentView.setImageViewResource(R.id.noti_image, R.drawable.ic_user_icon);
My MainActicity starts RefreshService with a Intent which has a boolean extra called isNextWeek.
My RefreshService makes a Notification which starts my MainActivity when the user clicks on it.
this looks like this:
Log.d("Refresh", "RefreshService got: isNextWeek: " + String.valueOf(isNextWeek));
Intent notificationIntent = new Intent(this, MainActivity.class);
notificationIntent.putExtra(MainActivity.IS_NEXT_WEEK, isNextWeek);
Log.d("Refresh", "RefreshService put in Intent: isNextWeek: " + String.valueOf(notificationIntent.getBooleanExtra(MainActivity.IS_NEXT_WEEK,false)));
pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
builder = new NotificationCompat.Builder(this).setContentTitle("Title").setContentText("ContentText").setSmallIcon(R.drawable.ic_notification).setContentIntent(pendingIntent);
notification = builder.build();
// Hide the notification after its selected
notification.flags |= Notification.FLAG_AUTO_CANCEL;
notificationManager.notify(NOTIFICATION_REFRESH, notification);
As you can see the notificationIntent should have the booleanextra IS_NEXT_WEEK with the value of isNextWeek which is put in the PendingIntent.
When I click now this Notification I always get false as value of isNextWeek
This is the way I get the value in the MainActivity:
isNextWeek = getIntent().getBooleanExtra(IS_NEXT_WEEK, false);
Log:
08-04 00:19:32.500 13367-13367/de.MayerhoferSimon.Vertretungsplan D/Refresh: MainActivity sent: isNextWeek: true
08-04 00:19:32.510 13367-13573/de.MayerhoferSimon.Vertretungsplan D/Refresh: RefreshService got: isNextWeek: true
08-04 00:19:32.510 13367-13573/de.MayerhoferSimon.Vertretungsplan D/Refresh: RefreshService put in Intent: isNextWeek: true
08-04 00:19:41.990 13367-13367/de.MayerhoferSimon.Vertretungsplan D/Refresh: MainActivity.onCreate got: isNextWeek: false
When I directly start the MainActivity with an Intent with the ìsNextValue` like this:
Intent i = new Intent(this, MainActivity.class);
i.putExtra(IS_NEXT_WEEK, isNextWeek);
finish();
startActivity(i);
everything works fine and I get true when isNextWeek is true.
What do I make wrong that there is always a false value?
UPDATE
this solves the problem:
https://stackoverflow.com/a/18049676/2180161
Quote:
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
UPDATE 2
See answer below why it is better to use PendingIntent.FLAG_UPDATE_CURRENT.
Using PendingIntent.FLAG_CANCEL_CURRENT not a good solution because of inefficient use of memory. Instead use PendingIntent.FLAG_UPDATE_CURRENT.
Use also Intent.FLAG_ACTIVITY_SINGLE_TOP (the activity will not be launched if it is already running at the top of the history stack).
Intent resultIntent = new Intent(this, FragmentPagerSupportActivity.class).
addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
resultIntent.putExtra(FragmentPagerSupportActivity.PAGE_NUMBER_KEY, pageNumber);
PendingIntent resultPendingIntent =
PendingIntent.getActivity(
this,
0,
resultIntent,
PendingIntent.FLAG_UPDATE_CURRENT
);
Then:
#Override
protected void onCreate(Bundle savedInstanceState) {
try {
super.onCreate(savedInstanceState);
int startPageNumber;
if ( savedInstanceState != null)
{
startPageNumber = savedInstanceState.getInt(PAGE_NUMBER_KEY);
//so on
It should work now.
If you still have not expected behaviour, try to implement void onNewIntent(Intent intent) event handler, that way you can access the new intent that was called for the activity (which is not the same as just calling getIntent(), this will always return the first Intent that launched your activity.
#Override
protected void onNewIntent(Intent intent) {
int startPageNumber;
if (intent != null) {
startPageNumber = intent.getExtras().getInt(PAGE_NUMBER_KEY);
} else {
startPageNumber = 0;
}
}
I think you need to update the Intent when you receive a new one by overriding onNewIntent(Intent) in your Activity. Add the following to your Activity:
#Override
public void onNewIntent(Intent newIntent) {
this.setIntent(newIntent);
// Now getIntent() returns the updated Intent
isNextWeek = getIntent().getBooleanExtra(IS_NEXT_WEEK, false);
}
Edit:
This is needed only if your Activity has already been started when the intent is received. If your activity is started (and not just resumed) by the intent, then the problem is elsewhere and my suggestion may not fix it.
Following code should work:-
int icon = R.drawable.icon;
String message = "hello";
long when = System.currentTimeMillis();
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new Notification(icon, message, when);
Intent notificationIntent = new Intent(context, MainActivity.class);
notificationIntent.putExtra("isNexWeek", true);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent pIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
notification.setLatestEventInfo(context, title, message, pIntent);
notification.flags |= Notification.FLAG_AUTO_CANCEL;
notificationManager.notify(0, notification);
In MainActivity onCreate:
if (getIntent().getExtras() != null && getIntent().getExtras().containsKey("isNextWeek")) {
boolean isNextWeek = getIntent().getExtras().getBoolean("isNextWeek");
}
So the actual reason is that the PendingIntent will cache the previous intent if the intents only differ in their extras. In my situation no combination of PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_CANCEL_CURRENT solves this as either the old intent will be replaced or the new one will stay the same as the initial one.
You need to ensure that Android cannot cache the Intents behind the PendingIntent. The solution for me is to make them differ in their data attribute.
so in the original posters code you would need to ensure that the data attribute is unique per each combination of extras that you are attaching.
Intent notificationIntent = new Intent(this, MainActivity.class);
notificationIntent.putExtra(MainActivity.IS_NEXT_WEEK, isNextWeek);
notificationIntent.setData(Uri.parse("myapp://nextWeek/" + (isNextWeek ? "1" : "0"))
Alternatively you could probably also just add a uuid to the data uri (however, if you have lots and lots of notifications, it might be nice to cache them
I am using GCMBaseIntentService in my service class which extends GCMBaseIntentService I override the method onMessage(Context,Intent).
The code goes here :
protected void onMessage(Context context, Intent intent) {
Log.i(TAG, "Received message");
//String message = getString(R.string.gcm_message);
String id=intent.getExtras().getString("event_id");
String message=intent.getExtras().getString("title");
String eventname=intent.getExtras().getString("event_name");
generateNotification(getApplicationContext(), id, message, eventname);
}
private static void generateNotification(Context context, String id, String message, String eventname)
{
int icon = R.drawable.ic_stat_gcm;
long when = System.currentTimeMillis();
NotificationManager notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new Notification(icon, message, when);
//new intent
Intent notificationIntent = new Intent(context, EventDescription.class);
notificationIntent.putExtra("event_id", id);//need this id in the eventdescription activity
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent intent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
notification.setLatestEventInfo(context, eventname, message, intent);
notification.flags |= Notification.FLAG_AUTO_CANCEL;
notificationManager.notify(0, notification);
}
The problem is that, while I click this notification and in the Eventdescription activity and extract the extras from intent and print the ID. It shows the correct value only the first time, after that for every notification it just shows the 1st value all the time. Please help!
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.notificationsfinal);
start=1;
end=15;
next=(Button)findViewById(R.id.nextbtn);
prev=(Button)findViewById(R.id.prevbtn);
statusview=(TextView)findViewById(R.id.status);
notification_list_view=(ListView)findViewById(R.id.not_listview);
updatestatus();
getNotifications();
}
private void getNotifications()
{
eventnotifierapp app=(eventnotifierapp)getApplication();
id=getIntent().getExtras().getString("event_id");
db=new MyDB(this);
}
This is my EventDescription activity where i am retreiving this event_id
Try this
PendingIntent intent = PendingIntent.getActivity(context, **uniqueKey**, notificationIntent, 0);
Please note requestCode of the getActivity of Pending intent should be unique.So just pass
unique value for every notification.You can put time stamp or even the id which you receive
from the server. I have tried this and this works.Do share your feedback
Your subsequent Intents aren't different enough, so they're being recycled. Specifically, changing the extras doesn't make a distinct Intent from the perspective of the system.
The docs for Intent.filterEquals explain that you will need to change one or more of: action, data, type, class, and categories. One approach, therefore, is to stick some distinguishing information (in your case the event_id) into the data URI; you don't have to use this URI for anything but it ensures that your intents will be distinct.
There's more info in this related question.