Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d00f4740 authored by Craig Mautner's avatar Craig Mautner
Browse files

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
parent 09d47bbb
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -6849,6 +6849,7 @@ package android.content {
    field public static final int FLAG_ACTIVITY_FORWARD_RESULT = 33554432; // 0x2000000
    field public static final int FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY = 1048576; // 0x100000
    field public static final int FLAG_ACTIVITY_MULTIPLE_TASK = 134217728; // 0x8000000
    field public static final int FLAG_ACTIVITY_NEW_DOCUMENT = 268959744; // 0x10080000
    field public static final int FLAG_ACTIVITY_NEW_TASK = 268435456; // 0x10000000
    field public static final int FLAG_ACTIVITY_NO_ANIMATION = 65536; // 0x10000
    field public static final int FLAG_ACTIVITY_NO_HISTORY = 1073741824; // 0x40000000
+52 −3
Original line number Diff line number Diff line
@@ -3457,7 +3457,16 @@ public class Intent implements Parcelable, Cloneable {
     */
    public static final int FLAG_ACTIVITY_NEW_TASK = 0x10000000;
    /**
     * <strong>Do not use this flag unless you are implementing your own
     * This flag is used to create a new task and launch an activity into it.
     * This flag is always paired with either {@link #FLAG_ACTIVITY_NEW_DOCUMENT}
     * or {@link #FLAG_ACTIVITY_NEW_TASK}. In both cases these flags alone would
     * search through existing tasks for ones matching this Intent. Only if no such
     * task is found would a new task be created. When paired with
     * FLAG_ACTIVITY_MULTIPLE_TASK both of these behaviors are modified to skip
     * the search for a matching task and unconditionally start a new task.
     *
     * <strong>When used with {@link #FLAG_ACTIVITY_NEW_TASK} do not use this
     * flag unless you are implementing your own
     * top-level application launcher.</strong>  Used in conjunction with
     * {@link #FLAG_ACTIVITY_NEW_TASK} to disable the
     * behavior of bringing an existing task to the foreground.  When set,
@@ -3469,12 +3478,18 @@ public class Intent implements Parcelable, Cloneable {
     * you should not use this flag unless you provide some way for a user to
     * return back to the tasks you have launched.</strong>
     *
     * <p>This flag is ignored if
     * {@link #FLAG_ACTIVITY_NEW_TASK} is not set.
     * See {@link #FLAG_ACTIVITY_NEW_DOCUMENT} for details of this flag's use for
     * creating new document tasks.
     *
     * <p>This flag is ignored if one of {@link #FLAG_ACTIVITY_NEW_TASK} or
     * {@link #FLAG_ACTIVITY_NEW_TASK} is not also set.
     *
     * <p>See
     * <a href="{@docRoot}guide/topics/fundamentals/tasks-and-back-stack.html">Tasks and Back
     * Stack</a> for more information about tasks.
     *
     * @see #FLAG_ACTIVITY_NEW_DOCUMENT
     * @see #FLAG_ACTIVITY_NEW_TASK
     */
    public static final int FLAG_ACTIVITY_MULTIPLE_TASK = 0x08000000;
    /**
@@ -3580,6 +3595,34 @@ public class Intent implements Parcelable, Cloneable {
     * to mail.
     */
    public static final int FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET = 0x00080000;
    /**
     * This flag is used to break out "documents" into separate tasks that can
     * be reached via the Recents mechanism. Such a document is any kind of
     * item for which an application may want to maintain multiple simultaneous
     * instances. Examples might be text files, web pages, spreadsheets, or
     * emails. Each such document will be in a separate task in the Recents list.
     *
     * <p>When set, the activity specified by this Intent will launch into a
     * separate task rooted at that activity. The activity launched must be
     * defined with {@link android.R.attr#launchMode} "standard" or "singleTop".
     *
     * <p>If FLAG_ACTIVITY_NEW_DOCUMENT is used without
     * {@link #FLAG_ACTIVITY_MULTIPLE_TASK} then the activity manager will
     * search for an existing task with a matching target activity and Intent
     * data URI and relaunch that task, first finishing all activities down to
     * the root activity and then calling the root activity's
     * {@link android.app.Activity#onNewIntent(Intent)} method. If no existing
     * task's root activity matches the Intent's data URI then a new task will
     * be launched with the target activity as root.
     *
     * <p>When paired with {@link #FLAG_ACTIVITY_MULTIPLE_TASK} this will
     * always create a new task. Thus the same document may be made to appear
     * more than one time in Recents.
     *
     * @see #FLAG_ACTIVITY_MULTIPLE_TASK
     */
    public static final int FLAG_ACTIVITY_NEW_DOCUMENT =
            FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET | FLAG_ACTIVITY_NEW_TASK;
    /**
     * If set, this flag will prevent the normal {@link android.app.Activity#onUserLeaveHint}
     * callback from occurring on the current frontmost activity before it is
@@ -6246,6 +6289,7 @@ public class Intent implements Parcelable, Cloneable {
     * @see #FLAG_ACTIVITY_FORWARD_RESULT
     * @see #FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
     * @see #FLAG_ACTIVITY_MULTIPLE_TASK
     * @see #FLAG_ACTIVITY_NEW_DOCUMENT
     * @see #FLAG_ACTIVITY_NEW_TASK
     * @see #FLAG_ACTIVITY_NO_ANIMATION
     * @see #FLAG_ACTIVITY_NO_HISTORY
@@ -7342,4 +7386,9 @@ public class Intent implements Parcelable, Cloneable {
        String htmlText = htmlTexts != null ? htmlTexts.get(which) : null;
        return new ClipData.Item(text, htmlText, null, uri);
    }

    /** @hide */
    public boolean isDocument() {
        return (mFlags & FLAG_ACTIVITY_NEW_DOCUMENT) == FLAG_ACTIVITY_NEW_DOCUMENT;
    }
}
+26 −11
Original line number Diff line number Diff line
@@ -3319,11 +3319,27 @@ public final class ActivityManagerService extends ActivityManagerNative
            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)))) {
            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--;
@@ -3334,7 +3350,6 @@ public final class ActivityManagerService extends ActivityManagerNative
                task = tr;
            }
        }
        }
        if (N >= MAX_RECENT_TASKS) {
            mRecentTasks.remove(N-1).disposeThumbnail();
        }
+28 −16
Original line number Diff line number Diff line
@@ -492,6 +492,9 @@ final class ActivityStack {
            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 @@ final class ActivityStack {
                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: "
@@ -2006,14 +2025,7 @@ final class ActivityStack {
                            + " 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;
                }

                final int targetTaskId = targetTask.taskId;
                mWindowManager.setAppGroupId(target.appToken, targetTaskId);
+13 −6
Original line number Diff line number Diff line
@@ -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,6 +1444,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
            }
        }

        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.
@@ -1451,6 +1453,11 @@ public final class ActivityStackSupervisor implements DisplayListener {
                        "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