passing variable to an activity through an Intent is always the same - android

My application receives a C2DM message and sends a status bad notification with the C2DM message. So far so good.
When the user clicks on the notification, an activity is called, passing the C2DM message as a variable.
Now, the first time it works smoothly, the second time the variable passed is not refreshed. It's always the first variable passed.
Am I missing something?
Here are the snipperts:
C2DM Notification
Intent notificationIntent = new Intent(context, BMBPad.class);
notificationIntent.putExtra("seqid", message);
PendingIntent contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);
This is how I read the variable in the Activity called by the Intent.
extra = this.getIntent().getExtras();
seqidi = extra.getString("seqid");
Anyone any idea why that happens?

You need to use the flag PendingIntent.FLAG_UPDATE_CURRENT
In your case:
PendingIntent contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Please also have a look here: Android PendingIntent

You can try to append this snippet in the Activity called by the Intent.
/**
* Override super.onNewIntent() to let getIntent() fetch the latest intent
* that was used to start this Activity rather than the first intent.
*/
#Override
public void onNewIntent(Intent intent){
super.onNewIntent(intent);
setIntent(intent);
}

override onNewIntent() method, get your variable like this:
#Override
public void onNewIntent(Intent intent){
super.onNewIntent(intent);
seqid = intent.getStringExtra("seqid","");
}
because start the activity again will trigger onNewIntent() method.

Related

Android - Do job onClick Notification?

How can on i process specific method when i press on notification without open activity while application is opened by user?
Intent intent = new Intent(this, MainActivity.class);
intent.putExtra("frame", 1);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(contentIntent);
You ask how to read your extras from intent? You should implement onNewIntent() in your activity and handle incoming Intent there. If you got more code that handles intent content then it's good to make it separate method:
#Override
public void onCreate(Bundle savedState)
{
super.onCreate(savedState);
dealWithIntentData(getIntent());
}
#Override
protected void onNewIntent(Intent intent)
{
super.onNewIntent(intent);
dealWithIntentData(intent);
}
protected void dealWithIntentData(Intent intent) {
...
}
You can create a different PendingIntent depending on what you need to do. In your snippet you are starting an activity by calling
PendingIntent.getActivity(this, 0, intent,PendingIntent.FLAG_UPDATE_CURRENT);
You can start a service by calling
PendingIntent.getService(), or send a broadcast by calling PendingIntent.getBroadcast()
More specifically to your question, if you don't want to be depended on any activities, try sending a Broadcast (with getBroadcast) and execute any logic on the Broadcast's onReceive()
More info # http://developer.android.com/reference/android/app/PendingIntent.html
I don't fully understand your question, but maybe do you want to make a broadcast Receiver & handle some action in it?
You can use PendingIntent.getBroadcast method for that.
So, using broadcast you can start activity from receiver, or, if receiver is inside activity, handle something
Intent intent = new Intent(this, MainActivity.class);
intent.putExtra("frame", 1);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
int frame = intent.getIntExtra("frame", 0);
// TODO your code...
}

PendingIntent does not send Intent extras

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

Implement setOnClickPendingIntent from notification

I build custom notification that contain button and i want to listin when user press on it.
The button should not open any activity but only logic staff like change song.
the Code:
RemoteViews contentView = new RemoteViews(getPackageName(), R.layout.notification);
contentView.setTextViewText(R.id.toptext, nowPlayingTitle);
//this not work
Intent intent = new Intent(this, receiver.class);
intent.putExtra("UNIQ", "1");
PendingIntent pendingIntent = PendingIntent.getBroadcast(
this.getApplicationContext(), 234324243, intent, PendingIntent.FLAG_CANCEL_CURRENT)
contentView.setOnClickPendingIntent(R.id.imageButtonPlay,
pendingIntent);
notification.contentView = contentView;
// this is to return to my activity if click somwhere else in notification
Intent notificationIntent = new Intent(this, MYACTIVITY.class);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.contentIntent = contentIntent;
mNotificationManager.notify(NOTIFICATION_ID, notification);
I don't get the hang of the setOnClickPendingIntent what need to be in the second param?
How can i just call a function after user press on the button?
im probably missing something cause i dont understand the receiver side and what happend after user press
You are missing the fact that the button you created actually doesn't belong to your application. It is created in another context, in another process. There is no way it can call your function.
Instead, when the user taps the button, that pending intent is fired. You can catch it by your receiver (in your activity), check some parameters and do the action.
Or you can implement a service and handle this intent in background. I'd prefer this way.
thanks for quick answer. I try using receiver but it never fired.
The code is in the main question and i created for the reciever class the following code:
public class receiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
Bundle bundle = intent.getExtras();
}
}
but click on the notification never fire the receiver ( Test on debug mode )

Android getIntent() returns the first intent

I have developed an application to download a video file and store it in the SD card. In the process I also update the progress and status of the download as a status bar notification using the NotificationManager.
My class called the DownloadTask.java extends the AsyncTask. So here I update the progress using the onProgressUpdate() method where in I use the NotificationManager for the purpose. Everything works like a charm except, on completion of download I want to click the notification to open the specific video file. So this is what i have done:
mNotificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
int icon = android.R.drawable.stat_sys_download_done;
long when = System.currentTimeMillis();
mNotification = new Notification(icon, "", when);
mContentTitle_complete = mContext.getString(R.string.download_complete);
notificationIntent = new Intent(mContext,OpenDownloadedVideo.class);
notificationIntent.putExtra("fileName", file);
mContentIntent = PendingIntent.getActivity(mContext, 0, notificationIntent, 0);
mNotification.setLatestEventInfo(mContext, file, mContentTitle_complete, mContentIntent);
mNotification.flags = Notification.FLAG_AUTO_CANCEL;
mNotificationManager.notify(NOTIFICATION_ID, mNotification);
Note that the fileName and NOTIFICATION_ID are unique in my case.
The Activity OpenDownloadedVideo.java opens the file by:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
fileName = getIntent().getExtras().getString("fileName");
Intent i = new Intent(Intent.ACTION_VIEW);
File videoFileToPlay = new File(Environment.getExternalStorageDirectory()+"/MyFolder"+"/"+fileName);
i.setDataAndType(Uri.fromFile(videoFileToPlay), "video/*");
startActivity(i);
finish();
} catch(Exception e) {
//
}
}
So when I download a video for the first time and click on the notification the appropriate video file will be opened. However next time when I download another video, and click on the notification the first file which was downloaded will be opened again.
This is because getIntent inside OpenDownloadedVideo returns the first Intent created and not the latest. How can I correct this?
Also, please note that the problem scenario exists when I download more than one video, e.g. if I download five different video files and there are five notifications in the status bar. The same file will be opened each time a notification is clicked.
/**
* Override super.onNewIntent() so that calls to getIntent() will return the
* latest intent that was used to start this Activity rather than the first
* intent.
*/
#Override
public void onNewIntent(Intent intent){
super.onNewIntent(intent); // Propagate.
setIntent(intent); // Passing the new intent to setIntent() means this new intent will be the one returned whenever getIntent() is called.
}
actually you just need create PendingIntent with PendingIntent.FLAG_UPDATE_CURRENT ,like this:
mContentIntent = PendingIntent.getActivity(mContext, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
From the Android Activity.onNewIntent() documentation
Note that getIntent() still returns the original Intent. You can use setIntent(Intent) to update it to this new Intent.
So when you get the new Intent, you need to explicitly set it as the activity intent.
#Alex and #Codinguser, thank you for your replies. Much appreciated. However I found a different answer that worked for me. When creating a PendingIntent for the Intent pass a unique value to it. In my case I was doing this:
mContentIntent = PendingIntent.getActivity(mContext, 0, notificationIntent, 0);
but now I'm using NOTIFICATION_ID since it was unique. I've changed the above call to:
mContentIntent = PendingIntent.getActivity(mContext, NOTIFICATION_ID,
notificationIntent, 0);
That's all and it works.
I found some information on it in the question
Mulitple Instances of Pending Intent
What if you make your OpenDownloadedVideo activity SINGLE_TOP and override onNewIntent?
in the activity you're intent is launching.
Add (override) the following function:
#Override
protected void onNewIntent(final Intent intent) {
super.onNewIntent(intent);
this.setIntent(intent);
}

getIntent() Extras always NULL

I wrote a simple Android App that show a custom Notification like this:
Context context = getApplicationContext();
NotificationManager manager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
Notification notification = new Notification( R.drawable.icon, title, System.currentTimeMillis());
Intent notificationIntent = new Intent( context, this.getClass());
notificationIntent.putExtra("com.mysecure.lastpage", "SECURECODE");
PendingIntent pendingIntent = PendingIntent.getActivity( context , 0, notificationIntent, 0);
notification.flags = notification.flags | Notification.FLAG_ONGOING_EVENT;
notification.contentView = new RemoteViews(context.getPackageName(), R.layout.notifypbar);
notification.contentIntent = pendingIntent;
notification.contentView.setTextViewText(R.id.notifypb_status_text, text);
notification.contentView.setProgressBar(R.id.notifypb_status_progress, 100, (int)(100*progress), false);
manager.notify(104, notification);
This piece of code is called ONLY ONCE in my application and it displays a notification with a progress bar (all correctly).
Now, when a user clicks on this notification my application handles the onResume event.
public void onResume()
{
super.onResume();
// TODO: Extras è SEMPRE NULL!!! impossibile!
Intent callingintent = getIntent();
Bundle extras = callingintent.getExtras();
but extras is always NULL!
I've tried any combination of:
notificationIntent.putExtra("com.mysecure.lastpage", "SECURECODE");
or
Bundle extra = new Bundle();
extra.putString(key, value);
notificationIntent.putExtra(extra);
but getIntent().getExtras() returns always NULL.
This is the scenario:
The method getIntent() returns the FIRST intent than launch activity.
So, when the activity is CLOSED (terminated) and the user clicks on the notification, it will run a new instance of the activity and getIntent() works as expected (Extras is not null).
But if the activity is "sleeping" (it is in the background) and the user clicks on the notification, getIntent() always returns the very FIRST intent that started the activity and NOT the notification intent.
So to catch the notification intent while the application is running, simply use this
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
and then override onNewIntent(Intent newintent).
So when an application first runs, getIntent() can be used and when application is resumed from sleeping, onNewIntent works.
Just Write this code above your on top of your Resume() method. This is all it takes. This refreshes intent - I don't really know, but it works.
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
}
Problem: You are sending the same request code for your pending intens. Change this.
Solution: Set global variable int UNIQUE_INT_PER_CALL =0 and when you create pendingIntent call like below.
PendingIntent contentIntent = PendingIntent.getActivity(context, UNIQUE_INT_PER_CALL, notificationIntent, 0);
UNIQUE_INT_PER_CALL++; // to increment.
Since it seems your activity is already running, I think you need to specify FLAG_UPDATE_CURRENT, otherwise the getIntent() call will return the previous one. See this answer.
Look at Shared Preferences for passing and retrieving persistent key/value pairs.

Categories

Resources