Notification Resume Activity - android

I know, there are several questions of this type but I tried all of it and it still doesn't work.
Ok, for my app; I've got an Activity. In this Activity, there are 4 Tabs, and the fourth one contents a list and a record button. When I am pushing record, there is a GPS Listener which starts. After getting a new gps value, it pushes it into the list.
This works so far!
If I click the Home Button it still works, if I longpress it then. It resumes that Activity with the specific Tab open and the list still hold the listitems and the gps listener is still active.
This works also fine!
Now I wanted to add a notification, which shows the count of gps values of the list as .number. On every new gps signal, it updates the notification icon with the new number. This is no problem, but the action to click on the notification totally screws up my application.
The actual code looks like this:
public void callNotify(String text) {
notif = new Notification();
Intent contentIntent = new Intent(this, tabactivity.class);
contentIntent.putExtra("fid", this.specialvalue);
contentIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
| Intent.FLAG_ACTIVITY_SINGLE_TOP);
notif.icon = R.drawable.icon;
notif.setLatestEventInfo(this, getString(R.string.app_name), text,
PendingIntent.getActivity(this.getBaseContext(), 0, contentIntent,
PendingIntent.FLAG_UPDATE_CURRENT));
notif.ledARGB = Color.RED;
notif.ledOnMS = 200;
notif.ledOffMS = 200;
notif.flags = Notification.FLAG_SHOW_LIGHTS
| Notification.FLAG_ONGOING_EVENT
| Notification.FLAG_ONLY_ALERT_ONCE;
notif.number = notifyNumber;
mNotificationManager.notify(notifyNumber, notif);
}
public void updateNotify(String text) {
notifyNumber++;
notif.number = (int) (notifyNumber / 2);
Intent contentIntent = new Intent(this, tabactivity.class);
contentIntent.putExtra("fid", this.specialvalue);
contentIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
| Intent.FLAG_ACTIVITY_SINGLE_TOP);
notif.setLatestEventInfo(this, getString(R.string.app_name), text,
PendingIntent.getActivity(this.getBaseContext(), 0, contentIntent,
PendingIntent.FLAG_UPDATE_CURRENT));
mNotificationManager.cancel((notifyNumber - 2));
mNotificationManager.notify(notifyNumber, notif);
}
So, the updateNotify() is called on a new gps signal. And the callNotify() is the first one, before it starts the gps listener. And, yeah, the notifyNumber/2 was my intention, because I work with that number further.
If I compile it like this, and click on the Notification, it opens a NEW tabactivity on the first tab. If I click back then, I get a lot of errors (database is still open, nullpointers and stuff). I think because it starts a new tabactivity and the other one is still open, 'cause I can see the gps listener is still working.
So, what I want is, that I can do the following:
I open my app, go to the tabactivity, open tab 4, click record. If I click back then, it should hide the app, also, if I just click the home button. But there is a notification.
If I click on that one, it should just show the hidden activity again and thats it.
So, what I am doing wrong there?
I thought, the Flags FLAG_ACTIVITY_CLEAR_TOP and FLAG_ACTIVITY_SINGLE_TOP should solve the problem?

What is happening here is a little confusing so bear with me here.
FLAG_ACTIVITY_SINGLE_TOP according to the docs If set, the activity will not be launched if it is already running at the top of the history stack. So if the current activity is not at the top of the history stack it will be relaunched.
FLAG_ACTIVITY_CLEAR_TOP again from the docs If set, and the activity being launched is already running in the current task, then instead of launching a new instance of that activity, all of the other activities on top of it will be closed and this Intent will be delivered to the (now on top) old activity as a new Intent.
By default the TabActivity will always open to tab 0, you can use setDefaultTab to change that via code. Each Tab in the TabHost is also a new Intent
If I compile it like this, and click
on the Notification, it opens a NEW
tabactivity on the first tab. If I
click back then, I get alot of errors
(database is still open, nullpointers
and stuff).
This is happening I think because the current Intent is tab4 (in reality its #3, 0,1,2,3) and your notification is bringing up the tabactivity.class. Since it is not active or on top of the stack, every act on top of it is closed, including tab4.
So, what I want is, that I can do the
following: I open my app, go to the
tabactivity, open tab 4, click record.
If I click back then, it should hide
the app, also, if I just click the
home button. But there is a
notification. If I click on that one,
it should just show the hidden
acitivity again and thats it. So, what
I am doing wrong there? I thought, the
Flags FLAG_ACTIVITY_CLEAR_TOP and
FLAG_ACTIVITY_SINGLE_TOP should solve
the problem?
You are confusing what the flags do and what happens with the home and back keys. Hitting home will hide your activity and the notification should work fine with those flags (once you fix the problem I mentioned earlier). When you hit back though, Android ends the current Activity and takes it off the stack. Since there is nothing under it, you are forced to relaunch from scratch when you press the notification.

Related

Android - how to open a push notification deep-link intent that, when closed, returns to the Home screen?

I've created a receiver to receive and display push notifications - when the user presses on the push notification it opens a deep-link within my application. The problem is that when the user presses "back" he doesn't exit back to the home screen, but rather he goes to whatever screens for my application were open before on the application backstack - even if the application was minimized before he pressed on the notification.
The behavior that I need is for the user to be on the home screen, for him to open the notifications panel, press on my notification, go into the deep link page in my app, and when he presses the back button - I want him to exit all the way out to the home screen again. I don't want him in any way interacting with the backstack for the main application.
I've tried numerous combinations of flags for the pendingIntent in the push notification. Everything from FLAG_ACTIVITY_TASK_ON_HOME to FLAG_ACTIVITY_NEW_TASK to FLAG_ACTIVITY_SINGLE_TOP, etc. No combination seems to give me what I want - in every single case, opening the deep link with the app minimized will always return me to the next page in the history of the app when I press the back button. How can I solve this?
Example code:
Intent notificationIntent = new Intent(this, DeepLink.class);
notificationIntent.setData(Uri.parse(url));
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_TASK_ON_HOME);
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(getBaseContext(), 1, notificationIntent, 0);
Solved. The deeplink class was starting an intent for each deeplink and these required that I set the flags NEW_TASK and CLEAR_TASK for each one. After that - everything worked.

Resuming an activity in android from notification

I'm developing an android application, and in one activity, when the user presses the HOME button, a notification appears. Upon pressing the notification the activity would resume from where it left off. The problem is that the activity is recreated each time. Upon pressing the notification onDestroy() and then onCreate() is called. But say if I reopen the activity through the "Recent apps" it resumes successfully.
This question has been asked before on stackoverflow and I have tried the answers provided and none of them seem to work. The API that I'm using is the latest 4.4. The options I have tried are:
Playing around with the Intent flags
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP| Intent.FLAG_ACTIVITY_SINGLE_TOP);
Setting the activity to singleInstance and singleTask
How can I mimic the intent that is sent when I open my activity through 'Recent apps'?
EDIT: One more caveat that might be important. There's 3 activities in my program A B C. When clicking on the launcher icon activity A is first started. The notification is created only when going from activity C to Home. I'm trying to resume activity C.
Problem solved.
I was debugging the application through LogCat and looking at the intents that were being generated by the ActivityManager. Whenever I was changing the flags of the Intent, I wouldn't see the change in LogCat. So
02-12 11:26:39.586: I/ActivityManager(766): START u0 {flg=0x1000c000 cmp=com.example.app/.controllers.Activity3 bnds=[0,153][1080,345]} from pid -1
Changing the Intent flags didn't change the flg variable in the log. Apart from this, the notification image was staying in the Status bar, my app wasn't destroying it. What I did was add the PendingIntent.FLAG_CANCEL_CURRENT flag to the PendingIntent I was sending:
Intent intent = new Intent(this, Activity3.class);
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,
intent, PendingIntent.FLAG_CANCEL_CURRENT);
mBuilder.setContentIntent(pendingIntent);
So the problem was an incorrect PendingIntent that I must have created before, that was never being removed. Now I'm able to resume the activity by clicking the notification. Hope this helps someone that might have a similar issue.

Appwidget with collection. Illegal working

I have appwidget with listview. Some information we can see here
1) This widget don't worked on 2.x. But user on this devices see this widget at his list and can move it at screen. After he get error. Can I any way to hide this widget on 2.x? Ofcouse, I can set title for this widget as "MyWidget... (3.x-4.x). But I think this is not good.
2) Second issue. On click widget I open my application one activity (widgetAct). This is not main activity. widgetAct showed as dialog. All works, but... If I open main activity, next click HOME, not BACK. Now click on widget, opened my widgetAct, but on background I see also main activity.
3) Another case. Open widgetAct. See this activity. Click BACK. Now long press: see last started application. Click on my application (which contain widgetAct) and see this widgetAct. But want see main activity or any another activity my application, but not widgetAct.
I try different cases: add FLAG_ACTIVITY_NO_HISTORY, FLAG_ACTIVITY_NEW_TASK, FLAG_ACTIVITY_CLEAR_TOP. But nothing help:
Intent i = new Intent(ctx, myActivityCls); i.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId);
i.setFlags(i.getFlags() | Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pi = PendingIntent.getActivity(ctx, 0, i, PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(viewId, pi);
I see, that my widgetAct on open have only FLAG_ACTIVITY_NEW_TASK flag.
I don't know why, but... I set some flags to intent and start activity on click widget. Really opened activity have only FLAG_ACTIVITY_NEW_TASK.
Solutions:
1) Move widget xml provider from xml folder to xml-v11. Now on 2.x devices this widget is hided.
2) Second case: set for widgetAct taskAffinity. But in this case at recent apps I see 2 my application instances, because used 2 stack activities. To fix it add to widgetAct:
#Override
protected void onPause() {
super.onPause();
finish();
}
3) On click at widget open widgetAct. I close this instance widgetAct and open another widgetAct, but add next flags: FLAG_ACTIVITY_NO_HISTORY, FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS.

SINGLE_TOP | CLEAR_TOP seem to work 95% of the time. Why the 5%?

I have a nearly-finished application with a non-trivial activity structure. There are push notifications associated with this app, and selecting the notification entry is supposed to bring up a specific activity regardless of whether the app is foreground/background/not active.
If the app is not active, I have been able to successfully start the app and auto-navigate to the appropriate part. However, when the app is active, I have a problem. I will present a simplified version of the issue, to communicate the nature of the problem, and I will post the details of my app's activity structure and relevant code as needed (actually, working on that now).
So, my app's activity stack (greatly simplified) looks like this:
A -> B -> X
Where A, the root activity, is a login page; B is something of a "home page" and X is one of several activities that can be started from the home page (but only one instance active at a time; as these can only be started from B).
When the notification is selected, I need the application to automatically navigate to B, regardless of what state it was in beforehand - whether [A], [A -> B], [A -> B -> X] or [ ] (app not active).
My notification passes an Intent to activity A. I have tried using CLEAR_TOP and NEW_TASK flags, and none. A currently has launchmode=singleTask. Doing this, I figure I am addressing all possible existing stack configurations and reducing them to [A]. The Intent also carries an extra which identifies it as coming from a notification, as opposed to a usual launch.
Activity A, upon identifying the Intent as being sent from the notification (it can do this in both onCreate() and onNewIntent() ), sends an Intent to Activity B. This Intent contains CLEAR_TOP and SINGLE_TOP. B has launchmode=singleTop.
95% of the time, this works as desired, and after pressing the notification, the app's stack is [A -> B].
Roughly 5% of the time, the app somehow ends up with a stack of [A -> B -> B].
Any ideas on what's happening here, or anything I'm doing wrong?
I'll post more detail if this turns out to be a non-trivial problem. In fact, posting more details now...
~~~~~~~~~~~~~~~~~~~~~~~MORE DETAIL~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Stepping through the debugger shows that, every time A sends its intent to B, the existing instance of B is onDestroy()'d before being onCreate()'d and then also having its onNewIntent() called. This seems odd to me, and suggests that either I misunderstand the flags I am using (CLEAR_TOP and SINGLE_TOP), or something else is interfering with them.
I have not successfully reproduced the erroneous stack structure in debug. Not sure if it's because it doesn't happen in debug, or I just haven't tried enough times.
Code for Intents being made:
In the C2DM receiver service:
protected void onMessage(Context context, Intent intent) {
int icon = R.drawable.some_drawable;
CharSequence tickerText = "blah";
long when = System.currentTimeMillis();
Notification notification = new Notification(icon, tickerText, when);
//Context context = getApplicationContext(); //Don't need this; using the context passed by the message.
CharSequence contentTitle = intent.getStringExtra("payload");
CharSequence contentText = "Lorem ipsum dolor si amet,";
Intent notificationIntent = new Intent(this, LoginPage.class);
//notificationIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK); //Tried with and without
notificationIntent.putExtra(PushManager.PUSH_INTENT, PushManager.PUSH_INTENT); //Indicator that this was send from notification
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);
notificationManager.notify(PushManager.ALARM_NOTIFICATION_ID, notification);
}
In LoginPage (Activity A), after successful login:
Intent i = new Intent(LoginPage.this, TabHomePage.class);
// (If we're automatically going to tab 2, inform next activity)
if(fromNotification) {
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
i.putExtra(TabHomePage.TAB_NUMBER, TabHomePage.TAB_2);
}
startActivity(i);
For more detail on the activity stack structure, here's the picture:
http://i89.photobucket.com/albums/k207/cephron/ActivityStack.png
And here's the thousand words:
Activity A is a login page; upon successful login, it starts B.
B is a TabActivity, which contains three Activities within it (represented by C, D, E).
Each of C, D, and E is actually an ActivityGroup whose child Activities mimic the usual stack behaviour of Activities.
So, each tab contains its own stack of activities, and switching between tabs changes which of these stacks is currently being pushed to/popped from by the user's navigation (each tab contains a stack of ListActivities browsing through a hierarchical structure of entities). These can also start new activities beyond the giant 'B' TabActivity (represented by X).
So, upon logging in from Activity A, at least three activities are created before more user input is accepted:
-B is created (and is seen, because of the TabWidget now at the top of the screen)
-One of the ActivityGroups is created: whichever one belongs to the default tab. This ActivityGroup remains unrepresented on screen, however...it only shows the top activity of its stack of child activities.
-So, finally, the "root" activity of that ActivityGroup's stack is created (in the picture, F is an example of such an Activity). This Activity shows itself below the TabWidget.
After each tab has been visited once, no more Activities are created/destroyed by switching between tabs (not counting memory kills).
Pressing back in any tab finish()es the Activity at the top of that stack, showing the one beneath it.
Pressing back from the root activity (like F) in any tab finishes the whole TabActivity, sending the user back to A.
The intent passed to B also instructs it to automatically navigate to a different tab than the default. In the case where we end up with a stack of [A -> B -> B], the first B is navigated to the correct tab, and the second is at the default.
TL;DR; Don't use CLEAR_TOP with SINGLE_TOP at the same time
If it only produces an error 5% of the time, it is likely to be a concurrency issue. You said you have SINGLE_TOP | CLEAR_TOP for calling Activity B. CLEAR_TOP destroys the current instance of Activity B and the intent is delivered to onCreate(). SINGLE_TOP doesn't destroy the current instance of Activity B, and delivers the intent to onNewIntent().
When the SINGLE_TOP flag is read first, the intent is delivered to the current instance of Activity B calling onNewIntent(). Then CLEAR_TOP is read and Activity B is destroyed and a new instance is created with onCreate() and everything works fine.
When CLEAR_TOP is read first, the existing instance of Activity B is destroyed and a new one is created with onCreate(). Then SINGLE_TOP is read and the intent is delivered to onNewIntent() as well. Again, it works out.
When CLEAR_TOP and SINGLE_TOP are read at the same time, the current instance of activity is destroyed and CLEAR_TOP calls onCreate() and SINGLE_TOP calls onCreate() as well, because no instance of Activity B exists at the moment. Thus, you end up with A->B->B.

Android - When launch the same activity from widget with different extras, how to prevent the same instance show up after returned from HOME button?

I have a widget that contains 4 buttons to show 4 stock prices, each of them will launch into the same activity Quote.class to show stock details. In onUpdate(), it will set up the pendingIntent with extras with stock symbol. After I hit button A, it goes to Quote activity that shows stock A. Then I hit the BACK button to the homescreen, Quote activity calls onDestroy() and when I hit button B, stock B will show properly. However, when i hit HOME button after it shows stock A, the Quote activity only calls onStop without calling onDestroy(), then as i hit button B, it will call onStart() and it shows the same instance that shows stock A.
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.etappwidget);
setQuoteIntent(context, views, R.id.view1, "BAC", 1);
setQuoteIntent(context, views, R.id.view2, "C", 2);
setQuoteIntent(context, views, R.id.view3, "GOOG", 3);
setQuoteIntent(context, views, R.id.view4, "AAPL", 4);
private static void setQuoteIntent(Context context, RemoteViews views, int viewId, String symbol, int requestCode) {
Intent i = new Intent(context, Quote.class);
i.putExtra("SYMBOL", symbol);
i.setFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
PendingIntent pi = PendingIntent.getActivity(context, requestCode, i, PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(viewId, pi);
}
Originally I thought adding a flag in the Intent should solve this problem. But I have tried
i.setFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK or FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_NO_HISTORY), none of them makes any difference.
So is there any ways to make it work? How can i remove the history stack from HOME button? How can I call onCreate in Quote activity and get new extras when i hit button B? Any help is appreciated. Thanks
It is normal for onDestroy to possibly not get called if you do simple task switching (like holding the HOME button). If you need to do clean-up, it needs to go in onPause.
I believe the problem is that you have a PendingIntent that only differs by extra. PendingIntents are cached, so if you use two with the same action and data, they'll overwrite each other. You can circumvent that by giving each some random data. Try passing the symbol in the data rather than through the extra (which is preferred anyway).
You can try this:
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
Your activity will not be seen in the history stack
clickIntent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
Since: API Level 1 If set, the new activity is not kept in the
history stack. As soon as the user navigates away from it, the
activity is finished. This may also be set with the noHistory
attribute.
This solved the same issue of mine while implementing widget activities.
When you press home, most probably the activity will not be destroyed. It is put to pause state in such case. So, I guess your code to initiate the stock view would stationed in onCreate rather than onResume. So, moving those to onResume should solve the problem.
If you are using a different Action in your Intent and use the SingleTop or similar flag and override onNewIntent to detect the correct action that should do the trick. You need to be prepared to handle the intent in onCreate and onNewIntent.

Categories

Resources