I have made a system overlay Icon similar to the one here: https://github.com/mollyIV/ChatHeads
I want it to open my app using the click listener of the icon. I am able to make it open MainActivity using context.startActivity(intent) with FLAG_ACTIVITY_NEW_TASK.
But I would like to open my app as if it was opened from the task switcher(Whatever activity is open, in the same state). How do I accomplish this?
You are using FLAG_ACTIVITY_NEW_TASK
If set, this activity will become the start of a new task on this
history stack.
Try to use FLAG_ACTIVITY_SINGLE_TOP:
If set, the activity will not be launched if it is already running at
the top of the history stack.
Source: http://developer.android.com/reference/android/content/Intent.html
Related
My app has two activities: A and B. A - is the main activity (default for launch), it has action android.intent.action.MAIN and category android.intent.category.LAUNCHER, and A activity has overridden lanchMode="singleTop", it means that if we trying to launch activity A and A is not the top of the task, then OS will create a new instance of A and put it on top.
Steps:
launch activity A from apps menu (click on the app icon)
click the button in activity A screen to launch B (now activity stack looks like A -> B)
press the home button to see the apps menu again and to minimize the app
click on the app icon again to launch my app
Result: opened activity B (stack looks like A -> B)
So my question is why OS do not create a new instance of A if my app in the background with task stack looks like A -> B (B places on top, A and B not finished, they in onStop state) and just open the current stack when I tap on app icon from apps menu (that tap send the intent to my app with Launcher intent, and Launcher is described in activity A which has launch mode singleTop)
I think it suppose to open new instance of A (with stack A -> B -> A) because of A has lanchMode="singleTop". Seems like if the app had activities in the background (in onStop state) and it was opened with the same intent as the first time, then Android OS just show the current app task, but I can not find any proof of that.
This behaviour actually has nothing to do with the launch mode of the Activity. Actually, in this case, Android isn't launching any Activity. You would see this if you added logging or set a breakpoint at onNewIntent() which would be called in the case where Android wanted to launch the Activity, saw that there was already an instance on top of the stack in the task, and routed the new Intent to the current instance by calling onNewIntent().
What is haooening here, when the user taps the app icon on the HOME screen, is that, before launching any Activity, Android looks to see if there is already a task in the background that was started with this same Intent (in this case, ACTION=MAIN, CATEGORY=LAUNCHER, COMPONENT=ActivityA). If it finds a task that was started with the same Intent, it simply brings that task to the foreground in whatever state it was in (exactly as it was when it was moved to the background) and that's it. It doesn't launch any new Activity, it does not call onNewIntent() on the topmost Activity.
This is documented here (although it is easy to miss): where it says:
The device Home screen is the starting place for most tasks. When the
user touches an icon in the app launcher (or a shortcut on the Home
screen), that app's task comes to the foreground. If no task exists
for the app (the app has not been used recently), then a new task is
created and the "main" activity for that app opens as the root
activity in the stack.
I need to launch an activity when a notification is clicked.
The Activity launched is a standalone activity and can not be opened from any other flow from the app itself. I need to ensure that no one can navigate back to this activity once it is destroyed.
Currently i am using the following configuration:
<activity android:name=".Activities.SingleRestaurantOfferActivity"
android:taskAffinity=".Activities.SingleRestaurantOfferActivity"
android:excludeFromRecents="true"
android:screenOrientation="portrait"
android:resizeableActivity="false"/>
And I am launching this activity with the intents
FLAG_ACTIVITY_CLEAR_TASK | FLAG_ACTIVITY_NEW_TASK
Now when the acitivity is created (first notification click), it creates a new task and as per my understanding, if another notification is clicked, since the task will be existing, it will clear the task and re launch the new activity with the new intent. Is my understanding correct?
If the app is open. Then the user clicks on the notification and launches the activity. Now the home button is pressed. What will happen to the notification activity? The recents screen will only show the actual app task and not the notification activity task, will the notification activity be destroyed eventually or will it leak memory?
Please guide me as to how i should approach this. The official android guide also uses launchMode:singleTask, do i need to use that as well?
I am answering my own question here so that anyone who faces a similar issue gets an idea as to what they can do.
Steps to follow are:
1) In the manifest of the required activity, add the following:
android:taskAffinity = "com.yourpackage.youractivity"
This ensures that this activity has a seperate task affinity as compared to the default affinity. This will come into picture when excludeFromRecents is added.
android:excludeFromRecents = "true"
This flag tells android that the task associated with the given activity should not be shown in recents screen. If we had not added the taskAffinity explicitly, this would have meant that the whole application would not show in the recents screen which would be irritating. adding the task affinity will only hide the task of the required activity from recents
android:noHistory = "true"
I am not sure if this is necessarily needed. I added it to ensure that as soon as the user navigates away from the activity in any way ... eg home button, it will kill the activity using onDestroy. Also exclude from recents will prevent it from showing in the recents screen.
2) Now comes the part of intent flags to launch the activity:
I have used the flags:
FLAG_ACTIVITY_NEW_TASK :
This flag along with the taskAffinity will create a new task for the activity if the task is not already created with the same affinity. Then it will place the activity at the root of this new task. If the task already exists, it will be brought to front and the new intent will be delivered to the activity in onNewIntent() method. I wanted the activity to get fully recreated so i added the other flag below.
FLAG_ACTIVITY_CLEAR_TASK:
This flag clears the task and kills all the activities in it. Then it adds the new intended activity at the root of the task. This will ensure in my case that the activity gets fully destroyed and recreated from scratch. You might not need this in your case. CLEAR_TOP with standard launch mode will also almost do the same thing but that's a whole different scenario.
Hope this helps people creating standalone activities which don't merge directly into app flows.
I have an app that runs a service (audio player) in the background and displays an ongoing notification while it is run. When the user clicks the notification, I'd like to open the player activity without it showing up in the recents list and without bringing the rest of the app to front, so when the user presses the back button they go directly to the app they were using previously, regardless of everything. I tried three different ways and none of them worked well.
Start an intent with FLAG_ACTIVITY_NEW_TASK. If there is an existing task, it's brought to the front. When the user presses the back button, the player activity finishes and reveals the previous activity in the said task instead of going back to the app that had been in foreground the moment the notification was clicked.
Start an intent with the following flags: FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS. The existing task isn't brought to the front and the back button works as expected. However, after this activity finishes, the app disappears from the recents list completely. The only way to get it back is to start it from the launcher icon which brings that existing task to the foreground as if opened from recents.
Start an intent with the following flags: FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK | FLAG_ACTIVITY_NO_HISTORY. The activity starts in a new task, but said task replaces the main one in the recents list. Adding FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS makes it behave exactly as in previous case.
Is there any proper way to do such navigation, or should I give up trying and just make it bring an entire existing task to the front with the player activity launched on top of it, as in case 1?
Is it convenience for u to declare the launchMode to "singleInstance" inside this Activity Tag in the Manifest File? I think that may help u.but i am not sure.U can try
Maybe you can try launchmode as a tag for your notificationActivity in your manifest;
android:launchMode="singleInstance"
you should try new document-centric API:
Adding Tasks to the Recents Screen
I actually figured out the proper way to do this: add the taskAffinity attribute to your <activity> in the manifest. This way, it won't interfere at all with how the rest of the app displays in recents, exactly what I was trying to achieve.
I'm having some problems with understanding the activity stack and the behaviour of how it affects my app.
Upon clicking a button it starts an Intent which opens the browser. When I'm in the Browser and I press the home button I land onto the homescreen. Now if I start my app again via launcher it opens the browser instead of my app. How can I circumvent opening the browser upon launching my app?
Right now, the code to open an url looks like this:
private void openUrlExternal(String url) {
Intent openUrlIntent = new Intent(Intent.ACTION_VIEW);
openUrlIntent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
openUrlIntent.setData(Uri.parse(url));
startActivity(openUrlIntent);
}
Am I using the wrong flags? If so, what flags do I have to use?
Thanks in advance!
Try like this:
openUrlIntent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
openUrlIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
That should disassociate the browser task from your own which means when you re-launch yours it should go to your Activity instead of the browser.
However it also depends on where you are calling openUrlExternal() from. If you call this when your activity launches it is still going to take you back to the browser, but if you call this from an event listener (i.e. Button click) then it shouldn't get called when you re-launch your app.
I don't think the accepted answer is exactly correct. It depends on what you intend (no pun intended, heh) to do.
Using Intent.FLAG_ACTIVITY_NEW_TASK it means that the launched activity is completely separate from the launching one. In particular, you can switch to the old activity with the Apps button without exiting the new one.
Using Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET means that the user will be returned to the previous activity when it's launched from the apps drawer.
In both cases launching the app again will get you to the previous activity. The main difference will be whether both activities (or just the last one) are shown in the app switcher.
I'm encountering the following scenario in my application:
Installing it and immediately opening it (using the open button
after the installation, instead of the icon in the applications
list).
Navigating through a few activities.
Clicking the home button.
Clicking the application icon to load it again.
Instead of returning to the activity I was in, the initial activity
is loaded. The previous activity is still there and can be accessed by clicking the back button, but there isn't really a way to know that and it looks like the app was completely restarted.
This may be an issue in this app, because in some cases it might require a registration after performing a few actions, and losing the focus on the activity could be very annoying
Is there anything that can be done to avoid that?
There's a couple of flags under Intent that might be helpful. You use them when an Activity is launched:
"FLAG_ACTIVITY_TASK_ON_HOME: If set in an Intent passed to Context.startActivity(), this flag will cause a newly launching task to be placed on top of the current home activity task (if there is one).
FLAG_ACTIVITY_REORDER_TO_FRONT: If set in an Intent passed to Context.startActivity(), this flag will cause the launched activity to be brought to the front of its task's history stack if it is already running."
http://developer.android.com/reference/android/content/Intent.html