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

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

Add task affiliation

Introduces new flag Intent.FLAG_ACTIVITY_LAUNCH_BEHIND which
causes the newly launched task to affiliate with the launching task.
(Later this flag will also launch the task behind the current task).
This shows up in a new member of the RecentTaskInfo class. This also
causes the recents list returned by getRecentsInfo to be rearranged
so that affiliated tasks are together.

Fixes bug 16157517.

Change-Id: Ia1386af50da2f01809278b62d249f05c6a0de951
parent 30f01591
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -7682,6 +7682,7 @@ package android.content {
    field public static final int FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS = 8388608; // 0x800000
    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_LAUNCH_BEHIND = 4096; // 0x1000
    field public static final int FLAG_ACTIVITY_MULTIPLE_TASK = 134217728; // 0x8000000
    field public static final int FLAG_ACTIVITY_NEW_DOCUMENT = 524288; // 0x80000
    field public static final int FLAG_ACTIVITY_NEW_TASK = 268435456; // 0x10000000
+8 −0
Original line number Diff line number Diff line
@@ -696,6 +696,12 @@ public class ActivityManager {
         */
        public TaskDescription taskDescription;

        /**
         * Task affiliation for grouping with other tasks.
         * @hide
         */
        public int affiliatedTaskId;

        public RecentTaskInfo() {
        }

@@ -727,6 +733,7 @@ public class ActivityManager {
            dest.writeInt(userId);
            dest.writeLong(firstActiveTime);
            dest.writeLong(lastActiveTime);
            dest.writeInt(affiliatedTaskId);
        }

        public void readFromParcel(Parcel source) {
@@ -741,6 +748,7 @@ public class ActivityManager {
            userId = source.readInt();
            firstActiveTime = source.readLong();
            lastActiveTime = source.readLong();
            affiliatedTaskId = source.readInt();
        }

        public static final Creator<RecentTaskInfo> CREATOR
+12 −0
Original line number Diff line number Diff line
@@ -3809,6 +3809,18 @@ public class Intent implements Parcelable, Cloneable {
     * {@link android.R.styleable#AndroidManifestActivity_autoRemoveFromRecents}.
     */
    public static final int FLAG_ACTIVITY_AUTO_REMOVE_FROM_RECENTS = 0x00002000;
    /**
     * If set along with FLAG_ACTIVITY_NEW_DOCUMENT then the task being launched will not be
     * presented to the user but will instead be only available through the recents task list.
     * In addition, the new task wil be affiliated with the launching activity's task.
     * Affiliated tasks are grouped together in the recents task list.
     *
     * <p>This behavior is not supported for activities with {@link
     * android.R.styleable#AndroidManifestActivity_launchMode launchMode} values of
     * <code>singleInstance</code> or <code>singleTask</code>.
     */
    public static final int FLAG_ACTIVITY_LAUNCH_BEHIND = 0x00001000;

    /**
     * If set, when sending a broadcast only registered receivers will be
     * called -- no BroadcastReceiver components will be launched.
+68 −12
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import android.os.BatteryStats;
import android.os.PersistableBundle;
import android.service.voice.IVoiceInteractionSession;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.SparseIntArray;
import com.android.internal.R;
@@ -420,6 +421,7 @@ public final class ActivityManagerService extends ActivityManagerNative
     * List of intents that were used to start the most recent tasks.
     */
    ArrayList<TaskRecord> mRecentTasks;
    ArraySet<TaskRecord> mTmpRecents = new ArraySet<TaskRecord>();
    public class PendingAssistExtras extends Binder implements Runnable {
        public final ActivityRecord activity;
@@ -3611,7 +3613,7 @@ public final class ActivityManagerService extends ActivityManagerNative
        int maxRecents = task.maxRecents - 1;
        for (int i=0; i<N; i++) {
            TaskRecord tr = mRecentTasks.get(i);
            final TaskRecord tr = mRecentTasks.get(i);
            if (task != tr) {
                if (task.userId != tr.userId) {
                    continue;
@@ -3644,6 +3646,9 @@ public final class ActivityManagerService extends ActivityManagerNative
            // and their maxRecents has been reached.
            tr.disposeThumbnail();
            mRecentTasks.remove(i);
            if (task != tr) {
                tr.closeRecentsChain();
            }
            i--;
            N--;
            if (task.intent == null) {
@@ -3654,7 +3659,9 @@ public final class ActivityManagerService extends ActivityManagerNative
            mTaskPersister.notify(tr, false);
        }
        if (N >= MAX_RECENT_TASKS) {
            mRecentTasks.remove(N-1).disposeThumbnail();
            final TaskRecord tr = mRecentTasks.remove(N - 1);
            tr.disposeThumbnail();
            tr.closeRecentsChain();
        }
        mRecentTasks.add(0, task);
    }
@@ -7280,8 +7287,7 @@ public final class ActivityManagerService extends ActivityManagerNative
        tr.updateTaskDescription();
        // Compose the recent task info
        ActivityManager.RecentTaskInfo rti
                = new ActivityManager.RecentTaskInfo();
        ActivityManager.RecentTaskInfo rti = new ActivityManager.RecentTaskInfo();
        rti.id = tr.getTopActivity() == null ? -1 : tr.taskId;
        rti.persistentId = tr.taskId;
        rti.baseIntent = new Intent(tr.getBaseIntent());
@@ -7292,19 +7298,20 @@ public final class ActivityManagerService extends ActivityManagerNative
        rti.taskDescription = new ActivityManager.TaskDescription(tr.lastTaskDescription);
        rti.firstActiveTime = tr.firstActiveTime;
        rti.lastActiveTime = tr.lastActiveTime;
        rti.affiliatedTaskId = tr.mAffiliatedTaskId;
        return rti;
    }
    @Override
    public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum,
            int flags, int userId) {
    public List<ActivityManager.RecentTaskInfo> getRecentTasks(int maxNum, int flags, int userId) {
        final int callingUid = Binder.getCallingUid();
        userId = handleIncomingUser(Binder.getCallingPid(), callingUid, userId,
                false, ALLOW_FULL_ONLY, "getRecentTasks", null);
        final boolean includeProfiles = (flags & ActivityManager.RECENT_INCLUDE_PROFILES) != 0;
        final boolean withExcluded = (flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0;
        synchronized (this) {
            final boolean allowed = checkCallingPermission(
                    android.Manifest.permission.GET_TASKS)
            final boolean allowed = checkCallingPermission(android.Manifest.permission.GET_TASKS)
                    == PackageManager.PERMISSION_GRANTED;
            if (!allowed) {
                Slog.w(TAG, "getRecentTasks: caller " + callingUid
@@ -7322,12 +7329,60 @@ public final class ActivityManagerService extends ActivityManagerNative
                            maxNum < N ? maxNum : N);
            final Set<Integer> includedUsers;
            if ((flags & ActivityManager.RECENT_INCLUDE_PROFILES) != 0) {
            if (includeProfiles) {
                includedUsers = getProfileIdsLocked(userId);
            } else {
                includedUsers = new HashSet<Integer>();
            }
            includedUsers.add(Integer.valueOf(userId));
            // Regroup affiliated tasks together.
            for (int i = 0; i < N; ) {
                TaskRecord task = mRecentTasks.remove(i);
                if (mTmpRecents.contains(task)) {
                    continue;
                }
                int affiliatedTaskId = task.mAffiliatedTaskId;
                while (true) {
                    TaskRecord next = task.mNextAffiliate;
                    if (next == null) {
                        break;
                    }
                    if (next.mAffiliatedTaskId != affiliatedTaskId) {
                        Slog.e(TAG, "Error in Recents: next.affiliatedTaskId=" +
                                next.mAffiliatedTaskId + " affiliatedTaskId=" + affiliatedTaskId);
                        task.setNextAffiliate(null);
                        if (next.mPrevAffiliate == task) {
                            next.setPrevAffiliate(null);
                        }
                        break;
                    }
                    if (next.mPrevAffiliate != task) {
                        Slog.e(TAG, "Error in Recents chain prev.mNextAffiliate=" +
                                next.mPrevAffiliate + " task=" + task);
                        next.setPrevAffiliate(null);
                        break;
                    }
                    if (!mRecentTasks.contains(next)) {
                        Slog.e(TAG, "Error in Recents: next=" + next + " not in mRecentTasks");
                        task.setNextAffiliate(null);
                        if (next.mPrevAffiliate == task) {
                            next.setPrevAffiliate(null);
                        }
                        break;
                    }
                    task = next;
                }
                // task is now the end of the list
                do {
                    mRecentTasks.remove(task);
                    mRecentTasks.add(i++, task);
                    mTmpRecents.add(task);
                } while ((task = task.mPrevAffiliate) != null);
            }
            mTmpRecents.clear();
            // mRecentTasks is now in sorted, affiliated order.
            for (int i=0; i<N && maxNum > 0; i++) {
                TaskRecord tr = mRecentTasks.get(i);
                // Only add calling user or related users recent tasks
@@ -7340,10 +7395,10 @@ public final class ActivityManagerService extends ActivityManagerNative
                // we should exclude the entry.
                if (i == 0
                        || ((flags&ActivityManager.RECENT_WITH_EXCLUDED) != 0)
                        || withExcluded
                        || (tr.intent == null)
                        || ((tr.intent.getFlags()
                                &Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)) {
                        || ((tr.intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
                                == 0)) {
                    if (!allowed) {
                        // If the caller doesn't have the GET_TASKS permission, then only
                        // allow them to see a small subset of tasks -- their own and home.
@@ -7439,6 +7494,7 @@ public final class ActivityManagerService extends ActivityManagerNative
    private void cleanUpRemovedTaskLocked(TaskRecord tr, int flags) {
        tr.disposeThumbnail();
        mRecentTasks.remove(tr);
        tr.closeRecentsChain();
        final boolean killProcesses = (flags&ActivityManager.REMOVE_TASK_KILL_PROCESS) != 0;
        Intent baseIntent = new Intent(
                tr.intent != null ? tr.intent : tr.affinityIntent);
+15 −6
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

package com.android.server.am;

import android.app.ActivityManager;
import android.app.ActivityManager.TaskDescription;
import android.os.PersistableBundle;
import android.os.Trace;
@@ -498,7 +497,7 @@ final class ActivityRecord {
        }
    }

    void setTask(TaskRecord newTask, boolean isRoot) {
    void setTask(TaskRecord newTask, TaskRecord taskToAffiliateWith) {
        if (task != null && task.removeActivity(this)) {
            if (task != newTask) {
                task.stack.removeTask(task);
@@ -508,6 +507,15 @@ final class ActivityRecord {
            }
        }
        task = newTask;
        setTaskToAffiliateWith(taskToAffiliateWith);
    }

    void setTaskToAffiliateWith(TaskRecord taskToAffiliateWith) {
        if (taskToAffiliateWith != null &&
                launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE &&
                launchMode != ActivityInfo.LAUNCH_SINGLE_TASK) {
            task.setTaskToAffiliateWith(taskToAffiliateWith);
        }
    }

    boolean changeWindowTranslucency(boolean toOpaque) {
@@ -1038,8 +1046,8 @@ final class ActivityRecord {
        return null;
    }

    private static String createImageFilename(ActivityRecord r) {
        return String.valueOf(r.task.taskId) + ACTIVITY_ICON_SUFFIX + r.createTime +
    private static String createImageFilename(ActivityRecord r, int taskId) {
        return String.valueOf(taskId) + ACTIVITY_ICON_SUFFIX + r.createTime +
                TaskPersister.IMAGE_EXTENSION;
    }

@@ -1056,7 +1064,8 @@ final class ActivityRecord {
        out.attribute(null, ATTR_USERID, String.valueOf(userId));

        if (taskDescription != null) {
            task.saveTaskDescription(taskDescription, createImageFilename(this), out);
            task.saveTaskDescription(taskDescription, createImageFilename(this, task.taskId),
                    out);
        }

        out.startTag(null, TAG_INTENT);
@@ -1148,7 +1157,7 @@ final class ActivityRecord {
        r.persistentState = persistentState;

        if (createTime >= 0) {
            taskDescription.setIcon(TaskPersister.restoreImage(createImageFilename(r)));
            taskDescription.setIcon(TaskPersister.restoreImage(createImageFilename(r, taskId)));
        }
        r.taskDescription = taskDescription;
        r.createTime = createTime;
Loading