summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Craig Mautner <cmautner@google.com> 2014-06-18 18:34:56 -0700
committer Craig Mautner <cmautner@google.com> 2014-06-19 16:40:01 -0700
commit9d4e9bcebbd97ad51daa0ef15cfba5aabb399bbb (patch)
treea9b891f93aac7f19953a2ea683523ac29616fb7c
parentb0586c92281b6f1419a7df09fa13b9436352e4e1 (diff)
Allow a root activity to relinquish task identity
If a an acitivty with attribute android:relinquishTaskIdentity true is the root activity of a task then the intent of that task will be that of the first activity in the stack with android:relinquishTaskIdentity set false. The ability to set intent also includes the ability to set the TaskDescription of the task. Fixes bug 15675610. Fixes bug 10428661. Change-Id: Ib28a9eae3b9832eeeef9106adbebe344184ee5ae
-rw-r--r--api/current.txt2
-rw-r--r--core/java/android/content/pm/ActivityInfo.java7
-rw-r--r--core/java/android/content/pm/PackageParser.java6
-rw-r--r--core/res/AndroidManifest.xml3
-rw-r--r--core/res/res/values/attrs_manifest.xml9
-rw-r--r--core/res/res/values/public.xml1
-rwxr-xr-xservices/core/java/com/android/server/am/ActivityRecord.java13
-rwxr-xr-xservices/core/java/com/android/server/am/ActivityStack.java46
-rw-r--r--services/core/java/com/android/server/am/TaskRecord.java60
9 files changed, 91 insertions, 56 deletions
diff --git a/api/current.txt b/api/current.txt
index 3b311e31ca0f..03b301335ac8 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -957,6 +957,7 @@ package android {
field public static final int ratingBarStyleIndicator = 16843280; // 0x1010210
field public static final int ratingBarStyleSmall = 16842877; // 0x101007d
field public static final int readPermission = 16842759; // 0x1010007
+ field public static final int relinquishTaskIdentity = 16843893; // 0x1010475
field public static final int repeatCount = 16843199; // 0x10101bf
field public static final int repeatMode = 16843200; // 0x10101c0
field public static final int reqFiveWayNav = 16843314; // 0x1010232
@@ -8085,6 +8086,7 @@ package android.content.pm {
field public static final int FLAG_IMMERSIVE = 2048; // 0x800
field public static final int FLAG_MULTIPROCESS = 1; // 0x1
field public static final int FLAG_NO_HISTORY = 128; // 0x80
+ field public static final int FLAG_RELINQUISH_TASK_IDENTITY = 4096; // 0x1000
field public static final int FLAG_SINGLE_USER = 1073741824; // 0x40000000
field public static final int FLAG_STATE_NOT_NEEDED = 16; // 0x10
field public static final int LAUNCH_MULTIPLE = 0; // 0x0
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index abc8cde2c9eb..bcf1e8760e75 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -252,6 +252,13 @@ public class ActivityInfo extends ComponentInfo
*/
public static final int FLAG_IMMERSIVE = 0x0800;
/**
+ * Bit in {@link #flags}: If set, a task rooted at this activity will have its
+ * baseIntent replaced by the activity immediately above this. Each activity may further
+ * relinquish its identity to the activity above it using this flag. Set from the
+ * android.R.attr#relinquishTaskIdentity attribute.
+ */
+ public static final int FLAG_RELINQUISH_TASK_IDENTITY = 0x1000;
+ /**
* Bit in {@link #flags} indicating that tasks started with this activity are to be
* removed from the recent list of tasks when the last activity in the task is finished.
* {@link android.R.attr#autoRemoveFromRecents}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 0b336d011692..b40a441a88d6 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2629,6 +2629,12 @@ public class PackageParser {
false)) {
a.info.flags |= ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS;
}
+
+ if (sa.getBoolean(
+ com.android.internal.R.styleable.AndroidManifestActivity_relinquishTaskIdentity,
+ false)) {
+ a.info.flags |= ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY;
+ }
} else {
a.info.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
a.info.configChanges = 0;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 8b5dff014e19..fa1a563e43b9 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2742,7 +2742,8 @@
android:finishOnCloseSystemDialogs="true"
android:excludeFromRecents="true"
android:multiprocess="true"
- android:documentLaunchMode="never">
+ android:documentLaunchMode="never"
+ android:relinquishTaskIdentity="true">
<intent-filter>
<action android:name="android.intent.action.CHOOSER" />
<category android:name="android.intent.category.DEFAULT" />
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 4e06d9a03c5e..fc1d0df86f46 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -985,6 +985,14 @@
Intent.FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS} -->
<attr name="autoRemoveFromRecents" format="boolean" />
+ <!-- Tasks whose root has this attribute set to true will replace baseIntent with that of the
+ next activity in the task. If the next activity also has this attribute set to true then
+ it will yield the baseIntent to any activity that it launches in the same task. This
+ continues until an activity is encountered which has this attribute set to false. False
+ is the default. This attribute set to true also permits activity's use of the
+ TaskDescription to change labels, colors and icons in the recent task list. -->
+ <attr name="relinquishTaskIdentity" format="boolean" />
+
<!-- The <code>manifest</code> tag is the root of an
<code>AndroidManifest.xml</code> file,
describing the contents of an Android package (.apk) file. One
@@ -1653,6 +1661,7 @@
<attr name="documentLaunchMode" />
<attr name="maxRecents" />
<attr name="autoRemoveFromRecents" />
+ <attr name="relinquishTaskIdentity" />
</declare-styleable>
<!-- The <code>activity-alias</code> tag declares a new
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index f73c9586788f..07a1e5159fdf 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2209,6 +2209,7 @@
<public type="attr" name="fullBackupOnly" />
<public type="attr" name="propertyXName" />
<public type="attr" name="propertyYName" />
+ <public type="attr" name="relinquishTaskIdentity" />
<public-padding type="dimen" name="l_resource_pad" end="0x01050010" />
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index dd9cae90dd00..0825f2e75554 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -582,11 +582,6 @@ final class ActivityRecord {
}
}
- boolean isRootActivity() {
- final ArrayList<ActivityRecord> activities = task.mActivities;
- return activities.size() == 0 || this == activities.get(0);
- }
-
UriPermissionOwner getUriPermissionsLocked() {
if (uriPermissions == null) {
uriPermissions = new UriPermissionOwner(service, this);
@@ -1035,11 +1030,11 @@ final class ActivityRecord {
return -1;
}
final TaskRecord task = r.task;
- switch (task.mActivities.indexOf(r)) {
- case -1: return -1;
- case 0: return task.taskId;
- default: return onlyRoot ? -1 : task.taskId;
+ final int activityNdx = task.mActivities.indexOf(r);
+ if (activityNdx < 0 || (onlyRoot && activityNdx > task.findEffectiveRootIndex())) {
+ return -1;
}
+ return task.taskId;
}
static ActivityRecord isInStackLocked(IBinder token) {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 03ce5300e863..fe2a473e3173 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1066,40 +1066,6 @@ final class ActivityStack {
}
}
- /**
- * Determine if home should be visible below the passed record.
- * @param record activity we are querying for.
- * @return true if home is visible below the passed activity, false otherwise.
- */
- boolean isActivityOverHome(ActivityRecord record) {
- // Start at record and go down, look for either home or a visible fullscreen activity.
- final TaskRecord recordTask = record.task;
- for (int taskNdx = mTaskHistory.indexOf(recordTask); taskNdx >= 0; --taskNdx) {
- TaskRecord task = mTaskHistory.get(taskNdx);
- final ArrayList<ActivityRecord> activities = task.mActivities;
- final int startNdx =
- task == recordTask ? activities.indexOf(record) : activities.size() - 1;
- for (int activityNdx = startNdx; activityNdx >= 0; --activityNdx) {
- final ActivityRecord r = activities.get(activityNdx);
- if (r.isHomeActivity()) {
- return true;
- }
- if (!r.finishing && r.fullscreen) {
- // Passed activity is over a fullscreen activity.
- return false;
- }
- }
- if (task.mOnTopOfHome) {
- // Got to the bottom of a task on top of home without finding a visible fullscreen
- // activity. Home is visible.
- return true;
- }
- }
- // Got to the bottom of this stack and still don't know. If this is over the home stack
- // then record is over home. May not work if we ever get more than two layers.
- return mStackSupervisor.isFrontStack(this);
- }
-
private void setVisibile(ActivityRecord r, boolean visible) {
r.visible = visible;
mWindowManager.setAppVisibility(r.appToken, visible);
@@ -1954,8 +1920,7 @@ final class ActivityStack {
// existing activities from other tasks in to it.
// If the caller has requested that the target task be
// reset, then do so.
- if ((r.intent.getFlags()
- & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
+ if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
resetTaskIfNeededLocked(r, r);
doShow = topRunningNonDelayedActivityLocked(null) == r;
}
@@ -2048,7 +2013,8 @@ final class ActivityStack {
// the root, we may no longer have the task!).
final ArrayList<ActivityRecord> activities = task.mActivities;
final int numActivities = activities.size();
- for (int i = numActivities - 1; i > 0; --i ) {
+ final int rootActivityNdx = task.findEffectiveRootIndex();
+ for (int i = numActivities - 1; i > rootActivityNdx; --i ) {
ActivityRecord target = activities.get(i);
final int flags = target.info.flags;
@@ -2207,8 +2173,10 @@ final class ActivityStack {
final ArrayList<ActivityRecord> activities = affinityTask.mActivities;
final int numActivities = activities.size();
- // Do not operate on the root Activity.
- for (int i = numActivities - 1; i > 0; --i) {
+ final int rootActivityNdx = affinityTask.findEffectiveRootIndex();
+
+ // Do not operate on or below the effective root Activity.
+ for (int i = numActivities - 1; i > rootActivityNdx; --i) {
ActivityRecord target = activities.get(i);
final int flags = target.info.flags;
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 1cde41fb92ad..9fff329b7bca 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -27,7 +27,6 @@ import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
-import android.os.SystemClock;
import android.os.UserHandle;
import android.service.voice.IVoiceInteractionSession;
import android.util.Slog;
@@ -57,11 +56,12 @@ final class TaskRecord extends ThumbnailHolder {
private static final String ATTR_ONTOPOFHOME = "on_top_of_home";
private static final String ATTR_LASTDESCRIPTION = "last_description";
private static final String ATTR_LASTTIMEMOVED = "last_time_moved";
+ private static final String ATTR_NEVERRELINQUISH = "never_relinquish_identity";
private static final String TASK_THUMBNAIL_SUFFIX = "_task_thumbnail";
final int taskId; // Unique identifier for this task.
- final String affinity; // The affinity name for this task, or null.
+ String affinity; // The affinity name for this task, or null.
final IVoiceInteractionSession voiceSession; // Voice interaction session driving task
final IVoiceInteractor voiceInteractor; // Associated interactor to provide to app
Intent intent; // The original intent that started the task.
@@ -111,13 +111,15 @@ final class TaskRecord extends ThumbnailHolder {
* Display.DEFAULT_DISPLAY. */
boolean mOnTopOfHome = false;
+ /** If original intent did not allow relinquishing task identity, save that information */
+ boolean mNeverRelinquishIdentity = true;
+
final ActivityManagerService mService;
TaskRecord(ActivityManagerService service, int _taskId, ActivityInfo info, Intent _intent,
IVoiceInteractionSession _voiceSession, IVoiceInteractor _voiceInteractor) {
mService = service;
taskId = _taskId;
- affinity = info.taskAffinity;
voiceSession = _voiceSession;
voiceInteractor = _voiceInteractor;
setIntent(_intent, info);
@@ -128,7 +130,7 @@ final class TaskRecord extends ThumbnailHolder {
String _affinity, ComponentName _realActivity, ComponentName _origActivity,
boolean _rootWasReset, boolean _askedCompatMode, int _taskType, boolean _onTopOfHome,
int _userId, String _lastDescription, ArrayList<ActivityRecord> activities,
- long lastTimeMoved) {
+ long lastTimeMoved, boolean neverRelinquishIdentity) {
mService = service;
taskId = _taskId;
intent = _intent;
@@ -146,6 +148,7 @@ final class TaskRecord extends ThumbnailHolder {
lastDescription = _lastDescription;
mActivities = activities;
mLastTimeMoved = lastTimeMoved;
+ mNeverRelinquishIdentity = neverRelinquishIdentity;
}
void touchActiveTime() {
@@ -157,6 +160,14 @@ final class TaskRecord extends ThumbnailHolder {
}
void setIntent(Intent _intent, ActivityInfo info) {
+ if (intent == null) {
+ mNeverRelinquishIdentity =
+ (info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) == 0;
+ } else if (mNeverRelinquishIdentity) {
+ return;
+ }
+
+ affinity = info.taskAffinity;
stringName = null;
if (info.targetActivity == null) {
@@ -282,6 +293,7 @@ final class TaskRecord extends ThumbnailHolder {
mActivities.remove(newTop);
mActivities.add(newTop);
+ updateEffectiveIntent();
setFrontOfTask();
}
@@ -311,6 +323,7 @@ final class TaskRecord extends ThumbnailHolder {
r.mActivityType = taskType;
}
mActivities.add(index, r);
+ updateEffectiveIntent();
if (r.isPersistable()) {
mService.notifyTaskPersisterLocked(this, false);
}
@@ -322,6 +335,7 @@ final class TaskRecord extends ThumbnailHolder {
// Was previously in list.
numFullscreen--;
}
+ updateEffectiveIntent();
if (r.isPersistable()) {
mService.notifyTaskPersisterLocked(this, false);
}
@@ -579,12 +593,19 @@ final class TaskRecord extends ThumbnailHolder {
// utility activities.
int activityNdx;
final int numActivities = mActivities.size();
+ final boolean relinquish = numActivities == 0 ? false :
+ (mActivities.get(0).info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) != 0;
for (activityNdx = Math.min(numActivities, 1); activityNdx < numActivities;
++activityNdx) {
final ActivityRecord r = mActivities.get(activityNdx);
+ if (relinquish && (r.info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) == 0) {
+ // This will be the top activity for determining taskDescription. Pre-inc to
+ // overcome initial decrement below.
+ ++activityNdx;
+ break;
+ }
if (r.intent != null &&
- (r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET)
- != 0) {
+ (r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
break;
}
}
@@ -615,6 +636,27 @@ final class TaskRecord extends ThumbnailHolder {
}
}
+ int findEffectiveRootIndex() {
+ int activityNdx;
+ final int topActivityNdx = mActivities.size() - 1;
+ for (activityNdx = 0; activityNdx < topActivityNdx; ++activityNdx) {
+ final ActivityRecord r = mActivities.get(activityNdx);
+ if (r.finishing) {
+ continue;
+ }
+ if ((r.info.flags & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) == 0) {
+ break;
+ }
+ }
+ return activityNdx;
+ }
+
+ void updateEffectiveIntent() {
+ final int effectiveRootIndex = findEffectiveRootIndex();
+ final ActivityRecord r = mActivities.get(effectiveRootIndex);
+ setIntent(r.intent, r.info);
+ }
+
void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
Slog.i(TAG, "Saving task=" + this);
@@ -634,6 +676,7 @@ final class TaskRecord extends ThumbnailHolder {
out.attribute(null, ATTR_TASKTYPE, String.valueOf(taskType));
out.attribute(null, ATTR_ONTOPOFHOME, String.valueOf(mOnTopOfHome));
out.attribute(null, ATTR_LASTTIMEMOVED, String.valueOf(mLastTimeMoved));
+ out.attribute(null, ATTR_NEVERRELINQUISH, String.valueOf(mNeverRelinquishIdentity));
if (lastDescription != null) {
out.attribute(null, ATTR_LASTDESCRIPTION, lastDescription.toString());
}
@@ -684,6 +727,7 @@ final class TaskRecord extends ThumbnailHolder {
int userId = 0;
String lastDescription = null;
long lastTimeOnTop = 0;
+ boolean neverRelinquishIdentity = true;
int taskId = -1;
final int outerDepth = in.getDepth();
@@ -714,6 +758,8 @@ final class TaskRecord extends ThumbnailHolder {
lastDescription = attrValue;
} else if (ATTR_LASTTIMEMOVED.equals(attrName)) {
lastTimeOnTop = Long.valueOf(attrValue);
+ } else if (ATTR_NEVERRELINQUISH.equals(attrName)) {
+ neverRelinquishIdentity = Boolean.valueOf(attrValue);
} else {
Slog.w(TAG, "TaskRecord: Unknown attribute=" + attrName);
}
@@ -748,7 +794,7 @@ final class TaskRecord extends ThumbnailHolder {
final TaskRecord task = new TaskRecord(stackSupervisor.mService, taskId, intent,
affinityIntent, affinity, realActivity, origActivity, rootHasReset,
askedCompatMode, taskType, onTopOfHome, userId, lastDescription, activities,
- lastTimeOnTop);
+ lastTimeOnTop, neverRelinquishIdentity);
for (int activityNdx = activities.size() - 1; activityNdx >=0; --activityNdx) {
final ActivityRecord r = activities.get(activityNdx);