Remove app from recent apps programmatically - android

I know that Activities can be declared in manifest as being excluded from recents with android:excludeFromRecents:
http://developer.android.com/guide/topics/manifest/activity-element.html#exclude
However, that's not what I'm looking for, I would like to know if there is a way to remove the app from recent apps programmatically

Yes, generally when you want to have special properties for an Activity when starting it you supply special flags to the Intent. In this case FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS.
Updated:
If you need to hide the current already running activity, you might be able to use this flag in combination with FLAG_ACTIVITY_CLEAR_TOP which would send the new Intent to the existing Activity. You'll have to think and perhaps experiment with what happens as the user moves around your stack though and whether that will make your app re-appear in the recent apps.

This can be done using the ActivityManager.AppTask functionality (starting in API 21)
ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
if(am != null) {
List<ActivityManager.AppTask> tasks = am.getAppTasks();
if (tasks != null && tasks.size() > 0) {
tasks.get(0).setExcludeFromRecents(true);
}
}

Add these lines to the Activity from which you are exiting the application:
#Override
public void finish() {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
super.finishAndRemoveTask();
}
else {
super.finish();
}
}

Following is the definition of the flag android:excludeFromRecents (which i know you have already seen):
Whether or not the task initiated by this activity should be excluded from the list of recently used applications ("recent apps").
That is, when this activity is the root activity of a new task, this
attribute determines whether the task should not appear in the list of
recent apps. "true" if the task should be excluded from the list;
"false" if it should be included. The default value is "false".
so to remove the app from the list of recent app you can set this flag on the first activity in your application since that activity launches the the task for you application. If you have multiple tasks (unlikely for most apps) in your application then you need o set this flag for root activity of all the task.

Call this when your activity is done and should be closed and the task should be completely removed as a part of finishing the root activity of the task.
finishAndRemoveTask();

After receiving the other answers, I managed to get to the following workaround: I have an Activity, let's call it XPTO, declared in manifest with
and basically, when I want app to disappear from the recents list, I finish all other activities, then start the XPTO, which basically kills the app (calling android.os.Process.killProcess(android.os.Process.myPid()); in its onResume()
If anyone has a better way of doing this, please share it

Related

Exclude current activity from Recent Tasks

My app, running in background, at some point displays activity to purposefully interrupt user's flow. My activity starts a new task, which appears in "Recent Tasks" lists while being in foreground. Is there any way it could be prevented? Setting android:excludeFromRecents does not work - activity is not presented anymore in "Recent Tasks" only after is has been paused.
Manifest looks like:
<activity
android:name="com.example.recenttasks.MainActivity"
android:excludeFromRecents="true">
</activity>
and activity is started this way:
#Override
public void onReceive(Context context, Intent intent) {
Intent i = new Intent(context, MainActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
}
The key thing you mentioned is
appears in "Recent Tasks" lists while being in foreground
I think you can't change that behavior. I just tested on my app and the same thing happens. If I press the "recent tasks" button while having my activity in the foreground, it appears listed there. The moment I move out of it to another activity or to my phone's main screen, the activity is not listed anymore.
I also tested this on the built-in DeskClock app that comes with recent Android versions and the same behavior is present there when a new alarm is triggered. Note that the AlarmAlertFullscreen activity of that app has the same parameters you mentioned in your question.
I'm not sure you can circumvent this or why you would need to in the first place since the activity is not listed anymore once it loses the focus.
you are defined it in manifest that is enough but it is not coming..
ok..try add this flag also to your Intnet and start the Activity..
intnet.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
Should the user be able to return to it? (Meaning if it shows and user clicks recents, have they lost their chance to see the hidden activity or should it still be there?)
If they cannot return to it anyway then the best action would be to finish() the activity onPause(). This will mean that as long as you have used android:excludeFromRecents and android:noHistory="true", there will be no item in recents.
If however you do wish to return to the 'interruption' activity (but do not want a recents entry) you could consider still finishing the activity onPause - but also recording a preference flag (something like IS_INTERSTITIAL). Your other activities can then check this preference in onResume and, if it is true, send an Intent to restart the Interstitial instead - To the user it will just appear they are resuming the app in the same state as they left it (interstitial)
Edit: If the screen needs to stay (rather than be re-instantiated) it may be possible to use a DialogFragment, although then you must worry about configuration changes. There is one hack you could try (explained in this answer) -
Set your label empty By using android:label="" your recent task is excluded. however this is a definite hack which may produce inconsistent results (as I haven't tested it to be sure)

How to bring most recently used third party Activity to front?

In my app, I want to programmatically bring the most recently used third party Activity to the front. After looking at other answers here, I've tried relaunching the activity using the baseIntent returned from a list of recent tasks, but that does not seem to bring the activity to the front over whatever else is going on.
My end goal is to create an app that replaces the incoming call screen with a small overlay so the user is not pulled completely out of whatever app they are using when they get a call. I've found you can't replace the default incoming call screen (if this is not true, please let me know as I'd rather do that instead) so as a workaround, I am trying to call the most recently used app to the front of the screen (to overlay the incoming call screen) and then display my overlay on top of that.
Here's the code I am using (The activity is launched from a broadcast receiver)
public class BringMRUAppToFront extends Activity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
ActivityManager activityManager = (ActivityManager) getSystemService("activity");
List<RecentTaskInfo> recentTasks = activityManager.getRecentTasks(1, ActivityManager.RECENT_WITH_EXCLUDED);
if(recentTasks.size() > 2) {
RecentTaskInfo recentTask = recentTasks.get(2);
Intent testIntent = recentTask.baseIntent;
Log.i("MyApp", "Recent task - " + recentTask.baseIntent.getComponent().getPackageName());
testIntent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(testIntent);
}
finish();
}
}
Is there a reliable way to bring any third party activity to the front? The activity is guaranteed to be in memory (if one is not in memory, then I would just display the home screen), so there shouldn't be an issue there. I also don't believe it would be a security issue in this case as it would just be displaying an app that was visible right before the phone rang - though I do understand that opening this up in general in the SDK could pose a risk...still hoping it is possible.
EDIT: Modified the code slightly to reflect what I'm doing. The desired task will almost always be the 3rd task in the list - first is the current task and second is the task of the ringing phone. I am able to call the task to the front, but it is not always in the same state (going to the browser's page instead of the settings screen in the browser, for example). How does the recent tasks list do this?
Figured it out by looking at the Android source code - this is exactly what the Recent Tasks screen does, both pre- and post-Honeycomb:
RecentTaskInfo recentTask = recentTasks.get(1); // task 0 is current task
// maintains state more accurately - only available in API 11+ (3.0/Honeycomb+)
if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
final ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
am.moveTaskToFront(recentTask.id, ActivityManager.MOVE_TASK_WITH_HOME);
} else { // API 10 and below (Gingerbread on down)
Intent restartTaskIntent = new Intent(recentTask.baseIntent);
if (restartTaskIntent != null) {
restartTaskIntent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY);
try {
startActivity(restartTaskIntent);
} catch (ActivityNotFoundException e) {
Log.w("MyApp", "Unable to launch recent task", e);
}
}
}
Permission android.permission.REORDER_TASKS is necessary for this to work correctly.
Start from Android L, getRecentTasks() returns application’s own tasks and possibly some other non-sensitive tasks (such as Home), so you can not do such job.
References: https://developer.android.com/preview/api-overview.html#Behaviors
Why dont you use a global static variable that is accessed by all activities and on its onPause just set that variable to that activity value
Eg
I am placing a static variable called ActivityName
public static String ActivityName = "";
and in the onPause of every activity just assign it the activities pacakage name
#Override
public void onPause() {
super.onPause();
// The static global variable
com.pacakagename.Utls.ActivityName = "com.pacakagename.Act1";
}
So when any of the activity pauses the value is assinged and you will come to know of the most recent paused activity and you can restart it using Class.forName(ActivityName)

Two instances of my android application are running....How to avoid this?

Here is my problem -
I copied my .apk file onto phone memory card and launch my application clicking on it and it allows me to install my application.I install my application.Finally,I got system installation pop up containing two options "Open" and "Done".When i click "Open" my application got launched.Up to this point everything is working without any problem.
Now in my application I click on a button and some download is taking place as a result(Showing progress dialog).Now I press a Home button,so my application goes to background.
Now I again launch my application by going inside Menu and clicking on my application icon.
Expected result - Still I Should see Progress Dialog for downloading.
Actual result - A new instance/session of my application is getting started.
So how to avoid this so that only one and one instance/session of my application should run.
#Palejandro, here you are. Put the code below into your main activity onCreate() method:
// Possible work around for market launches. See
// http://code.google.com/p/android/issues/detail?id=2373
// for more details. Essentially, the market launches the main activity
// on top of other activities.
// We never want this to happen. Instead, we check if we are the root
// and if not, we finish.
if (!isTaskRoot()) {
final Intent intent = getIntent();
final String intentAction = intent.getAction();
if (intent.hasCategory(Intent.CATEGORY_LAUNCHER) && intentAction != null && intentAction.equals(Intent.ACTION_MAIN)) {
Log.w(TAG, "Main Activity is not the root. Finishing Main Activity instead of launching.");
finish();
return;
}
}
I used this piece of code in my projects and it works fine!
I believe you need to put
<activity
android:launchMode="singleInstance"
</activity>
in the manifest file.
what do your OnPause, OnResume and OnCreate?
I will bet money you are not saving anything OnPause, and starting a new instance all the time via OnCreate.
You should read the notes on Activity Lifecycles.
If you haven't got this sorted yet, I would say your app is actually being killed when home is pressed, or perhaps you have a bug that doesn't latch onto whatever object is keeping state.
// put below code in your launcher activity before call super and setcontentview()
ActivityManager am = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
// get the info from the currently running task
List< ActivityManager.RunningTaskInfo > taskInfo = am.getRunningTasks(10);
boolean alreadyTask=false;
for(ActivityManager.RunningTaskInfo info : taskInfo){
ComponentName componentInfo = info.topActivity;
String value= componentInfo.getPackageName();
if(value.contains(getPackageName()) && !info.topActivity.getClassName().contains(getPackageName()+".LauncherActivity")){
alreadyTask=true;
Log.i(TAG, "second instance found!!!");
break;
}
}
if(alreadyTask){
finish();
}
I don't have a solution but the problem is that the intent used to start the app is different when you open it directly from install compared to opening it from your home screen. Since it will get started by two different intents it will open a new instance the second time round.
A quick work around is to avoid pressing "Open" when you have installed the application. Press "Done" and then find the application yourself.
See: http://code.google.com/p/android/issues/detail?id=2373

Always launch the main activity

My application has 4 activities. If the user clicks the home button, the next time the application is launched, I want it to start on the main activity not the last activity it was on. If the phone's display turns off, as long as the application hasn't been closed, I want it to resume where it left off. What is the proper way to go about this?
Just set clearTaskOnLaunch="true" in your manifest main activity declaration.
http://developer.android.com/guide/topics/manifest/activity-element.html#clear
This doesn't answer all parts of your question, but it sounds as though you'd benifit from looking at these attributes in the manifest; launchmode, finishOnTaskLaunch, clearTaskOnLaunch.
I suppose it is a problem of affinity and recent list. Here is how i solved it.
android:taskAffinity="com.packageName.Excluded"
android:excludeFromRecents="true"
so all tasks with the same affinity will not be listed in recent list.
Note : excludeFromRecents will exclude all the tasks with same affinity in one go, so if you don't set the affinity of the activity, your application will be excluded from recent list(app activities use same affinity by default if not set)
#Override
protected void onResume(){
super.onResume();
keeper += 1;
if (keeper == 2){
Intent iii = new Intent(MainActivity.this, SplashActivity.class);
startActivity(iii);
finish();
}
}
You should implement all theses cases on the onPause and onResume methods of your Activity.
You should learn the Activity lifecycle
http://developer.android.com/reference/android/app/Activity.html

App always starts fresh from root activity instead of resuming background state (Known Bug)

This question already has answers here:
Activity stack ordering problem when launching application from Android app installer and from Home screen
(3 answers)
How to return to the latest launched activity when re-launching application after pressing HOME? [duplicate]
(5 answers)
Closed yesterday.
I am facing exactly the problem mentioned in these links:
http://code.google.com/p/android/issues/detail?id=2373
http://groups.google.com/group/android-developers/browse_thread/thread/77aedf6c7daea2ae/da073056831fd8f3?#da073056831fd8f3
http://groups.google.com/group/android-developers/browse_thread/thread/2d88391190be3303?tvc=2
I have a simple root activity with the LAUNCHER and MAIN intents and nothing else. I start another activity with has no flags or anything extra in the manifest whatsoever.
I launch the app (root activity) and from there start the 2nd activity. On pressing the Home button the task goes to the background. On launching the app again (from Launcher or from holding the Home button for recent apps) it starts a new instance of the root activity on top of the existing stack.
If I press the back button, the new "root" activity closes and the old 2nd activity is visible, which means its launching the root activity in the same task instead of bring the task to the foreground.
To counter this I made the root activity's launch Mode singleTask. Now when I press home and launch the app again, it clears the activities above the old root task and brings the old root task to the foreground instead of just bringing the entire old task with the 2nd activity on top to the front. Note that the old root task still retains its application state, which means it wasn't a new instance, but the the higher activities had been killed.
It even occurs on other applications downloaded from the market. The manual install method has no effect for me, it still launches the same way.
This is due to the intents being used to start the app being different. Eclipse starts an app using an intent with no action and no category. The Launcher starts an app using an intent with android.intent.action.MAIN action and android.intent.category.LAUNCHER category. The installer starts an app with the android.intent.action.MAIN action and no category.
Whoever submitted the bug should have probably worded it as a request for enhancement to the Eclipse plugin since they apparently want Eclipse to have the ability to pretend to be the launcher and to start apps using the same intent as the launcher.
Here is the solution:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if ((getIntent().getFlags() & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) != 0 & getIntent().getExtras() == null) {
finish();
return;
}
Your code....
}
EDIT: I had problems with new intents and notifications. The previous solution doesn't work with notifications and intents...
Just add this in onCreate method of your launcher activity like this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
if (!isTaskRoot()) {
finish();
return;
}
// other function
}
Similar solution for Xamarin.Android:
if (!IsTaskRoot)
{
string action = this.Intent.Action;
if (this.Intent.HasCategory(Intent.CategoryLauncher) && !string.IsNullOrEmpty(this.Intent.Action) && action == Intent.ActionMain)
{
Finish();
return;
}
}

Categories

Resources