Merge "Allow a root activity to relinquish task identity"

This commit is contained in:
Craig Mautner
2014-06-19 23:45:14 +00:00
committed by Android (Google) Code Review
9 changed files with 91 additions and 56 deletions

View File

@@ -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

View File

@@ -251,6 +251,13 @@ public class ActivityInfo extends ComponentInfo
* @see android.app.Activity#setImmersive(boolean)
*/
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.

View File

@@ -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;

View File

@@ -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" />

View File

@@ -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

View File

@@ -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" />

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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);