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);
}
Related
I'm using Intents to save data and recover them in others places of my application. I have used them in others places, but now, it's not working as I hope.
public class GCMIntentService extends GCMBaseIntentService {
public GCMIntentService() {
super(ConstantsGCM.GCM_SENDER_ID);
}
#Override
protected void onMessage(Context context, Intent intent) {
...
String ns = Context.NOTIFICATION_SERVICE;
NotificationManager notManager = (NotificationManager) context.getSystemService(ns);
String room = intent.getExtras().getString(ConstantsGCM.GCM_ROOM);
Intent notIntent;
PendingIntent contIntent;
Notification notif;
notif = new Notification(icon, textStatus, time);
notIntent = new Intent(contexto,RoomsActivity2.class);
Bundle b2 = new Bundle();
b2.putString(ConstantsRooms.ROOM, room);
notIntent.putExtras(b2);
contIntent = PendingIntent.getActivity(contexto, 0, notIntent, 0);
notif.setLatestEventInfo(contexto, tittle, description, contIntent);
notif.flags |= Notification.FLAG_AUTO_CANCEL;
notManager.notify((int)(Math.random()*1000), notif);
This code is executed when a notification is coming. When I click this notification, it's executed the Activity RoomsActivities2.class. Here, I just call this code:
public String getMessageString(String cod){
String result = "";
bundle = getIntent().getExtras();
if (bundle != null){
result = bundle.getString(cod);
}
return result;
}
But, I didn't get the last data saved in the Intent. What's it wrong? I guess that I'm not using it correctly. Why can't I get the data from the activity?
What I think that it's happening it's:
The application gets a lot of notifications, the first one works right. But, if I keep getting more notifications, the data isn't override and I always get the first one although when I debug the code, I'm setting the another data.
OK, it's been a while since I've worked with pending intents, but I remember two things:
replace:
contIntent = PendingIntent.getActivity(contexto, 0, notIntent, 0);
with:
contIntent = PendingIntent.getActivity(contexto, 0, notIntent, PendingIntent.FLAG_UPDATE_CURRENT);
That will keep the bundle around.
BUT that flag will override any existing pending intents with the newest one, you might not want that.
If you have multiple pending intents from the same context with the same intent (but different bundles!), you can use the 2nd parameter.
contIntent = PendingIntent.getActivity(contexto, requestCode, notIntent, PendingIntent.FLAG_UPDATE_CURRENT);
as long as every pending intent has a unique requestCode, and even though the google dev's docs say the parameter isn't used, it actually does serve a purpose for identifying pending intent and allows duplicates with different bundles.
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.
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.
Wasn't really sure how to search for this...
I have a the following which is called whenever a job is added or removed from my queue to put a notification in the status bar:
private void showNotification()
{
int jobsize = mJobQueue.size();
int icon = (jobsize == 0) ?
android.R.drawable.stat_sys_upload_done :
android.R.drawable.stat_sys_upload;
Notification notification =
new Notification(icon, "Test", System.currentTimeMillis());
Intent intent = new Intent(this, FileManagerActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
notification.flags =
(Notification.FLAG_SHOW_LIGHTS | Notification.FLAG_AUTO_CANCEL);
notification.setLatestEventInfo(this,
"Uploading to our servers",
getString((jobsize > 0) ?
R.string.notification_active_transfers :
R.string.notification_no_transfers),
pendingIntent);
mNotifyManager.notify(NOTIFICATION, notification);
}
As it is now the behavior is this:
if the user logs out and hits the notification, it will still open a new FileManagerActivity (ops!) I could get around this by starting at my authentication activity and passing the intent up my stack in a natural order, its when the application is already running is where I have difficulties.
if the user already has the FileManagerActivity open clicking the notification will put a second instance over it. In this case, I want the currently running FileManagerActivity to recieve focus instead of launching a new instance.
How could I get the correct behavior?
I've done this before by setting my Activity to use the launch mode 'singleTop' in the Application Manifest. It will achieve the desired function, using the existing activity if one exists. In this case, onNewIntent will be called in your activity.
You'll need to check in your FileManagerActivity for authentication and start a new activity as appropriate if the user is not logged in.
I think Worked when added these:
intent.setAction(Long.toString(System.currentTimeMillis()));
PendingIntent.FLAG_UPDATE_CUR
Intent intent = new Intent(context, MyOwnActivity.class);
intent.putExtra("foo_bar_extra_key", "foo_bar_extra_value");
intent.setAction(Long.toString(System.currentTimeMillis()));
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0,intent,PendingIntent.FLAG_UPDATE_CURRENT);
My target: download files in parallel, and when file downloads complete, I get notifications.
Those notifications are suppose to launch an activity when you click on it which gets unique parameters through putExtra.
The problem is that I can't have different values in each launch of that activity.
Each time the activity, which is being launched through the notification bar, launches it destroys the extra of the ones which haven't been launched yet (the ones that still appear on the notification bar).
How do I keep all my notifications with their own parameters?
Here is my code:
if (messagesManager == null)
{
messagesManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
}
notification = new Notification(R.drawable.icon, message, System.currentTimeMillis());
// for launch activity
Intent intent = new Intent(context, DialogActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.putExtra("fileName", fileName); //- this is where i put my extra's!!
intent.putExtra("onSdcard", onSdcard);
PendingIntent contentIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
notification.setLatestEventInfo(context, "DownloadManager", message, contentIntent);
notification.flags = notification.FLAG_AUTO_CANCEL;
int noticeId = generateNotificationId(requestId);
messagesManager.notify(noticeId, notification);
Now this is the dialog activity:
protected void onCreate(Bundle savedInstanceState)
{
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
Intent i = getIntent();
boolean onSdcard = i.getBooleanExtra("onSdcard", true);
String fileName = i.getStringExtra("fileName");
...
}
I tried to use this technique as it was written in another post here, but it didn't work.
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
Please check the linked duplicate,
you need two things
you need to add an action string
the action string must be unique, probably a timestamp added to it would be good