Fix issue #16400873: Apps that show ads as new tasks stay in recents...
...even when I hit back or close the activity in UI
Change the semantics of NEW_DOCUMENT to have the recents entry be
removed by default when its activity is finished, with various ways
to explicitly turn off this behavior.
Change-Id: Idc717706d27de80f28b53ad76f9e375d85118d71
diff --git a/api/current.txt b/api/current.txt
index eb49bcd..f949049 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -7775,7 +7775,6 @@
field public static final int FILL_IN_PACKAGE = 16; // 0x10
field public static final int FILL_IN_SELECTOR = 64; // 0x40
field public static final int FILL_IN_SOURCE_BOUNDS = 32; // 0x20
- field public static final int FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS = 8192; // 0x2000
field public static final int FLAG_ACTIVITY_BROUGHT_TO_FRONT = 4194304; // 0x400000
field public static final int FLAG_ACTIVITY_CLEAR_TASK = 32768; // 0x8000
field public static final int FLAG_ACTIVITY_CLEAR_TOP = 67108864; // 0x4000000
@@ -7792,6 +7791,7 @@
field public static final int FLAG_ACTIVITY_PREVIOUS_IS_TOP = 16777216; // 0x1000000
field public static final int FLAG_ACTIVITY_REORDER_TO_FRONT = 131072; // 0x20000
field public static final int FLAG_ACTIVITY_RESET_TASK_IF_NEEDED = 2097152; // 0x200000
+ field public static final int FLAG_ACTIVITY_RETAIN_IN_RECENTS = 8192; // 0x2000
field public static final int FLAG_ACTIVITY_SINGLE_TOP = 536870912; // 0x20000000
field public static final int FLAG_ACTIVITY_TASK_ON_HOME = 16384; // 0x4000
field public static final int FLAG_DEBUG_LOG_RESOLUTION = 8; // 0x8
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 6e7543f..3f705ac 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3755,6 +3755,13 @@
* Activity to specify multiple document behavior for all launchers of the Activity
* whereas using this flag requires each Intent that launches the Activity to specify it.
*
+ * <p>Note that the default semantics of this flag w.r.t. whether the recents entry for
+ * it is kept after the activity is finished is different than the use of
+ * {@link #FLAG_ACTIVITY_NEW_TASK} and {@link android.R.attr#documentLaunchMode} -- if
+ * this flag is being used to create a new recents entry, then by default that entry
+ * will be removed once the activity is finished. You can modify this behavior with
+ * {@link #FLAG_ACTIVITY_RETAIN_IN_RECENTS}.
+ *
* <p>FLAG_ACTIVITY_NEW_DOCUMENT may be used in conjunction with {@link
* #FLAG_ACTIVITY_MULTIPLE_TASK}. When used alone it is the
* equivalent of the Activity manifest specifying {@link
@@ -3828,14 +3835,20 @@
*/
public static final int FLAG_ACTIVITY_TASK_ON_HOME = 0X00004000;
/**
- * If set and the new activity is the root of a new task, then the task
- * will remain in the list of recently launched tasks only until all of
- * the activities in it are finished.
+ * By default a document created by {@link #FLAG_ACTIVITY_NEW_DOCUMENT} will
+ * have its entry in recent tasks removed when the user closes it (with back
+ * or however else it may finish()). If you would like to instead allow the
+ * document to be kept in recents so that it can be re-launched, you can use
+ * this flag. When set and the task's activity is finished, the recents entry
+ * will remain in the interface for the user to re-launch it, like a recents
+ * entry for a top-level application.
*
- * <p>This is equivalent to the attribute
- * {@link android.R.styleable#AndroidManifestActivity_autoRemoveFromRecents}.
+ * <p>The receiving activity can override this request with
+ * {@link android.R.styleable#AndroidManifestActivity_autoRemoveFromRecents}
+ * or by explcitly calling {@link android.app.Activity#finishAndRemoveTask()
+ * Activity.finishAndRemoveTask()}.
*/
- public static final int FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS = 0x00002000;
+ public static final int FLAG_ACTIVITY_RETAIN_IN_RECENTS = 0x00002000;
/**
* If set, when sending a broadcast only registered receivers will be
diff --git a/core/java/android/widget/ShareActionProvider.java b/core/java/android/widget/ShareActionProvider.java
index ac79d05..9a24061 100644
--- a/core/java/android/widget/ShareActionProvider.java
+++ b/core/java/android/widget/ShareActionProvider.java
@@ -280,8 +280,7 @@
final String action = shareIntent.getAction();
if (Intent.ACTION_SEND.equals(action) || Intent.ACTION_SEND_MULTIPLE.equals(action)) {
shareIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT |
- Intent.FLAG_ACTIVITY_MULTIPLE_TASK |
- Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS);
+ Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
}
}
ActivityChooserModel dataModel = ActivityChooserModel.get(mContext,
@@ -304,8 +303,7 @@
if (Intent.ACTION_SEND.equals(action) ||
Intent.ACTION_SEND_MULTIPLE.equals(action)) {
launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT |
- Intent.FLAG_ACTIVITY_MULTIPLE_TASK |
- Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS);
+ Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
}
mContext.startActivity(launchIntent);
}
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 780715c..cd922a1 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -81,8 +81,7 @@
if (Intent.ACTION_SEND.equals(action) ||
Intent.ACTION_SEND_MULTIPLE.equals(action)) {
in.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT |
- Intent.FLAG_ACTIVITY_MULTIPLE_TASK |
- Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS);
+ Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
}
}
}
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 226e30a..021edc5 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -988,12 +988,10 @@
<attr name="maxRecents" format="integer" />
<!-- Tasks launched by activities with this attribute will remain in the recent tasks
- list until the last activity in the task is completed. When that happens the task
- will be automatically removed from the recent tasks list.
-
- This attribute is the equivalent of {@link
- android.content.Intent#FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS
- Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS} -->
+ list until the last activity in the task is completed. When that happens the task
+ will be automatically removed from the recent tasks list. This overrides the caller's
+ use of {@link android.content.Intent#FLAG_ACTIVITY_RETAIN_IN_RECENTS
+ Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS} -->
<attr name="autoRemoveFromRecents" format="boolean" />
<!-- Tasks whose root has this attribute set to true will replace baseIntent with that of the
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index cfbadb4..3aaa402 100755
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -7423,9 +7423,7 @@
continue;
}
}
- if (tr.intent != null &&
- (tr.intent.getFlags() & Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS)
- != 0 && tr.getTopActivity() == null) {
+ if (tr.autoRemoveRecents && tr.getTopActivity() == null) {
// Don't include auto remove tasks that are finished or finishing.
continue;
}
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 76373df..061053a 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -54,6 +54,7 @@
private static final String TAG_ACTIVITY = "activity";
private static final String ATTR_AFFINITY = "affinity";
private static final String ATTR_ROOTHASRESET = "root_has_reset";
+ private static final String ATTR_AUTOREMOVERECENTS = "auto_remove_recents";
private static final String ATTR_ASKEDCOMPATMODE = "asked_compat_mode";
private static final String ATTR_USERID = "user_id";
private static final String ATTR_TASKTYPE = "task_type";
@@ -83,6 +84,8 @@
long lastActiveTime; // Last time this task was active, including sleep.
boolean rootWasReset; // True if the intent at the root of the task had
// the FLAG_ACTIVITY_RESET_TASK_IF_NEEDED flag.
+ boolean autoRemoveRecents; // If true, we should automatically remove the task from
+ // recents when activity finishes
boolean askedCompatMode;// Have asked the user about compat mode for this task.
boolean hasBeenVisible; // Set if any activities in the task have been visible to the user.
@@ -159,7 +162,8 @@
TaskRecord(ActivityManagerService service, int _taskId, Intent _intent, Intent _affinityIntent,
String _affinity, ComponentName _realActivity, ComponentName _origActivity,
- boolean _rootWasReset, boolean _askedCompatMode, int _taskType, int _userId,
+ boolean _rootWasReset, boolean _autoRemoveRecents, boolean _askedCompatMode,
+ int _taskType, int _userId,
String _lastDescription, ArrayList<ActivityRecord> activities, long _firstActiveTime,
long _lastActiveTime, long lastTimeMoved, boolean neverRelinquishIdentity,
ActivityManager.TaskDescription _lastTaskDescription, int taskAffiliation,
@@ -177,6 +181,7 @@
realActivity = _realActivity;
origActivity = _origActivity;
rootWasReset = _rootWasReset;
+ autoRemoveRecents = _autoRemoveRecents;
askedCompatMode = _askedCompatMode;
taskType = _taskType;
mTaskToReturnTo = HOME_ACTIVITY_TYPE;
@@ -261,7 +266,20 @@
userId = UserHandle.getUserId(info.applicationInfo.uid);
creatorUid = info.applicationInfo.uid;
if ((info.flags & ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS) != 0) {
- intent.addFlags(Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS);
+ // If the activity itself has requested auto-remove, then just always do it.
+ autoRemoveRecents = true;
+ } else if ((intent.getFlags()&(Intent.FLAG_ACTIVITY_NEW_DOCUMENT
+ |Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS)) == Intent.FLAG_ACTIVITY_NEW_DOCUMENT) {
+ // If the caller has not asked for the document to be retained, then we may
+ // want to turn on auto-remove, depending on whether the target has set its
+ // own document launch mode.
+ if (info.documentLaunchMode != ActivityInfo.DOCUMENT_LAUNCH_NONE) {
+ autoRemoveRecents = false;
+ } else {
+ autoRemoveRecents = true;
+ }
+ } else {
+ autoRemoveRecents = false;
}
}
@@ -473,9 +491,7 @@
// We will automatically remove the task either if it has explicitly asked for
// this, or it is empty and has never contained an activity that got shown to
// the user.
- return (intent != null &&
- (intent.getFlags() & Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS) != 0) ||
- (mActivities.isEmpty() && !hasBeenVisible);
+ return autoRemoveRecents || (mActivities.isEmpty() && !hasBeenVisible);
}
/**
@@ -731,6 +747,7 @@
out.attribute(null, ATTR_AFFINITY, affinity);
}
out.attribute(null, ATTR_ROOTHASRESET, String.valueOf(rootWasReset));
+ out.attribute(null, ATTR_AUTOREMOVERECENTS, String.valueOf(autoRemoveRecents));
out.attribute(null, ATTR_ASKEDCOMPATMODE, String.valueOf(askedCompatMode));
out.attribute(null, ATTR_USERID, String.valueOf(userId));
out.attribute(null, ATTR_TASKTYPE, String.valueOf(taskType));
@@ -784,6 +801,7 @@
ComponentName origActivity = null;
String affinity = null;
boolean rootHasReset = false;
+ boolean autoRemoveRecents = false;
boolean askedCompatMode = false;
int taskType = ActivityRecord.APPLICATION_ACTIVITY_TYPE;
int userId = 0;
@@ -814,6 +832,8 @@
affinity = attrValue;
} else if (ATTR_ROOTHASRESET.equals(attrName)) {
rootHasReset = Boolean.valueOf(attrValue);
+ } else if (ATTR_AUTOREMOVERECENTS.equals(attrName)) {
+ autoRemoveRecents = Boolean.valueOf(attrValue);
} else if (ATTR_ASKEDCOMPATMODE.equals(attrName)) {
askedCompatMode = Boolean.valueOf(attrValue);
} else if (ATTR_USERID.equals(attrName)) {
@@ -876,9 +896,9 @@
final TaskRecord task = new TaskRecord(stackSupervisor.mService, taskId, intent,
affinityIntent, affinity, realActivity, origActivity, rootHasReset,
- askedCompatMode, taskType, userId, lastDescription, activities, firstActiveTime,
- lastActiveTime, lastTimeOnTop, neverRelinquishIdentity, taskDescription,
- taskAffiliation, prevTaskId, nextTaskId);
+ autoRemoveRecents, askedCompatMode, taskType, userId, lastDescription, activities,
+ firstActiveTime, lastActiveTime, lastTimeOnTop, neverRelinquishIdentity,
+ taskDescription, taskAffiliation, prevTaskId, nextTaskId);
for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) {
activities.get(activityNdx).task = task;