Launch new tasks with Doc Centric flag.
Introduction of new Intent flag FLAG_ACTIVITY_NEW_DOCUMENT. When
this flag is set the target activity will be launched in its own
task. This is the start of the new Doc Centric mode of working.
Change-Id: I719168532134ab2c5ea3300df676c2b2a0e81795
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index cd9c920..ab7d60a 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3319,20 +3319,35 @@
return;
}
// Remove any existing entries that are the same kind of task.
+ final Intent intent = task.intent;
+ final boolean document = intent != null && intent.isDocument();
for (int i=0; i<N; i++) {
TaskRecord tr = mRecentTasks.get(i);
- if (task.userId == tr.userId
- && ((task.affinity != null && task.affinity.equals(tr.affinity))
- || (task.intent != null && task.intent.filterEquals(tr.intent)))) {
- tr.disposeThumbnail();
- mRecentTasks.remove(i);
- i--;
- N--;
- if (task.intent == null) {
- // If the new recent task we are adding is not fully
- // specified, then replace it with the existing recent task.
- task = tr;
+ if (task != tr) {
+ if (task.userId != tr.userId) {
+ continue;
}
+ final Intent trIntent = tr.intent;
+ if ((task.affinity == null || !task.affinity.equals(tr.affinity)) &&
+ (intent == null || !intent.filterEquals(trIntent))) {
+ continue;
+ }
+ if (document || trIntent != null && trIntent.isDocument()) {
+ // Document tasks do not match other tasks.
+ continue;
+ }
+ }
+
+ // Either task and tr are the same or, their affinities match or their intents match
+ // and neither of them is a document.
+ tr.disposeThumbnail();
+ mRecentTasks.remove(i);
+ i--;
+ N--;
+ if (task.intent == null) {
+ // If the new recent task we are adding is not fully
+ // specified, then replace it with the existing recent task.
+ task = tr;
}
}
if (N >= MAX_RECENT_TASKS) {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 34cc22a..25292a0 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -492,6 +492,9 @@
cls = new ComponentName(info.packageName, info.targetActivity);
}
final int userId = UserHandle.getUserId(info.applicationInfo.uid);
+ boolean isDocument = intent != null & intent.isDocument();
+ // If documentData is non-null then it must match the existing task data.
+ Uri documentData = isDocument ? intent.getData() : null;
if (DEBUG_TASKS) Slog.d(TAG, "Looking for task of " + target + " in " + this);
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
@@ -508,23 +511,39 @@
continue;
}
+ final Intent taskIntent = task.intent;
+ final Intent affinityIntent = task.affinityIntent;
+ final boolean taskIsDocument;
+ final Uri taskDocumentData;
+ if (taskIntent != null && taskIntent.isDocument()) {
+ taskIsDocument = true;
+ taskDocumentData = taskIntent.getData();
+ } else if (affinityIntent != null && affinityIntent.isDocument()) {
+ taskIsDocument = true;
+ taskDocumentData = affinityIntent.getData();
+ } else {
+ taskIsDocument = false;
+ taskDocumentData = null;
+ }
+
if (DEBUG_TASKS) Slog.d(TAG, "Comparing existing cls="
- + r.task.intent.getComponent().flattenToShortString()
+ + taskIntent.getComponent().flattenToShortString()
+ "/aff=" + r.task.affinity + " to new cls="
+ intent.getComponent().flattenToShortString() + "/aff=" + info.taskAffinity);
- if (task.affinity != null) {
- if (task.affinity.equals(info.taskAffinity)) {
+ if (!isDocument && !taskIsDocument && task.affinity != null) {
+ if (task.affinity.equals(target.taskAffinity)) {
if (DEBUG_TASKS) Slog.d(TAG, "Found matching affinity!");
return r;
}
- } else if (task.intent != null && task.intent.getComponent().equals(cls)) {
+ } else if (taskIntent != null && taskIntent.getComponent().equals(cls) &&
+ Objects.equals(documentData, taskDocumentData)) {
if (DEBUG_TASKS) Slog.d(TAG, "Found matching class!");
//dump();
if (DEBUG_TASKS) Slog.d(TAG, "For Intent " + intent + " bringing to top: "
+ r.intent);
return r;
- } else if (task.affinityIntent != null
- && task.affinityIntent.getComponent().equals(cls)) {
+ } else if (affinityIntent != null && affinityIntent.getComponent().equals(cls) &&
+ Objects.equals(documentData, taskDocumentData)) {
if (DEBUG_TASKS) Slog.d(TAG, "Found matching class!");
//dump();
if (DEBUG_TASKS) Slog.d(TAG, "For Intent " + intent + " bringing to top: "
@@ -1857,7 +1876,7 @@
// 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) {
+ & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
resetTaskIfNeededLocked(r, r);
doShow = topRunningNonDelayedActivityLocked(null) == r;
}
@@ -2006,14 +2025,7 @@
+ " out to new task " + target.task);
}
- if (clearWhenTaskReset) {
- // This is the start of a new sub-task.
- if (target.thumbHolder == null) {
- target.thumbHolder = new ThumbnailHolder();
- }
- } else {
- target.thumbHolder = newThumbHolder;
- }
+ target.thumbHolder = newThumbHolder;
final int targetTaskId = targetTask.taskId;
mWindowManager.setAppGroupId(target.appToken, targetTaskId);
@@ -2484,7 +2496,7 @@
final int index = activities.indexOf(r);
if (index < (activities.size() - 1)) {
task.setFrontOfTask();
- if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
+ if ((r.intent.getFlags() & Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET) != 0) {
// If the caller asked that this activity (and all above it)
// be cleared when the task is reset, don't lose that information,
// but propagate it up to the next activity.
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 3c7ef61..3555993 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -17,6 +17,7 @@
package com.android.server.am;
import static android.Manifest.permission.START_ANY_ACTIVITY;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -1443,14 +1444,20 @@
}
}
+ final boolean newDocument = intent.isDocument();
if (sourceRecord == null) {
// This activity is not being started from another... in this
// case we -always- start a new task.
- if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
+ if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
Slog.w(TAG, "startActivity called from non-Activity context; forcing " +
"Intent.FLAG_ACTIVITY_NEW_TASK for: " + intent);
launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
}
+ } else if (newDocument) {
+ if (r.launchMode != ActivityInfo.LAUNCH_MULTIPLE) {
+ Slog.w(TAG, "FLAG_ACTIVITY_NEW_DOCUMENT and launchMode != \"standard\"");
+ r.launchMode = ActivityInfo.LAUNCH_MULTIPLE;
+ }
} else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
// The original activity who is starting us is running as a single
// instance... this new activity it is starting must go on its
@@ -1473,7 +1480,7 @@
// so we don't want to blindly throw it in to that task. Instead we will take
// the NEW_TASK flow and try to find a task for it. But save the task information
// so it can be used when creating the new task.
- if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
+ if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
Slog.w(TAG, "startActivity called from finishing " + sourceRecord
+ "; forcing " + "Intent.FLAG_ACTIVITY_NEW_TASK for: " + intent);
launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
@@ -1489,7 +1496,7 @@
sourceStack = null;
}
- if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
+ if (r.resultTo != null && (launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
// For whatever reason this activity is being launched into a new
// task... yet the caller has requested a result back. Well, that
// is pretty messed up, so instead immediately send back a cancel
@@ -1506,8 +1513,8 @@
boolean movedHome = false;
TaskRecord reuseTask = null;
ActivityStack targetStack;
- if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
- (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
+ if (((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
+ (launchFlags & Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
// If bring to front is requested, and no result is requested, and
@@ -1696,7 +1703,7 @@
if (top != null && r.resultTo == null) {
if (top.realActivity.equals(r.realActivity) && top.userId == r.userId) {
if (top.app != null && top.app.thread != null) {
- if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
+ if ((launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP
|| r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {
ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, top,