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;