TaskStack.java revision 9756755db76aeda2065322aa3c26e1a19578d45f
1303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung/*
2303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung * Copyright (C) 2014 The Android Open Source Project
3303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung *
4303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung * Licensed under the Apache License, Version 2.0 (the "License");
5303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung * you may not use this file except in compliance with the License.
6303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung * You may obtain a copy of the License at
7303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung *
8303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung *      http://www.apache.org/licenses/LICENSE-2.0
9303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung *
10303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung * Unless required by applicable law or agreed to in writing, software
11303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung * distributed under the License is distributed on an "AS IS" BASIS,
12303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung * See the License for the specific language governing permissions and
14303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung * limitations under the License.
15303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung */
16303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
17303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chungpackage com.android.systemui.recents.model;
18303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
19882072baacaee4ecd43f0209b691a9af746462f2Winsonimport android.animation.ObjectAnimator;
20e7f138c7f0a190c86cec10fb32fa106aacae4093Winsonimport android.content.ComponentName;
2135f3050959e43bf378f9a0adcaef13729206c7e4Winsonimport android.content.Context;
22ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chungimport android.graphics.Color;
23be7607af8875236b9cf7bdb5f5aa089c207529afWinsonimport android.graphics.Rect;
24be7607af8875236b9cf7bdb5f5aa089c207529afWinsonimport android.graphics.RectF;
25882072baacaee4ecd43f0209b691a9af746462f2Winsonimport android.graphics.drawable.ColorDrawable;
262b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chungimport android.util.SparseArray;
272536c7ed446203ea12b38cf05a88e603f8d1b768Winsonimport com.android.systemui.R;
28e7f138c7f0a190c86cec10fb32fa106aacae4093Winsonimport com.android.systemui.recents.Recents;
29c742f973b1e506732911c156c5869fd377afc5bfWinsonimport com.android.systemui.recents.RecentsDebugFlags;
30ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chungimport com.android.systemui.recents.misc.NamedCounter;
31e7f138c7f0a190c86cec10fb32fa106aacae4093Winsonimport com.android.systemui.recents.misc.SystemServicesProxy;
32a0e88b5013d708ac6ed6518817d83c64c87ae4b1Winson Chungimport com.android.systemui.recents.misc.Utilities;
33eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winsonimport com.android.systemui.recents.views.DropTarget;
34303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
35303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chungimport java.util.ArrayList;
36ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chungimport java.util.Collections;
37ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chungimport java.util.Comparator;
38ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chungimport java.util.HashMap;
39e7f138c7f0a190c86cec10fb32fa106aacae4093Winsonimport java.util.HashSet;
40303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chungimport java.util.List;
41a433fa9c17772f563163ff7db177d091d6aebd5bWinson Chungimport java.util.Random;
42303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
43be7607af8875236b9cf7bdb5f5aa089c207529afWinsonimport static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT;
44be7607af8875236b9cf7bdb5f5aa089c207529afWinsonimport static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
45eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winsonimport static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
46eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winsonimport static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
47be7607af8875236b9cf7bdb5f5aa089c207529afWinson
48303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
49303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung/**
50303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung * An interface for a task filter to query whether a particular task should show in a stack.
51303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung */
52303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chunginterface TaskFilter {
53303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Returns whether the filter accepts the specified task */
542b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung    public boolean acceptTask(SparseArray<Task> taskIdMap, Task t, int index);
55303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung}
56303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
57303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung/**
58303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung * A list of filtered tasks.
59303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung */
60303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chungclass FilteredTaskList {
61eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson
62eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson    private static final String TAG = "FilteredTaskList";
638b1871d74137d7e36ba0fed5608772f51f62015bWinson    private static final boolean DEBUG = false;
64eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson
65eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson    ArrayList<Task> mTasks = new ArrayList<>();
66eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson    ArrayList<Task> mFilteredTasks = new ArrayList<>();
67eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson    HashMap<Task.TaskKey, Integer> mTaskIndices = new HashMap<>();
68303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    TaskFilter mFilter;
69303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
70303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Sets the task filter, saving the current touch state */
71c6a1623cc48581380b698ae87b43bfafb9c935baWinson Chung    boolean setFilter(TaskFilter filter) {
72c6a1623cc48581380b698ae87b43bfafb9c935baWinson Chung        ArrayList<Task> prevFilteredTasks = new ArrayList<Task>(mFilteredTasks);
73303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mFilter = filter;
74303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        updateFilteredTasks();
75b44c24fb50845dfbc1f49e78085cf5e01a32067fWinson Chung        if (!prevFilteredTasks.equals(mFilteredTasks)) {
76b44c24fb50845dfbc1f49e78085cf5e01a32067fWinson Chung            return true;
77b44c24fb50845dfbc1f49e78085cf5e01a32067fWinson Chung        } else {
78b44c24fb50845dfbc1f49e78085cf5e01a32067fWinson Chung            return false;
79b44c24fb50845dfbc1f49e78085cf5e01a32067fWinson Chung        }
80303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
81303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
828f0e3a68cdd3b2403ff8a1677f90b998f4175f40Winson    /**
838f0e3a68cdd3b2403ff8a1677f90b998f4175f40Winson     * Resets the task list, but does not remove the filter.
848f0e3a68cdd3b2403ff8a1677f90b998f4175f40Winson     */
85bc571a980704dc767838935e83c6aed231c406e9Winson Chung    void reset() {
86bc571a980704dc767838935e83c6aed231c406e9Winson Chung        mTasks.clear();
87bc571a980704dc767838935e83c6aed231c406e9Winson Chung        mFilteredTasks.clear();
88bc571a980704dc767838935e83c6aed231c406e9Winson Chung        mTaskIndices.clear();
89bc571a980704dc767838935e83c6aed231c406e9Winson Chung    }
90bc571a980704dc767838935e83c6aed231c406e9Winson Chung
91303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Removes the task filter and returns the previous touch state */
92303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    void removeFilter() {
93303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mFilter = null;
94303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        updateFilteredTasks();
95303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
96303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
97303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Adds a new task to the task list */
98303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    void add(Task t) {
99303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mTasks.add(t);
100303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        updateFilteredTasks();
101303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
102303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
103eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson    /**
104eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson     * Moves the given task.
105eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson     */
106eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson    public void moveTaskToStack(Task task, int insertIndex, int newStackId) {
107eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson        int taskIndex = indexOf(task);
108eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson        if (taskIndex != insertIndex) {
109eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson            mTasks.remove(taskIndex);
110eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson            if (taskIndex < insertIndex) {
111eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson                insertIndex--;
112eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson            }
113eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson            mTasks.add(insertIndex, task);
114eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson        }
115eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson
116eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson        // Update the stack id now, after we've moved the task, and before we update the
117eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson        // filtered tasks
118eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson        task.setStackId(newStackId);
119eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson        updateFilteredTasks();
120eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson    }
121eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson
122303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Sets the list of tasks */
123303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    void set(List<Task> tasks) {
124303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mTasks.clear();
125303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mTasks.addAll(tasks);
126303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        updateFilteredTasks();
127303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
128303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
129303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Removes a task from the base list only if it is in the filtered list */
130303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    boolean remove(Task t) {
131303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        if (mFilteredTasks.contains(t)) {
132303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            boolean removed = mTasks.remove(t);
133303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            updateFilteredTasks();
134303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            return removed;
135303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        }
136303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        return false;
137303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
138303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
139303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Returns the index of this task in the list of filtered tasks */
140303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    int indexOf(Task t) {
14123746d51d922d3df2cdd2635d0c133366c754438Winson        if (t != null && mTaskIndices.containsKey(t.key)) {
142a4ccb86ddc8f9f486aee25fb836f4aff97bf7679Winson Chung            return mTaskIndices.get(t.key);
143a4ccb86ddc8f9f486aee25fb836f4aff97bf7679Winson Chung        }
144a4ccb86ddc8f9f486aee25fb836f4aff97bf7679Winson Chung        return -1;
145303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
146303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
147303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Returns the size of the list of filtered tasks */
148303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    int size() {
149303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        return mFilteredTasks.size();
150303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
151303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
152303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Returns whether the filtered list contains this task */
153303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    boolean contains(Task t) {
154ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        return mTaskIndices.containsKey(t.key);
155303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
156303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
157303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Updates the list of filtered tasks whenever the base task list changes */
158303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    private void updateFilteredTasks() {
159303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mFilteredTasks.clear();
160303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        if (mFilter != null) {
1612b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung            // Create a sparse array from task id to Task
1622b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung            SparseArray<Task> taskIdMap = new SparseArray<>();
163303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            int taskCount = mTasks.size();
164303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            for (int i = 0; i < taskCount; i++) {
165303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                Task t = mTasks.get(i);
1662b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung                taskIdMap.put(t.key.id, t);
1672b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung            }
1682b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung
1692b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung            for (int i = 0; i < taskCount; i++) {
1702b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung                Task t = mTasks.get(i);
1712b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung                if (mFilter.acceptTask(taskIdMap, t, i)) {
172303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                    mFilteredTasks.add(t);
173303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                }
174303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            }
175303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        } else {
176303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            mFilteredTasks.addAll(mTasks);
177303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        }
178ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        updateFilteredTaskIndices();
179ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    }
180ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
181ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    /** Updates the mapping of tasks to indices. */
182ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    private void updateFilteredTaskIndices() {
183ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        mTaskIndices.clear();
184ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        int taskCount = mFilteredTasks.size();
185ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        for (int i = 0; i < taskCount; i++) {
186ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            Task t = mFilteredTasks.get(i);
187ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            mTaskIndices.put(t.key, i);
188ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        }
189303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
190303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
191303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Returns whether this task list is filtered */
192303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    boolean hasFilter() {
193303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        return (mFilter != null);
194303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
195303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
196303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Returns the list of filtered tasks */
197303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    ArrayList<Task> getTasks() {
198303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        return mFilteredTasks;
199303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
200303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung}
201303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
202303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung/**
203303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung * The task stack contains a list of multiple tasks.
204303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung */
205303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chungpublic class TaskStack {
206ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
207ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    /** Task stack callbacks */
20804dfe0d26b944324ee920001f40d74cff47281d6Winson Chung    public interface TaskStackCallbacks {
209062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        /**
210062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung         * Notifies when a new task has been added to the stack.
211062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung         */
212062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        void onStackTaskAdded(TaskStack stack, Task newTask);
213062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung
214062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        /**
215062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung         * Notifies when a task has been removed from the stack.
216062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung         */
217aaf33bc2b27fa0c4b59484059434a0fad3187af4Winson        void onStackTaskRemoved(TaskStack stack, Task removedTask, boolean wasFrontMostTask,
218aaf33bc2b27fa0c4b59484059434a0fad3187af4Winson            Task newFrontMostTask);
219a0731a1a2611d5a89c5960fe39a7ff09cc8fd5eaWinson
220062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        /**
221062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung         * Notifies when a task has been removed from the history.
222062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung         */
223a0731a1a2611d5a89c5960fe39a7ff09cc8fd5eaWinson        void onHistoryTaskRemoved(TaskStack stack, Task removedTask);
22404dfe0d26b944324ee920001f40d74cff47281d6Winson Chung    }
22504dfe0d26b944324ee920001f40d74cff47281d6Winson Chung
226250608a5cd08862f4752a924d51710805850db8aWinson    /**
227250608a5cd08862f4752a924d51710805850db8aWinson     * The various possible dock states when dragging and dropping a task.
228250608a5cd08862f4752a924d51710805850db8aWinson     */
229f0d1c44a59a10707baa0cca8dd377302260710c1Winson    public static class DockState implements DropTarget {
230f0d1c44a59a10707baa0cca8dd377302260710c1Winson
231f0d1c44a59a10707baa0cca8dd377302260710c1Winson        private static final int DOCK_AREA_ALPHA = 192;
232f0d1c44a59a10707baa0cca8dd377302260710c1Winson        public static final DockState NONE = new DockState(-1, 96, null, null);
233f0d1c44a59a10707baa0cca8dd377302260710c1Winson        public static final DockState LEFT = new DockState(
234f0d1c44a59a10707baa0cca8dd377302260710c1Winson                DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, DOCK_AREA_ALPHA,
235f0d1c44a59a10707baa0cca8dd377302260710c1Winson                new RectF(0, 0, 0.25f, 1), new RectF(0, 0, 0.25f, 1));
236f0d1c44a59a10707baa0cca8dd377302260710c1Winson        public static final DockState TOP = new DockState(
237f0d1c44a59a10707baa0cca8dd377302260710c1Winson                DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, DOCK_AREA_ALPHA,
238f0d1c44a59a10707baa0cca8dd377302260710c1Winson                new RectF(0, 0, 1, 0.25f), new RectF(0, 0, 1, 0.25f));
239f0d1c44a59a10707baa0cca8dd377302260710c1Winson        public static final DockState RIGHT = new DockState(
240f0d1c44a59a10707baa0cca8dd377302260710c1Winson                DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT, DOCK_AREA_ALPHA,
241f0d1c44a59a10707baa0cca8dd377302260710c1Winson                new RectF(0.75f, 0, 1, 1), new RectF(0.75f, 0, 1, 1));
242f0d1c44a59a10707baa0cca8dd377302260710c1Winson        public static final DockState BOTTOM = new DockState(
243f0d1c44a59a10707baa0cca8dd377302260710c1Winson                DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT, DOCK_AREA_ALPHA,
244eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson                new RectF(0, 0.75f, 1, 1), new RectF(0, 0.75f, 1, 1));
245eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson
246eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson        @Override
247eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson        public boolean acceptsDrop(int x, int y, int width, int height) {
248eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson            return touchAreaContainsPoint(width, height, x, y);
249eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson        }
250be7607af8875236b9cf7bdb5f5aa089c207529afWinson
251882072baacaee4ecd43f0209b691a9af746462f2Winson        // Represents the view state of this dock state
252882072baacaee4ecd43f0209b691a9af746462f2Winson        public class ViewState {
253882072baacaee4ecd43f0209b691a9af746462f2Winson            public final int dockAreaAlpha;
254882072baacaee4ecd43f0209b691a9af746462f2Winson            public final ColorDrawable dockAreaOverlay;
255882072baacaee4ecd43f0209b691a9af746462f2Winson            private ObjectAnimator dockAreaOverlayAnimator;
256882072baacaee4ecd43f0209b691a9af746462f2Winson
257882072baacaee4ecd43f0209b691a9af746462f2Winson            private ViewState(int alpha) {
258882072baacaee4ecd43f0209b691a9af746462f2Winson                dockAreaAlpha = alpha;
259882072baacaee4ecd43f0209b691a9af746462f2Winson                dockAreaOverlay = new ColorDrawable(0xFFffffff);
260882072baacaee4ecd43f0209b691a9af746462f2Winson                dockAreaOverlay.setAlpha(0);
261882072baacaee4ecd43f0209b691a9af746462f2Winson            }
262882072baacaee4ecd43f0209b691a9af746462f2Winson
263882072baacaee4ecd43f0209b691a9af746462f2Winson            /**
264882072baacaee4ecd43f0209b691a9af746462f2Winson             * Creates a new alpha animation.
265882072baacaee4ecd43f0209b691a9af746462f2Winson             */
266882072baacaee4ecd43f0209b691a9af746462f2Winson            public void startAlphaAnimation(int alpha, int duration) {
267882072baacaee4ecd43f0209b691a9af746462f2Winson                if (dockAreaOverlay.getAlpha() != alpha) {
268882072baacaee4ecd43f0209b691a9af746462f2Winson                    if (dockAreaOverlayAnimator != null) {
269882072baacaee4ecd43f0209b691a9af746462f2Winson                        dockAreaOverlayAnimator.cancel();
270882072baacaee4ecd43f0209b691a9af746462f2Winson                    }
271882072baacaee4ecd43f0209b691a9af746462f2Winson                    dockAreaOverlayAnimator = ObjectAnimator.ofInt(dockAreaOverlay, "alpha", alpha);
272882072baacaee4ecd43f0209b691a9af746462f2Winson                    dockAreaOverlayAnimator.setDuration(duration);
273882072baacaee4ecd43f0209b691a9af746462f2Winson                    dockAreaOverlayAnimator.start();
274882072baacaee4ecd43f0209b691a9af746462f2Winson                }
275882072baacaee4ecd43f0209b691a9af746462f2Winson            }
276882072baacaee4ecd43f0209b691a9af746462f2Winson        }
277882072baacaee4ecd43f0209b691a9af746462f2Winson
278be7607af8875236b9cf7bdb5f5aa089c207529afWinson        public final int createMode;
279882072baacaee4ecd43f0209b691a9af746462f2Winson        public final ViewState viewState;
280be7607af8875236b9cf7bdb5f5aa089c207529afWinson        private final RectF dockArea;
281882072baacaee4ecd43f0209b691a9af746462f2Winson        private final RectF touchArea;
282be7607af8875236b9cf7bdb5f5aa089c207529afWinson
283be7607af8875236b9cf7bdb5f5aa089c207529afWinson        /**
284be7607af8875236b9cf7bdb5f5aa089c207529afWinson         * @param createMode used to pass to ActivityManager to dock the task
285be7607af8875236b9cf7bdb5f5aa089c207529afWinson         * @param touchArea the area in which touch will initiate this dock state
286eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson         * @param dockArea the visible dock area
287be7607af8875236b9cf7bdb5f5aa089c207529afWinson         */
288eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson        DockState(int createMode, int dockAreaAlpha, RectF touchArea, RectF dockArea) {
289be7607af8875236b9cf7bdb5f5aa089c207529afWinson            this.createMode = createMode;
290882072baacaee4ecd43f0209b691a9af746462f2Winson            this.viewState = new ViewState(dockAreaAlpha);
291be7607af8875236b9cf7bdb5f5aa089c207529afWinson            this.dockArea = dockArea;
292882072baacaee4ecd43f0209b691a9af746462f2Winson            this.touchArea = touchArea;
293be7607af8875236b9cf7bdb5f5aa089c207529afWinson        }
294be7607af8875236b9cf7bdb5f5aa089c207529afWinson
295be7607af8875236b9cf7bdb5f5aa089c207529afWinson        /**
296be7607af8875236b9cf7bdb5f5aa089c207529afWinson         * Returns whether {@param x} and {@param y} are contained in the touch area scaled to the
297be7607af8875236b9cf7bdb5f5aa089c207529afWinson         * given {@param width} and {@param height}.
298be7607af8875236b9cf7bdb5f5aa089c207529afWinson         */
299be7607af8875236b9cf7bdb5f5aa089c207529afWinson        public boolean touchAreaContainsPoint(int width, int height, float x, float y) {
300be7607af8875236b9cf7bdb5f5aa089c207529afWinson            int left = (int) (touchArea.left * width);
301be7607af8875236b9cf7bdb5f5aa089c207529afWinson            int top = (int) (touchArea.top * height);
302be7607af8875236b9cf7bdb5f5aa089c207529afWinson            int right = (int) (touchArea.right * width);
303be7607af8875236b9cf7bdb5f5aa089c207529afWinson            int bottom = (int) (touchArea.bottom * height);
304be7607af8875236b9cf7bdb5f5aa089c207529afWinson            return x >= left && y >= top && x <= right && y <= bottom;
305be7607af8875236b9cf7bdb5f5aa089c207529afWinson        }
306be7607af8875236b9cf7bdb5f5aa089c207529afWinson
307be7607af8875236b9cf7bdb5f5aa089c207529afWinson        /**
308be7607af8875236b9cf7bdb5f5aa089c207529afWinson         * Returns the docked task bounds with the given {@param width} and {@param height}.
309be7607af8875236b9cf7bdb5f5aa089c207529afWinson         */
310be7607af8875236b9cf7bdb5f5aa089c207529afWinson        public Rect getDockedBounds(int width, int height) {
311be7607af8875236b9cf7bdb5f5aa089c207529afWinson            return new Rect((int) (dockArea.left * width), (int) (dockArea.top * height),
312be7607af8875236b9cf7bdb5f5aa089c207529afWinson                    (int) (dockArea.right * width), (int) (dockArea.bottom * height));
313be7607af8875236b9cf7bdb5f5aa089c207529afWinson        }
314be7607af8875236b9cf7bdb5f5aa089c207529afWinson    }
315be7607af8875236b9cf7bdb5f5aa089c207529afWinson
316250608a5cd08862f4752a924d51710805850db8aWinson    // A comparator that sorts tasks by their last active time
317250608a5cd08862f4752a924d51710805850db8aWinson    private Comparator<Task> LAST_ACTIVE_TIME_COMPARATOR = new Comparator<Task>() {
318250608a5cd08862f4752a924d51710805850db8aWinson        @Override
319250608a5cd08862f4752a924d51710805850db8aWinson        public int compare(Task o1, Task o2) {
320250608a5cd08862f4752a924d51710805850db8aWinson            return Long.compare(o1.key.lastActiveTime, o2.key.lastActiveTime);
321250608a5cd08862f4752a924d51710805850db8aWinson        }
322250608a5cd08862f4752a924d51710805850db8aWinson    };
323250608a5cd08862f4752a924d51710805850db8aWinson
324083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung    // The task offset to apply to a task id as a group affiliation
325083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung    static final int IndividualTaskIdOffset = 1 << 16;
326083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung
327062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung    ArrayList<Task> mRawTaskList = new ArrayList<>();
328250608a5cd08862f4752a924d51710805850db8aWinson    FilteredTaskList mStackTaskList = new FilteredTaskList();
329250608a5cd08862f4752a924d51710805850db8aWinson    FilteredTaskList mHistoryTaskList = new FilteredTaskList();
330303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    TaskStackCallbacks mCb;
331303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
3328f0e3a68cdd3b2403ff8a1677f90b998f4175f40Winson    ArrayList<TaskGrouping> mGroups = new ArrayList<>();
3338f0e3a68cdd3b2403ff8a1677f90b998f4175f40Winson    HashMap<Integer, TaskGrouping> mAffinitiesGroups = new HashMap<>();
3348f0e3a68cdd3b2403ff8a1677f90b998f4175f40Winson
3358f0e3a68cdd3b2403ff8a1677f90b998f4175f40Winson    public TaskStack() {
3368f0e3a68cdd3b2403ff8a1677f90b998f4175f40Winson        // Ensure that we only show non-docked tasks
337250608a5cd08862f4752a924d51710805850db8aWinson        mStackTaskList.setFilter(new TaskFilter() {
3388f0e3a68cdd3b2403ff8a1677f90b998f4175f40Winson            @Override
3392b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung            public boolean acceptTask(SparseArray<Task> taskIdMap, Task t, int index) {
3402b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung                if (t.isAffiliatedTask()) {
3412b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung                    // If this task is affiliated with another parent in the stack, then the historical state of this
3422b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung                    // task depends on the state of the parent task
3432b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung                    Task parentTask = taskIdMap.get(t.taskAffiliationId);
3442b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung                    if (parentTask != null) {
3452b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung                        t = parentTask;
3462b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung                    }
3472b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung                }
348250608a5cd08862f4752a924d51710805850db8aWinson                return !t.isHistorical && !SystemServicesProxy.isDockedStack(t.key.stackId);
349250608a5cd08862f4752a924d51710805850db8aWinson            }
350250608a5cd08862f4752a924d51710805850db8aWinson        });
351250608a5cd08862f4752a924d51710805850db8aWinson        mHistoryTaskList.setFilter(new TaskFilter() {
352250608a5cd08862f4752a924d51710805850db8aWinson            @Override
3532b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung            public boolean acceptTask(SparseArray<Task> taskIdMap, Task t, int index) {
3542b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung                if (t.isAffiliatedTask()) {
3552b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung                    // If this task is affiliated with another parent in the stack, then the historical state of this
3562b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung                    // task depends on the state of the parent task
3572b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung                    Task parentTask = taskIdMap.get(t.taskAffiliationId);
3582b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung                    if (parentTask != null) {
3592b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung                        t = parentTask;
3602b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung                    }
3612b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung                }
362250608a5cd08862f4752a924d51710805850db8aWinson                return t.isHistorical && !SystemServicesProxy.isDockedStack(t.key.stackId);
3638f0e3a68cdd3b2403ff8a1677f90b998f4175f40Winson            }
3648f0e3a68cdd3b2403ff8a1677f90b998f4175f40Winson        });
3658f0e3a68cdd3b2403ff8a1677f90b998f4175f40Winson    }
366303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
367d16c565a607de754379fe699a4def21bd0e3de2fWinson Chung    /** Sets the callbacks for this task stack. */
368303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    public void setCallbacks(TaskStackCallbacks cb) {
369303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mCb = cb;
370303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
371303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
372bc571a980704dc767838935e83c6aed231c406e9Winson Chung    /** Resets this TaskStack. */
373bc571a980704dc767838935e83c6aed231c406e9Winson Chung    public void reset() {
374bc571a980704dc767838935e83c6aed231c406e9Winson Chung        mCb = null;
375250608a5cd08862f4752a924d51710805850db8aWinson        mStackTaskList.reset();
376250608a5cd08862f4752a924d51710805850db8aWinson        mHistoryTaskList.reset();
377bc571a980704dc767838935e83c6aed231c406e9Winson Chung        mGroups.clear();
378bc571a980704dc767838935e83c6aed231c406e9Winson Chung        mAffinitiesGroups.clear();
379bc571a980704dc767838935e83c6aed231c406e9Winson Chung    }
380bc571a980704dc767838935e83c6aed231c406e9Winson Chung
381eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson    /**
382eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson     * Moves the given task to either the front of the freeform workspace or the stack.
383eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson     */
384eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson    public void moveTaskToStack(Task task, int newStackId) {
385eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson        // Find the index to insert into
386250608a5cd08862f4752a924d51710805850db8aWinson        ArrayList<Task> taskList = mStackTaskList.getTasks();
387eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson        int taskCount = taskList.size();
388eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson        if (!task.isFreeformTask() && (newStackId == FREEFORM_WORKSPACE_STACK_ID)) {
389eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson            // Insert freeform tasks at the front
390250608a5cd08862f4752a924d51710805850db8aWinson            mStackTaskList.moveTaskToStack(task, taskCount, newStackId);
391eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson        } else if (task.isFreeformTask() && (newStackId == FULLSCREEN_WORKSPACE_STACK_ID)) {
392eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson            // Insert after the first stacked task
393eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson            int insertIndex = 0;
394eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson            for (int i = taskCount - 1; i >= 0; i--) {
395eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson                if (!taskList.get(i).isFreeformTask()) {
396eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson                    insertIndex = i + 1;
397eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson                    break;
398eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson                }
399eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson            }
400250608a5cd08862f4752a924d51710805850db8aWinson            mStackTaskList.moveTaskToStack(task, insertIndex, newStackId);
401eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson        }
402eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson    }
403eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson
4046ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung    /** Does the actual work associated with removing the task. */
405250608a5cd08862f4752a924d51710805850db8aWinson    void removeTaskImpl(FilteredTaskList taskList, Task t) {
4066ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung        // Remove the task from the list
407250608a5cd08862f4752a924d51710805850db8aWinson        taskList.remove(t);
4086ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung        // Remove it from the group as well, and if it is empty, remove the group
4096ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung        TaskGrouping group = t.group;
4104e5fb2f4e1ed4eb119a201541ad89aafac8c53feWinson Chung        if (group != null) {
4114e5fb2f4e1ed4eb119a201541ad89aafac8c53feWinson Chung            group.removeTask(t);
4124e5fb2f4e1ed4eb119a201541ad89aafac8c53feWinson Chung            if (group.getTaskCount() == 0) {
4134e5fb2f4e1ed4eb119a201541ad89aafac8c53feWinson Chung                removeGroup(group);
4144e5fb2f4e1ed4eb119a201541ad89aafac8c53feWinson Chung            }
4156ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung        }
4166ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung        // Update the lock-to-app state
4176ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung        t.lockToThisTask = false;
4186ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung    }
4196ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung
420303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Removes a task */
421303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    public void removeTask(Task t) {
422250608a5cd08862f4752a924d51710805850db8aWinson        if (mStackTaskList.contains(t)) {
423250608a5cd08862f4752a924d51710805850db8aWinson            boolean wasFrontMostTask = (getStackFrontMostTask() == t);
424250608a5cd08862f4752a924d51710805850db8aWinson            removeTaskImpl(mStackTaskList, t);
425250608a5cd08862f4752a924d51710805850db8aWinson            Task newFrontMostTask = getStackFrontMostTask();
42656e09b42a0f1670970872bef611a8036904ad6bfJason Monk            if (newFrontMostTask != null && newFrontMostTask.lockToTaskEnabled) {
42756e09b42a0f1670970872bef611a8036904ad6bfJason Monk                newFrontMostTask.lockToThisTask = true;
4281f24c7e37bc794057a156a730c7e4b53b01212edWinson Chung            }
429303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            if (mCb != null) {
430ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                // Notify that a task has been removed
431aaf33bc2b27fa0c4b59484059434a0fad3187af4Winson                mCb.onStackTaskRemoved(this, t, wasFrontMostTask, newFrontMostTask);
432303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            }
433250608a5cd08862f4752a924d51710805850db8aWinson        } else if (mHistoryTaskList.contains(t)) {
434250608a5cd08862f4752a924d51710805850db8aWinson            removeTaskImpl(mHistoryTaskList, t);
435303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            if (mCb != null) {
436ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                // Notify that a task has been removed
437a0731a1a2611d5a89c5960fe39a7ff09cc8fd5eaWinson                mCb.onHistoryTaskRemoved(this, t);
438303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            }
439303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        }
440250608a5cd08862f4752a924d51710805850db8aWinson    }
441250608a5cd08862f4752a924d51710805850db8aWinson
442250608a5cd08862f4752a924d51710805850db8aWinson    /**
443250608a5cd08862f4752a924d51710805850db8aWinson     * Sets a few tasks in one go, without calling any callbacks.
444062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung     *
445062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung     * @param tasks the new set of tasks to replace the current set.
446062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung     * @param notifyStackChanges whether or not to callback on specific changes to the list of tasks.
447250608a5cd08862f4752a924d51710805850db8aWinson     */
448062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung    public void setTasks(List<Task> tasks, boolean notifyStackChanges) {
449062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        // Compute a has set for each of the tasks
450062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        HashMap<Task.TaskKey, Task> currentTasksMap = createTaskKeyMapFromList(mRawTaskList);
451062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        HashMap<Task.TaskKey, Task> newTasksMap = createTaskKeyMapFromList(tasks);
452062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung
453062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        ArrayList<Task> newTasks = new ArrayList<>();
454062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung
455062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        // Disable notifications if there are no callbacks
456062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        if (mCb == null) {
457062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung            notifyStackChanges = false;
458062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        }
459062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung
460062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        // Remove any tasks that no longer exist
461062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        int taskCount = mRawTaskList.size();
462062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        for (int i = 0; i < taskCount; i++) {
463062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung            Task task = mRawTaskList.get(i);
464062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung            if (!newTasksMap.containsKey(task.key)) {
465062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung                if (notifyStackChanges) {
466062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung                    mCb.onStackTaskRemoved(this, task, i == (taskCount - 1), null);
467062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung                }
468062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung            }
4699756755db76aeda2065322aa3c26e1a19578d45fWinson Chung            task.setGroup(null);
470062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        }
471062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung
472062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        // Add any new tasks
473062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        taskCount = tasks.size();
474062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        for (int i = 0; i < taskCount; i++) {
475062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung            Task task = tasks.get(i);
476062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung            if (!currentTasksMap.containsKey(task.key)) {
477062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung                if (notifyStackChanges) {
478062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung                    mCb.onStackTaskAdded(this, task);
479062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung                }
480062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung                newTasks.add(task);
481062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung            } else {
482062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung                newTasks.add(currentTasksMap.get(task.key));
483062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung            }
484062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        }
485062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung
486062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        // Sort all the tasks to ensure they are ordered correctly
487062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        Collections.sort(newTasks, LAST_ACTIVE_TIME_COMPARATOR);
488062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung
489062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        // TODO: Update screen pinning for the new front-most task post refactoring lockToTask out
490062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        // of the Task
491062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung
492062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        // Filter out the historical tasks from this new list
493250608a5cd08862f4752a924d51710805850db8aWinson        ArrayList<Task> stackTasks = new ArrayList<>();
494250608a5cd08862f4752a924d51710805850db8aWinson        ArrayList<Task> historyTasks = new ArrayList<>();
495062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        int newTaskCount = newTasks.size();
496062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        for (int i = 0; i < newTaskCount; i++) {
497062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung            Task task = newTasks.get(i);
498250608a5cd08862f4752a924d51710805850db8aWinson            if (task.isHistorical) {
499250608a5cd08862f4752a924d51710805850db8aWinson                historyTasks.add(task);
500250608a5cd08862f4752a924d51710805850db8aWinson            } else {
501250608a5cd08862f4752a924d51710805850db8aWinson                stackTasks.add(task);
502303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            }
503303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        }
504062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung
505250608a5cd08862f4752a924d51710805850db8aWinson        mStackTaskList.set(stackTasks);
506250608a5cd08862f4752a924d51710805850db8aWinson        mHistoryTaskList.set(historyTasks);
507062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        mRawTaskList.clear();
508062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        mRawTaskList.addAll(newTasks);
5099756755db76aeda2065322aa3c26e1a19578d45fWinson Chung        mGroups.clear();
5109756755db76aeda2065322aa3c26e1a19578d45fWinson Chung        mAffinitiesGroups.clear();
511303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
512303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
513ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    /** Gets the front task */
514250608a5cd08862f4752a924d51710805850db8aWinson    public Task getStackFrontMostTask() {
515250608a5cd08862f4752a924d51710805850db8aWinson        if (mStackTaskList.size() == 0) return null;
516250608a5cd08862f4752a924d51710805850db8aWinson        return mStackTaskList.getTasks().get(mStackTaskList.size() - 1);
517ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    }
518ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
51904400672962d2e12132f9465928cbf7615c147c4Winson Chung    /** Gets the task keys */
52004400672962d2e12132f9465928cbf7615c147c4Winson Chung    public ArrayList<Task.TaskKey> getTaskKeys() {
5218f0e3a68cdd3b2403ff8a1677f90b998f4175f40Winson        ArrayList<Task.TaskKey> taskKeys = new ArrayList<>();
522250608a5cd08862f4752a924d51710805850db8aWinson        ArrayList<Task> tasks = computeAllTasksList();
52304400672962d2e12132f9465928cbf7615c147c4Winson Chung        int taskCount = tasks.size();
52404400672962d2e12132f9465928cbf7615c147c4Winson Chung        for (int i = 0; i < taskCount; i++) {
525250608a5cd08862f4752a924d51710805850db8aWinson            Task task = tasks.get(i);
526250608a5cd08862f4752a924d51710805850db8aWinson            taskKeys.add(task.key);
52704400672962d2e12132f9465928cbf7615c147c4Winson Chung        }
52804400672962d2e12132f9465928cbf7615c147c4Winson Chung        return taskKeys;
52904400672962d2e12132f9465928cbf7615c147c4Winson Chung    }
53004400672962d2e12132f9465928cbf7615c147c4Winson Chung
531250608a5cd08862f4752a924d51710805850db8aWinson    /**
532250608a5cd08862f4752a924d51710805850db8aWinson     * Returns the set of "active" (non-historical) tasks in the stack that have been used recently.
533250608a5cd08862f4752a924d51710805850db8aWinson     */
534250608a5cd08862f4752a924d51710805850db8aWinson    public ArrayList<Task> getStackTasks() {
535250608a5cd08862f4752a924d51710805850db8aWinson        return mStackTaskList.getTasks();
536250608a5cd08862f4752a924d51710805850db8aWinson    }
537250608a5cd08862f4752a924d51710805850db8aWinson
538250608a5cd08862f4752a924d51710805850db8aWinson    /**
539250608a5cd08862f4752a924d51710805850db8aWinson     * Returns the set of tasks that are inactive. These tasks will be presented in a separate
540250608a5cd08862f4752a924d51710805850db8aWinson     * history view.
541250608a5cd08862f4752a924d51710805850db8aWinson     */
542250608a5cd08862f4752a924d51710805850db8aWinson    public ArrayList<Task> getHistoricalTasks() {
543250608a5cd08862f4752a924d51710805850db8aWinson        return mHistoryTaskList.getTasks();
544303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
545303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
546250608a5cd08862f4752a924d51710805850db8aWinson    /**
547250608a5cd08862f4752a924d51710805850db8aWinson     * Computes a set of all the active and historical tasks ordered by their last active time.
548250608a5cd08862f4752a924d51710805850db8aWinson     */
549250608a5cd08862f4752a924d51710805850db8aWinson    public ArrayList<Task> computeAllTasksList() {
550250608a5cd08862f4752a924d51710805850db8aWinson        ArrayList<Task> tasks = new ArrayList<>();
551250608a5cd08862f4752a924d51710805850db8aWinson        tasks.addAll(mStackTaskList.getTasks());
552250608a5cd08862f4752a924d51710805850db8aWinson        tasks.addAll(mHistoryTaskList.getTasks());
553250608a5cd08862f4752a924d51710805850db8aWinson        Collections.sort(tasks, LAST_ACTIVE_TIME_COMPARATOR);
554250608a5cd08862f4752a924d51710805850db8aWinson        return tasks;
555303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
556303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
55736a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson    /**
558250608a5cd08862f4752a924d51710805850db8aWinson     * Returns the number of tasks in the active stack.
559250608a5cd08862f4752a924d51710805850db8aWinson     */
560250608a5cd08862f4752a924d51710805850db8aWinson    public int getStackTaskCount() {
561250608a5cd08862f4752a924d51710805850db8aWinson        return mStackTaskList.size();
562250608a5cd08862f4752a924d51710805850db8aWinson    }
563250608a5cd08862f4752a924d51710805850db8aWinson
564250608a5cd08862f4752a924d51710805850db8aWinson    /**
565f0d1c44a59a10707baa0cca8dd377302260710c1Winson     * Returns the number of freeform tasks in the active stack.
566f0d1c44a59a10707baa0cca8dd377302260710c1Winson     */
567f0d1c44a59a10707baa0cca8dd377302260710c1Winson    public int getStackTaskFreeformCount() {
568f0d1c44a59a10707baa0cca8dd377302260710c1Winson        ArrayList<Task> tasks = mStackTaskList.getTasks();
569f0d1c44a59a10707baa0cca8dd377302260710c1Winson        int freeformCount = 0;
570f0d1c44a59a10707baa0cca8dd377302260710c1Winson        int taskCount = tasks.size();
571f0d1c44a59a10707baa0cca8dd377302260710c1Winson        for (int i = 0; i < taskCount; i++) {
572f0d1c44a59a10707baa0cca8dd377302260710c1Winson            Task task = tasks.get(i);
573f0d1c44a59a10707baa0cca8dd377302260710c1Winson            if (task.isFreeformTask()) {
574f0d1c44a59a10707baa0cca8dd377302260710c1Winson                freeformCount++;
575f0d1c44a59a10707baa0cca8dd377302260710c1Winson            }
576f0d1c44a59a10707baa0cca8dd377302260710c1Winson        }
577f0d1c44a59a10707baa0cca8dd377302260710c1Winson        return freeformCount;
578f0d1c44a59a10707baa0cca8dd377302260710c1Winson    }
579f0d1c44a59a10707baa0cca8dd377302260710c1Winson
580f0d1c44a59a10707baa0cca8dd377302260710c1Winson    /**
581250608a5cd08862f4752a924d51710805850db8aWinson     * Returns the task in stack tasks which is the launch target.
58236a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson     */
58336a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson    public Task getLaunchTarget() {
584250608a5cd08862f4752a924d51710805850db8aWinson        ArrayList<Task> tasks = mStackTaskList.getTasks();
58536a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson        int taskCount = tasks.size();
58636a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson        for (int i = 0; i < taskCount; i++) {
58736a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson            Task task = tasks.get(i);
58836a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson            if (task.isLaunchTarget) {
58936a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson                return task;
59036a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson            }
59136a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson        }
59236a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson        return null;
59336a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson    }
59436a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson
595303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Returns the index of this task in this current task stack */
596250608a5cd08862f4752a924d51710805850db8aWinson    public int indexOfStackTask(Task t) {
597250608a5cd08862f4752a924d51710805850db8aWinson        return mStackTaskList.indexOf(t);
598303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
599303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
600b1f749906f5c27114d02ea0c3f8ce0dcea08fd3fWinson Chung    /** Finds the task with the specified task id. */
601b1f749906f5c27114d02ea0c3f8ce0dcea08fd3fWinson Chung    public Task findTaskWithId(int taskId) {
602250608a5cd08862f4752a924d51710805850db8aWinson        ArrayList<Task> tasks = computeAllTasksList();
603250608a5cd08862f4752a924d51710805850db8aWinson        for (Task task : tasks) {
604b1f749906f5c27114d02ea0c3f8ce0dcea08fd3fWinson Chung            if (task.key.id == taskId) {
605b1f749906f5c27114d02ea0c3f8ce0dcea08fd3fWinson Chung                return task;
606b1f749906f5c27114d02ea0c3f8ce0dcea08fd3fWinson Chung            }
607b1f749906f5c27114d02ea0c3f8ce0dcea08fd3fWinson Chung        }
608b1f749906f5c27114d02ea0c3f8ce0dcea08fd3fWinson Chung        return null;
609b1f749906f5c27114d02ea0c3f8ce0dcea08fd3fWinson Chung    }
610b1f749906f5c27114d02ea0c3f8ce0dcea08fd3fWinson Chung
611ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    /******** Grouping ********/
612ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
613ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    /** Adds a group to the set */
614ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    public void addGroup(TaskGrouping group) {
615ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        mGroups.add(group);
616ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        mAffinitiesGroups.put(group.affiliation, group);
617ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    }
618ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
619ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    public void removeGroup(TaskGrouping group) {
620ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        mGroups.remove(group);
621ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        mAffinitiesGroups.remove(group.affiliation);
622ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    }
623ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
624ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    /** Returns the group with the specified affiliation. */
625083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung    public TaskGrouping getGroupWithAffiliation(int affiliation) {
626ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        return mAffinitiesGroups.get(affiliation);
627ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    }
628ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
629ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    /**
630ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung     * Temporary: This method will simulate affiliation groups by
631ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung     */
63235f3050959e43bf378f9a0adcaef13729206c7e4Winson    public void createAffiliatedGroupings(Context context) {
633c742f973b1e506732911c156c5869fd377afc5bfWinson        if (RecentsDebugFlags.Static.EnableSimulatedTaskGroups) {
634ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            HashMap<Task.TaskKey, Task> taskMap = new HashMap<Task.TaskKey, Task>();
635ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            // Sort all tasks by increasing firstActiveTime of the task
636250608a5cd08862f4752a924d51710805850db8aWinson            ArrayList<Task> tasks = mStackTaskList.getTasks();
637ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            Collections.sort(tasks, new Comparator<Task>() {
638ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                @Override
639ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                public int compare(Task task, Task task2) {
64016bc2a7f379edd7796bb5aa4400e1b7c14376a08Winson Chung                    return Long.compare(task.key.firstActiveTime, task2.key.firstActiveTime);
641ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                }
642ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            });
643ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            // Create groups when sequential packages are the same
644ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            NamedCounter counter = new NamedCounter("task-group", "");
645ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            int taskCount = tasks.size();
646ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            String prevPackage = "";
647083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung            int prevAffiliation = -1;
648a433fa9c17772f563163ff7db177d091d6aebd5bWinson Chung            Random r = new Random();
649c742f973b1e506732911c156c5869fd377afc5bfWinson            int groupCountDown = RecentsDebugFlags.Static.TaskAffiliationsGroupCount;
650ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            for (int i = 0; i < taskCount; i++) {
651ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                Task t = tasks.get(i);
652e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                String packageName = t.key.getComponent().getPackageName();
653a433fa9c17772f563163ff7db177d091d6aebd5bWinson Chung                packageName = "pkg";
654ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                TaskGrouping group;
655a433fa9c17772f563163ff7db177d091d6aebd5bWinson Chung                if (packageName.equals(prevPackage) && groupCountDown > 0) {
656ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    group = getGroupWithAffiliation(prevAffiliation);
657a433fa9c17772f563163ff7db177d091d6aebd5bWinson Chung                    groupCountDown--;
658ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                } else {
659083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung                    int affiliation = IndividualTaskIdOffset + t.key.id;
660ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    group = new TaskGrouping(affiliation);
661ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    addGroup(group);
662ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    prevAffiliation = affiliation;
663ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    prevPackage = packageName;
664c742f973b1e506732911c156c5869fd377afc5bfWinson                    groupCountDown = RecentsDebugFlags.Static.TaskAffiliationsGroupCount;
665ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                }
666ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                group.addTask(t);
667ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                taskMap.put(t.key, t);
668ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            }
669ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            // Sort groups by increasing latestActiveTime of the group
670ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            Collections.sort(mGroups, new Comparator<TaskGrouping>() {
671ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                @Override
672ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                public int compare(TaskGrouping taskGrouping, TaskGrouping taskGrouping2) {
673ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    return (int) (taskGrouping.latestActiveTimeInGroup -
674ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                            taskGrouping2.latestActiveTimeInGroup);
675ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                }
676ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            });
6772b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung            // Sort group tasks by increasing firstActiveTime of the task, and also build a new list
6782b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung            // of tasks
679ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            int taskIndex = 0;
680ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            int groupCount = mGroups.size();
681ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            for (int i = 0; i < groupCount; i++) {
682ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                TaskGrouping group = mGroups.get(i);
683083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung                Collections.sort(group.mTaskKeys, new Comparator<Task.TaskKey>() {
684ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    @Override
685ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    public int compare(Task.TaskKey taskKey, Task.TaskKey taskKey2) {
686ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                        return (int) (taskKey.firstActiveTime - taskKey2.firstActiveTime);
687ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    }
688ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                });
689083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung                ArrayList<Task.TaskKey> groupTasks = group.mTaskKeys;
690ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                int groupTaskCount = groupTasks.size();
691ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                for (int j = 0; j < groupTaskCount; j++) {
692ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    tasks.set(taskIndex, taskMap.get(groupTasks.get(j)));
693ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    taskIndex++;
694ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                }
695ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            }
696250608a5cd08862f4752a924d51710805850db8aWinson            mStackTaskList.set(tasks);
697ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        } else {
698083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung            // Create the task groups
6992b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung            HashMap<Task.TaskKey, Task> tasksMap = new HashMap<>();
700250608a5cd08862f4752a924d51710805850db8aWinson            ArrayList<Task> tasks = mStackTaskList.getTasks();
701ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            int taskCount = tasks.size();
702ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            for (int i = 0; i < taskCount; i++) {
703ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                Task t = tasks.get(i);
704083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung                TaskGrouping group;
7052b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung                int affiliation = t.taskAffiliationId > 0 ? t.taskAffiliationId :
706083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung                        IndividualTaskIdOffset + t.key.id;
707083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung                if (mAffinitiesGroups.containsKey(affiliation)) {
708083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung                    group = getGroupWithAffiliation(affiliation);
709083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung                } else {
710083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung                    group = new TaskGrouping(affiliation);
711083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung                    addGroup(group);
712083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung                }
713ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                group.addTask(t);
714ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                tasksMap.put(t.key, t);
715ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung            }
716ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung            // Update the task colors for each of the groups
71735f3050959e43bf378f9a0adcaef13729206c7e4Winson            float minAlpha = context.getResources().getFloat(
71835f3050959e43bf378f9a0adcaef13729206c7e4Winson                    R.dimen.recents_task_affiliation_color_min_alpha_percentage);
719ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung            int taskGroupCount = mGroups.size();
720ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung            for (int i = 0; i < taskGroupCount; i++) {
721ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                TaskGrouping group = mGroups.get(i);
722ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                taskCount = group.getTaskCount();
723ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                // Ignore the groups that only have one task
724ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                if (taskCount <= 1) continue;
725ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                // Calculate the group color distribution
726ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                int affiliationColor = tasksMap.get(group.mTaskKeys.get(0)).taskAffiliationColor;
727ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                float alphaStep = (1f - minAlpha) / taskCount;
728ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                float alpha = 1f;
729ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                for (int j = 0; j < taskCount; j++) {
730ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                    Task t = tasksMap.get(group.mTaskKeys.get(j));
731a0e88b5013d708ac6ed6518817d83c64c87ae4b1Winson Chung                    t.colorPrimary = Utilities.getColorWithOverlay(affiliationColor, Color.WHITE,
732a0e88b5013d708ac6ed6518817d83c64c87ae4b1Winson Chung                            alpha);
733ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                    alpha -= alphaStep;
734ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                }
735ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            }
736ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        }
737ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    }
738ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
739e7f138c7f0a190c86cec10fb32fa106aacae4093Winson    /**
740e7f138c7f0a190c86cec10fb32fa106aacae4093Winson     * Computes the components of tasks in this stack that have been removed as a result of a change
741e7f138c7f0a190c86cec10fb32fa106aacae4093Winson     * in the specified package.
742e7f138c7f0a190c86cec10fb32fa106aacae4093Winson     */
743e7f138c7f0a190c86cec10fb32fa106aacae4093Winson    public HashSet<ComponentName> computeComponentsRemoved(String packageName, int userId) {
744e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        // Identify all the tasks that should be removed as a result of the package being removed.
745e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        // Using a set to ensure that we callback once per unique component.
746e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        SystemServicesProxy ssp = Recents.getSystemServices();
747e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        HashSet<ComponentName> existingComponents = new HashSet<>();
748e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        HashSet<ComponentName> removedComponents = new HashSet<>();
749e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        ArrayList<Task.TaskKey> taskKeys = getTaskKeys();
750e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        for (Task.TaskKey t : taskKeys) {
751e7f138c7f0a190c86cec10fb32fa106aacae4093Winson            // Skip if this doesn't apply to the current user
752e7f138c7f0a190c86cec10fb32fa106aacae4093Winson            if (t.userId != userId) continue;
753e7f138c7f0a190c86cec10fb32fa106aacae4093Winson
754e7f138c7f0a190c86cec10fb32fa106aacae4093Winson            ComponentName cn = t.getComponent();
755e7f138c7f0a190c86cec10fb32fa106aacae4093Winson            if (cn.getPackageName().equals(packageName)) {
756e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                if (existingComponents.contains(cn)) {
757e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                    // If we know that the component still exists in the package, then skip
758e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                    continue;
759e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                }
760e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                if (ssp.getActivityInfo(cn, userId) != null) {
761e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                    existingComponents.add(cn);
762e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                } else {
763e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                    removedComponents.add(cn);
764e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                }
765e7f138c7f0a190c86cec10fb32fa106aacae4093Winson            }
766e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        }
767e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        return removedComponents;
768e7f138c7f0a190c86cec10fb32fa106aacae4093Winson    }
769e7f138c7f0a190c86cec10fb32fa106aacae4093Winson
770303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    @Override
771303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    public String toString() {
772250608a5cd08862f4752a924d51710805850db8aWinson        String str = "Stack Tasks:\n";
773250608a5cd08862f4752a924d51710805850db8aWinson        for (Task t : mStackTaskList.getTasks()) {
774250608a5cd08862f4752a924d51710805850db8aWinson            str += "  " + t.toString() + "\n";
775250608a5cd08862f4752a924d51710805850db8aWinson        }
776250608a5cd08862f4752a924d51710805850db8aWinson        str += "Historical Tasks:\n";
777250608a5cd08862f4752a924d51710805850db8aWinson        for (Task t : mHistoryTaskList.getTasks()) {
778303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            str += "  " + t.toString() + "\n";
779303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        }
780303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        return str;
781303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
782062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung
783062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung    /**
784062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung     * Given a list of tasks, returns a map of each task's key to the task.
785062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung     */
786062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung    private HashMap<Task.TaskKey, Task> createTaskKeyMapFromList(List<Task> tasks) {
787062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        HashMap<Task.TaskKey, Task> map = new HashMap<>();
788062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        int taskCount = tasks.size();
789062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        for (int i = 0; i < taskCount; i++) {
790062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung            Task task = tasks.get(i);
791062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung            map.put(task.key, task);
792062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        }
793062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        return map;
794062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung    }
795062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung}
796