Relaunching activities in Android - android

I'm a newbie in Android developing and after reading the documentation about tasks and activities I can't get my application working correctly.
(First of all, sorry for my English)
My application consist of two activities: LOGIN and NEWS. Both activities launching method is singleTask.
The NEWS activity creates a notification with onCreate with the standard notification code of the Android notification tutorial!.
int icon = R.drawable.notification_icon; // icon from resources
CharSequence tickerText = "Hello"; // ticker-text
long when = System.currentTimeMillis(); // notification time
Context context = getApplicationContext(); // application Context
CharSequence contentTitle = "My notification"; // expanded message title
CharSequence contentText = "Hello World!"; // expanded message text
Intent notificationIntent = new Intent(this, MyClass.class);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
Notification notification = new Notification(icon, tickerText, when);
notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);
When I first open the application:
LOGIN --> onResume() --> NEWS --> onCreate() --> Notification
With the code
Intent newLogAct = new Intent(Login.this, News.class);
TomTuckerActivity.this.startActivity(newLogAct);
If I hit Back *NEWS* is destroyed and again:
LOGIN --> onResume() --> NEWS --> onCreate() --> Notification
(I don't like that loop, the reason of using it is explained at the end)
If I hit Home I go back to the main menu and here begin what I don't understand:
If I use the notification to relaunch the application there is no problem and NEWS window is opened again without calling onCreate and without sending the notification.
If I use the application icon when calling NEWS the singleTask option seems to be useless because onCreate() is called again and the notification is sent again.
What I want is to recover the application where I left it either I use the notification or the icon.
May a flag in the newLogAct will solve the problem?
Is OK tho have singleTask launching option in both activities?
About the Back button loop problem:
To avoid the loop I thought about using onCreate() instead of onResume(). However, when I relaunches the application with the application icon LOGIN is loaded but onCreate is not called so NEWS is not loaded.
Is there any other way to solve that?
Maybe with onNewIntent() method?

Your problem (or at least a part of it) seems to be: How to make a notification come back where you left the application.
Notification are not supposed to be used this way, clicking on a notification should start a new activity whose aim is to deal with the notification.
If you do want to come back to the application where you left it (I’m doing it), you can use the following trick (I don’t know if this is good practice, but it works and does not seems that hackish) : create an Activity called Autodestruct which call finish() in its onCreate() method, and make the notification run this Activity. This will restore the back stack with a dummy Activity on top of it and remove the dummy Activity immediately.

Related

Changing default style in notification list to BigTextStyle

I have a method which receives text from a push notification, via the Parse API, and packages it into a notification object. Pretty standard stuff. My problem is that I'm trying to use a BigTextStyle to display my notification in the list, but it refuses to do so, and only shows one line of text and the two-finger gesture does not cause it to expand.
However, if I tap the notification, which opens the app, then return to the notification list, it is displayed in the BigTextStyle and is responsive to gestures. So, my guess is that somehow tapping on the notification is activating it and allowing the BigTextStyle code to kick in.
I like that tapping on the notification opens the app, but I don't want to force my users to open the app then close it again to see the full text of my messages. So is there a way I could either make the notification display in the BigTextStyle format from the start, or to make it so that the first click "activates" the notification, allowing the full message text to be seen, and then a second click opens the app? Any help would be appreciated.
Here is my code from the Notification method:
public void receiveNotification() {
NotificationCompat.BigTextStyle bts = new NotificationCompat.BigTextStyle();
bts.bigText(SplashActivity.globalDataString);
bts.setSummaryText("Tap to open app, swipe to dismiss message");
NotificationCompat.Builder m = new NotificationCompat.Builder(this);
m.setContentTitle("New Push Notification")
.setContentText(SplashActivity.globalDataString)
.setSmallIcon(R.drawable.app_icon)
.setStyle(bts)
.build();
Intent openApp = new Intent(this, MenuActivity.class);
// This ensures that navigating backward from the Activity leads out of
// the application to the Home screen.
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
// Adds the back stack for the Intent (but not the Intent itself)
stackBuilder.addParentStack(MenuActivity.class);
// Adds the Intent that starts the Activity to the top of the stack
stackBuilder.addNextIntent(openApp);
PendingIntent resultPendingIntent =
stackBuilder.getPendingIntent(
0,
PendingIntent.FLAG_UPDATE_CURRENT
);
m.setContentIntent(resultPendingIntent);
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// mId allows you to update the notification later on.
mNotificationManager.notify(pushMessageID, m.build());
pushMessageID++;
//reset notification
flag1 = false;
}
EDIT: I think my problem is with where I'm calling my receiveNotification() method from. Right now I have it in the onCreate() method of my app's starting activity, which doesn't make much sense looking back. Should I put it in my broadcastReceiver class, or would there be a better place to put it?
Yes, the creation and display of the notification is usually done either in the broadcast receiver, or in an intent service started by the broadcast receiver. Only when the user taps the notification, the relevant activity is launched. You can see Google's client code sample here.

How to start an app the same way Android Launcher does (resume)

There are a lot of questions/answers about how to start an application from within your application in Android. But those solutions do not produce the same flow as if an icon was tapped in Android launcher.
For example, I do this (this is used with notifications):
intent = context.getPackageManager().getLaunchIntentForPackage("com.test.startup");
intent.setAction(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
pendingIntent = PendingIntent.getActivity(context, 0,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
Then when I tap on notification the app is started, however, it is started somewhat differently than when I tap the icon in the App drawer. Specifically: with this approach my main Activity is always created (i.e. onCreate() then onResume() is called). However, if application was already started and then put in background, then starting it from Launcher will only cause onResume() of currently shown activity to be called (not onCreate() on the main one). Is there a way to trigger the same resume flow programmatically from within my app?
To summarize the task: when user taps on notification I need my app to be either started (if it's not already), or brought to the foreground in its current state (if it's in background) and have some data passed to it. The app will then take care of handling/rendering that data.
Your app is behaving the way it supposed to. Even if you try the launch the app from App drawer it will call the same callback. You have to understand the lifecycle. As your activity is in the background onCreate will not get called. But for the handling the data from the notification intent you should utilize callback method OnNewIntent() in activity. You should override this method and extract the data the from the new intent and should update UI. After onNewIntent onresume will be called.
I hope this solves your problem.
Here is my onPause code which works the way you expected i.e when user clicks on the notification it doesnt call onCreate again:
notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
intent = new Intent(getApplicationContext(), PlayerActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP| Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent pIntent = PendingIntent.getActivity(getBaseContext(), 0, intent,0);
NotificationCompat.Builder noti =
new NotificationCompat.Builder(this)
.setSmallIcon(android.R.drawable.ic_media_play)
.setContentTitle("Nepali Music And more")
.setContentText("Playing");
noti.setContentIntent(pIntent);
noti.setAutoCancel(true);
noti.setOngoing(true);
Notification notification = noti.getNotification();
notificationManager.notify(1, notification);
Focus mainly on the intent flags
You want to use the intent flags Intent.FLAG_ACTIVITY_CLEAR_TOP to find your activity and clear the stack above it. You also need the Intent.FLAG_ACTIVITY_SINGLE_TOP flag to prevent your activity from being recreated (to resume).
The Intent.FLAG_ACTIVITY_SINGLE_TOP is necessary since by default, the launch mode is "standard" which lets you create multiple instances of your activity. If you were to set your launch mode to SingleTop, then this flag own't be necessary

Change notification intent in Android

I have a service that shows a notification that I wish that will be able to go to a specific activity of my app each time the user presses on it. Usually it would be the last one that the user has shown, but not always.
If the activity was started before, it should return to it, and if not, it should open it inside of the app's task, adding it to the activities tasks.
In addition, on some cases according to the service's logic, I wish to change the notification's intent so that it will target a different activity.
How do i do that? Is it possible without creating a new notification and dismissing the previous one? Is it also possible without creating a new task or an instance of an activity?
No it wouldn't be possible to change the Activity once you have sent the notification.
You can start an Activity on your task stack that is not a problem, check out the notification service in the tutorial here:
http://blog.blundell-apps.com/notification-for-a-user-chosen-time/
You have to set a pending intent on the notification:
// The PendingIntent to launch our activity if the user selects this notification
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, SecondActivity.class), 0);
// Set the info for the view that shows in the notification panel.
notification.setLatestEventInfo(this, title, text, contentIntent);
You can see the pending intent takes a normal intent "new Intent(this, SecondActivity.class" so if you want specific behaviour (like bringing to the top instead of starting a new activity. Add the flags like you would normally to this intent. i.e. FLAG_ACTIVITY_REORDER_TO_FRONT (something like that)
Since platform version 11, you can build a notification using Notification.Builder. The v4 support library has an equivalent class NotificationCompat.Builder.
You can't change the Activity once you've sent the notification, but you can update the notification with a new Intent. When you create the PendingIntent, use the flag FLAG_CANCEL_CURRENT. When you send the new notification, use the ID of the existing notification when you call NotificationManager.notify().
Also, you should be careful how you start your app. The Status Bar Notifications guide tells you how to set up the back stack.

Android SDK. Get NOTIFICATION_SERVICE to resume, not start new instance

I am really moving forward with my android application. I was able to implement onDestroy() and onPause() routines.
I have also managed to get Android's notification service to place my icon with title and body in the notification bar/task menu.
The only problem with this notification service is that if my android app is already running, and has initiated the onPause() function that super.onPause(); moveTaskToBack(true);, if a users taps the notification, it will bring up a NEW instance of my app.
Once the user interacts with the new instance, the program will crash because the background version is already running, causing conflicts.
Here's my notification code, I need help in making this code look for an already running version of my app:
String ns = Context.NOTIFICATION_SERVICE;
NotificationManager mNotificatonManager = (NotificationManager) getSystemService(ns);
int icon = R.drawable.ic_launcher;
CharSequence tickerText = "app name";
long when = System.currentTimeMillis();
CharSequence contentTitle = "app title";
CharSequence contentText = "text";
Intent notificationIntent = new Intent(this, SuperMicProActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent);
final int signed = 1;
mNotificatonManager.notify(signed, notification);
I was looking at onResume() with may be some sort of bringTaskToFront(this) option. Does this exist?
Thanks,
You have a few issues, IMHO.
and has initiated the onPause() function that super.onPause(); moveTaskToBack(true);
That is rather strange behavior. Why are you doing this?
Once the user interacts with the new instance, the program will crash because the background version is already running, causing conflicts.
Then whatever was being done in the original activity should not be in an activity at all, but in a service. Once you no longer have a foreground activity, the odds of Android terminating your process to free up memory is fairly high and may occur rather quickly, depending on what else is going on. You seem to be depending upon that older activity somehow still doing something. A "background version" of an activity should not be doing anything that would impact any other activity in your process, and an activity not in the foreground should not be responsible for doing anything that the user might miss if the activity goes "poof".
That being said, there are other reasons to avoid having a second copy of your activity, notably navigation -- as it stands, when the user presses BACK from the second copy of the activity, they will see the first copy, and get confused.
I need help in making this code look for an already running version of my app
No, you "need help in making this code look for an already running version of" your activity. An app is not an activity. An activity is not an app.
Adding FLAG_ACTIVITY_CLEAR_TOP and FLAG_ACTIVITY_SINGLE_TOP to your Intent will solve this:
Intent i=new Intent(this, SuperMicProActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent pi=PendingIntent.getActivity(this, 0, i, 0);
This will bring your existing activity to the foreground and, if needed, get rid of other activities in your task.
Yes something like that is possible. You need to use flags.
http://developer.android.com/reference/android/content/Intent.html#setFlags(int)
You should look into these 2 in particular.
FLAG_ACTIVITY_SINGLE_TOP
FLAG_ACTIVITY_CLEAR_TOP

Correct way of using android notifications to pass data to my application

Hallo!
I have a question concerning notifications.
I want to create an application, that parses received SMS for a certain content. If the sms contains a certain content it is parsed and the data is extracted. A notification should be created and it should show up. When the user selects the notification, the application should be invoked with the extracted data. If the application is not running, it should be started. If it is already running, the instance should be displayed and processing the information.
To solve this I did the following:
A Broadcast receiver listens for SMS and parses them. To invoke the application I use the following code:
NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new Notification(icon, tickerText, when); Bundle bundleNotification = creatingNotificationBundle(...);
Intent notificationIntent = new Intent(Intent.ACTION_MAIN); notificationIntent.setClassName(...); notificationIntent.putExtras(bundleNotification);
PendingIntent contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0); notification.setLatestEventInfo(context, contentTitle, contentText, contentIntent); mNotificationManager.notify((int) System.currentTimeMillis(), notification);
The Activity that I invoke processes the Intent in the onCreate(...) method. This works fine when the application is not running. When I already have an instance running, it is invoked and no data is passed (or I'm not overwriting the correct methods). I have seen the an onResume() is invoked. But this method doesn't have an intent as a parameter. What is the best idea to solve this problem?
I did an (in my opinion) very dirty workaround to get this work:
I created a temporary activity
I do the same code as above except that I invoke this new activity and set the flags notificationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) and notificationIntent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK)
this activity sends first a Broadcast and than an Intent both forwarding the data previously parsed.
Using this way the main application alwas gets the data. If it is already running it receives the broadcast and comes to front with the intent, if it is not running, it receives the data from the intent in the onCreate(...) method.
But I don't think that this is the correct solution for this problem, since it seams quite dirty to create a dummy activity just for redirecting data and doing nothing else.
Any ideas and suggestions would be highly appreciated.
Thanks
You probably want to override Activity#onNewIntent(android.content.Intent):
…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.

Categories

Resources