diff options
| author | 2014-06-18 18:34:56 -0700 | |
|---|---|---|
| committer | 2014-06-19 16:40:01 -0700 | |
| commit | 9d4e9bcebbd97ad51daa0ef15cfba5aabb399bbb (patch) | |
| tree | a9b891f93aac7f19953a2ea683523ac29616fb7c | |
| parent | b0586c92281b6f1419a7df09fa13b9436352e4e1 (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.txt | 2 | ||||
| -rw-r--r-- | core/java/android/content/pm/ActivityInfo.java | 7 | ||||
| -rw-r--r-- | core/java/android/content/pm/PackageParser.java | 6 | ||||
| -rw-r--r-- | core/res/AndroidManifest.xml | 3 | ||||
| -rw-r--r-- | core/res/res/values/attrs_manifest.xml | 9 | ||||
| -rw-r--r-- | core/res/res/values/public.xml | 1 | ||||
| -rwxr-xr-x | services/core/java/com/android/server/am/ActivityRecord.java | 13 | ||||
| -rwxr-xr-x | services/core/java/com/android/server/am/ActivityStack.java | 46 | ||||
| -rw-r--r-- | services/core/java/com/android/server/am/TaskRecord.java | 60 |
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); |