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
19ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chungimport android.graphics.Color;
20ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chungimport com.android.systemui.recents.Constants;
21ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chungimport com.android.systemui.recents.RecentsConfiguration;
22ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chungimport com.android.systemui.recents.misc.NamedCounter;
23a0e88b5013d708ac6ed6518817d83c64c87ae4b1Winson Chungimport com.android.systemui.recents.misc.Utilities;
24303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
25303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chungimport java.util.ArrayList;
26ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chungimport java.util.Collections;
27ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chungimport java.util.Comparator;
28ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chungimport java.util.HashMap;
29303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chungimport java.util.List;
30a433fa9c17772f563163ff7db177d091d6aebd5bWinson Chungimport java.util.Random;
31303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
32303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
33303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung/**
34303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung * An interface for a task filter to query whether a particular task should show in a stack.
35303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung */
36303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chunginterface TaskFilter {
37303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Returns whether the filter accepts the specified task */
38303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    public boolean acceptTask(Task t, int index);
39303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung}
40303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
41303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung/**
42303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung * A list of filtered tasks.
43303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung */
44303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chungclass FilteredTaskList {
45303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    ArrayList<Task> mTasks = new ArrayList<Task>();
46303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    ArrayList<Task> mFilteredTasks = new ArrayList<Task>();
47ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    HashMap<Task.TaskKey, Integer> mTaskIndices = new HashMap<Task.TaskKey, Integer>();
48303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    TaskFilter mFilter;
49303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
50303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Sets the task filter, saving the current touch state */
51c6a1623cc48581380b698ae87b43bfafb9c935baWinson Chung    boolean setFilter(TaskFilter filter) {
52c6a1623cc48581380b698ae87b43bfafb9c935baWinson Chung        ArrayList<Task> prevFilteredTasks = new ArrayList<Task>(mFilteredTasks);
53303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mFilter = filter;
54303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        updateFilteredTasks();
55b44c24fb50845dfbc1f49e78085cf5e01a32067fWinson Chung        if (!prevFilteredTasks.equals(mFilteredTasks)) {
56b44c24fb50845dfbc1f49e78085cf5e01a32067fWinson Chung            return true;
57b44c24fb50845dfbc1f49e78085cf5e01a32067fWinson Chung        } else {
58b44c24fb50845dfbc1f49e78085cf5e01a32067fWinson Chung            // If the tasks are exactly the same pre/post filter, then just reset it
59b44c24fb50845dfbc1f49e78085cf5e01a32067fWinson Chung            mFilter = null;
60b44c24fb50845dfbc1f49e78085cf5e01a32067fWinson Chung            return false;
61b44c24fb50845dfbc1f49e78085cf5e01a32067fWinson Chung        }
62303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
63303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
64bc571a980704dc767838935e83c6aed231c406e9Winson Chung    /** Resets this FilteredTaskList. */
65bc571a980704dc767838935e83c6aed231c406e9Winson Chung    void reset() {
66bc571a980704dc767838935e83c6aed231c406e9Winson Chung        mTasks.clear();
67bc571a980704dc767838935e83c6aed231c406e9Winson Chung        mFilteredTasks.clear();
68bc571a980704dc767838935e83c6aed231c406e9Winson Chung        mTaskIndices.clear();
69bc571a980704dc767838935e83c6aed231c406e9Winson Chung        mFilter = null;
70bc571a980704dc767838935e83c6aed231c406e9Winson Chung    }
71bc571a980704dc767838935e83c6aed231c406e9Winson Chung
72303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Removes the task filter and returns the previous touch state */
73303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    void removeFilter() {
74303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mFilter = null;
75303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        updateFilteredTasks();
76303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
77303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
78303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Adds a new task to the task list */
79303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    void add(Task t) {
80303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mTasks.add(t);
81303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        updateFilteredTasks();
82303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
83303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
84303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Sets the list of tasks */
85303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    void set(List<Task> tasks) {
86303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mTasks.clear();
87303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mTasks.addAll(tasks);
88303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        updateFilteredTasks();
89303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
90303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
91303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Removes a task from the base list only if it is in the filtered list */
92303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    boolean remove(Task t) {
93303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        if (mFilteredTasks.contains(t)) {
94303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            boolean removed = mTasks.remove(t);
95303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            updateFilteredTasks();
96303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            return removed;
97303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        }
98303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        return false;
99303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
100303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
101303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Returns the index of this task in the list of filtered tasks */
102303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    int indexOf(Task t) {
103a4ccb86ddc8f9f486aee25fb836f4aff97bf7679Winson Chung        if (mTaskIndices.containsKey(t.key)) {
104a4ccb86ddc8f9f486aee25fb836f4aff97bf7679Winson Chung            return mTaskIndices.get(t.key);
105a4ccb86ddc8f9f486aee25fb836f4aff97bf7679Winson Chung        }
106a4ccb86ddc8f9f486aee25fb836f4aff97bf7679Winson Chung        return -1;
107303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
108303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
109303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Returns the size of the list of filtered tasks */
110303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    int size() {
111303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        return mFilteredTasks.size();
112303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
113303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
114303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Returns whether the filtered list contains this task */
115303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    boolean contains(Task t) {
116ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        return mTaskIndices.containsKey(t.key);
117303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
118303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
119303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Updates the list of filtered tasks whenever the base task list changes */
120303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    private void updateFilteredTasks() {
121303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mFilteredTasks.clear();
122303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        if (mFilter != null) {
123303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            int taskCount = mTasks.size();
124303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            for (int i = 0; i < taskCount; i++) {
125303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                Task t = mTasks.get(i);
126303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                if (mFilter.acceptTask(t, i)) {
127303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                    mFilteredTasks.add(t);
128303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                }
129303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            }
130303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        } else {
131303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            mFilteredTasks.addAll(mTasks);
132303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        }
133ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        updateFilteredTaskIndices();
134ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    }
135ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
136ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    /** Updates the mapping of tasks to indices. */
137ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    private void updateFilteredTaskIndices() {
138ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        mTaskIndices.clear();
139ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        int taskCount = mFilteredTasks.size();
140ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        for (int i = 0; i < taskCount; i++) {
141ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            Task t = mFilteredTasks.get(i);
142ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            mTaskIndices.put(t.key, i);
143ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        }
144303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
145303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
146303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Returns whether this task list is filtered */
147303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    boolean hasFilter() {
148303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        return (mFilter != null);
149303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
150303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
151303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Returns the list of filtered tasks */
152303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    ArrayList<Task> getTasks() {
153303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        return mFilteredTasks;
154303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
155303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung}
156303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
157303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung/**
158303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung * The task stack contains a list of multiple tasks.
159303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung */
160303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chungpublic class TaskStack {
161ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
162ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    /** Task stack callbacks */
16304dfe0d26b944324ee920001f40d74cff47281d6Winson Chung    public interface TaskStackCallbacks {
16404dfe0d26b944324ee920001f40d74cff47281d6Winson Chung        /* Notifies when a task has been added to the stack */
16504dfe0d26b944324ee920001f40d74cff47281d6Winson Chung        public void onStackTaskAdded(TaskStack stack, Task t);
16604dfe0d26b944324ee920001f40d74cff47281d6Winson Chung        /* Notifies when a task has been removed from the stack */
1671f24c7e37bc794057a156a730c7e4b53b01212edWinson Chung        public void onStackTaskRemoved(TaskStack stack, Task removedTask, Task newFrontMostTask);
16804dfe0d26b944324ee920001f40d74cff47281d6Winson Chung        /** Notifies when the stack was filtered */
16911ca76a53c60a1898956614315ae929668c523d6Winson Chung        public void onStackFiltered(TaskStack newStack, ArrayList<Task> curTasks, Task t);
17004dfe0d26b944324ee920001f40d74cff47281d6Winson Chung        /** Notifies when the stack was un-filtered */
17111ca76a53c60a1898956614315ae929668c523d6Winson Chung        public void onStackUnfiltered(TaskStack newStack, ArrayList<Task> curTasks);
17204dfe0d26b944324ee920001f40d74cff47281d6Winson Chung    }
17304dfe0d26b944324ee920001f40d74cff47281d6Winson Chung
174ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    /** A pair of indices representing the group and task positions in the stack and group. */
175ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    public static class GroupTaskIndex {
176ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        public int groupIndex; // Index in the stack
177ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        public int taskIndex;  // Index in the group
178ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
179ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        public GroupTaskIndex() {}
180ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
181ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        public GroupTaskIndex(int gi, int ti) {
182ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            groupIndex = gi;
183ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            taskIndex = ti;
184ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        }
185ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    }
186ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
187083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung    // The task offset to apply to a task id as a group affiliation
188083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung    static final int IndividualTaskIdOffset = 1 << 16;
189083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung
190303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    FilteredTaskList mTaskList = new FilteredTaskList();
191303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    TaskStackCallbacks mCb;
192303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
193ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    ArrayList<TaskGrouping> mGroups = new ArrayList<TaskGrouping>();
194083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung    HashMap<Integer, TaskGrouping> mAffinitiesGroups = new HashMap<Integer, TaskGrouping>();
195303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
196303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Sets the callbacks for this task stack */
197303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    public void setCallbacks(TaskStackCallbacks cb) {
198303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mCb = cb;
199303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
200303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
201bc571a980704dc767838935e83c6aed231c406e9Winson Chung    /** Resets this TaskStack. */
202bc571a980704dc767838935e83c6aed231c406e9Winson Chung    public void reset() {
203bc571a980704dc767838935e83c6aed231c406e9Winson Chung        mCb = null;
204bc571a980704dc767838935e83c6aed231c406e9Winson Chung        mTaskList.reset();
205bc571a980704dc767838935e83c6aed231c406e9Winson Chung        mGroups.clear();
206bc571a980704dc767838935e83c6aed231c406e9Winson Chung        mAffinitiesGroups.clear();
207bc571a980704dc767838935e83c6aed231c406e9Winson Chung    }
208bc571a980704dc767838935e83c6aed231c406e9Winson Chung
209303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Adds a new task */
210303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    public void addTask(Task t) {
211303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mTaskList.add(t);
212303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        if (mCb != null) {
213303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            mCb.onStackTaskAdded(this, t);
214303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        }
215303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
216303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
217303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Removes a task */
218303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    public void removeTask(Task t) {
219303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        if (mTaskList.contains(t)) {
220ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            // Remove the task from the list
221303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            mTaskList.remove(t);
222ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            // Remove it from the group as well, and if it is empty, remove the group
223ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            TaskGrouping group = t.group;
224ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            group.removeTask(t);
225ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            if (group.getTaskCount() == 0) {
226ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                removeGroup(group);
227ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            }
2281f24c7e37bc794057a156a730c7e4b53b01212edWinson Chung            // Update the lock-to-app state
22956e09b42a0f1670970872bef611a8036904ad6bfJason Monk            t.lockToThisTask = false;
23082c8c5e9872b984ba6f43b01da0c7731fd5bf762Winson Chung            Task newFrontMostTask = getFrontMostTask();
23156e09b42a0f1670970872bef611a8036904ad6bfJason Monk            if (newFrontMostTask != null && newFrontMostTask.lockToTaskEnabled) {
23256e09b42a0f1670970872bef611a8036904ad6bfJason Monk                newFrontMostTask.lockToThisTask = true;
2331f24c7e37bc794057a156a730c7e4b53b01212edWinson Chung            }
234303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            if (mCb != null) {
235ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                // Notify that a task has been removed
2361f24c7e37bc794057a156a730c7e4b53b01212edWinson Chung                mCb.onStackTaskRemoved(this, t, newFrontMostTask);
237303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            }
238303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        }
239303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
240303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
241303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Sets a few tasks in one go */
242303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    public void setTasks(List<Task> tasks) {
243ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        ArrayList<Task> taskList = mTaskList.getTasks();
244ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        int taskCount = taskList.size();
245303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        for (int i = 0; i < taskCount; i++) {
246ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            Task t = taskList.get(i);
247ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            // Remove the task from the list
248ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            mTaskList.remove(t);
249ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            // Remove it from the group as well, and if it is empty, remove the group
250ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            TaskGrouping group = t.group;
251ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            group.removeTask(t);
252ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            if (group.getTaskCount() == 0) {
253ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                removeGroup(group);
254ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            }
25598e8f7ac5e75a47abaa0061aab343b9f06770258Winson Chung            // Update the lock-to-app state
25698e8f7ac5e75a47abaa0061aab343b9f06770258Winson Chung            t.lockToThisTask = false;
257303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            if (mCb != null) {
258ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                // Notify that a task has been removed
2591f24c7e37bc794057a156a730c7e4b53b01212edWinson Chung                mCb.onStackTaskRemoved(this, t, null);
260303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            }
261303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        }
262303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mTaskList.set(tasks);
263303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        for (Task t : tasks) {
264303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            if (mCb != null) {
265303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                mCb.onStackTaskAdded(this, t);
266303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            }
267303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        }
268303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
269303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
270ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    /** Gets the front task */
271ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    public Task getFrontMostTask() {
2721f24c7e37bc794057a156a730c7e4b53b01212edWinson Chung        if (mTaskList.size() == 0) return null;
273ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        return mTaskList.getTasks().get(mTaskList.size() - 1);
274ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    }
275ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
27604400672962d2e12132f9465928cbf7615c147c4Winson Chung    /** Gets the task keys */
27704400672962d2e12132f9465928cbf7615c147c4Winson Chung    public ArrayList<Task.TaskKey> getTaskKeys() {
27804400672962d2e12132f9465928cbf7615c147c4Winson Chung        ArrayList<Task.TaskKey> taskKeys = new ArrayList<Task.TaskKey>();
27904400672962d2e12132f9465928cbf7615c147c4Winson Chung        ArrayList<Task> tasks = mTaskList.getTasks();
28004400672962d2e12132f9465928cbf7615c147c4Winson Chung        int taskCount = tasks.size();
28104400672962d2e12132f9465928cbf7615c147c4Winson Chung        for (int i = 0; i < taskCount; i++) {
28204400672962d2e12132f9465928cbf7615c147c4Winson Chung            taskKeys.add(tasks.get(i).key);
28304400672962d2e12132f9465928cbf7615c147c4Winson Chung        }
28404400672962d2e12132f9465928cbf7615c147c4Winson Chung        return taskKeys;
28504400672962d2e12132f9465928cbf7615c147c4Winson Chung    }
28604400672962d2e12132f9465928cbf7615c147c4Winson Chung
287303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Gets the tasks */
288303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    public ArrayList<Task> getTasks() {
289303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        return mTaskList.getTasks();
290303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
291303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
292303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Gets the number of tasks */
293303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    public int getTaskCount() {
294303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        return mTaskList.size();
295303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
296303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
297303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Returns the index of this task in this current task stack */
298303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    public int indexOfTask(Task t) {
299303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        return mTaskList.indexOf(t);
300303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
301303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
302b1f749906f5c27114d02ea0c3f8ce0dcea08fd3fWinson Chung    /** Finds the task with the specified task id. */
303b1f749906f5c27114d02ea0c3f8ce0dcea08fd3fWinson Chung    public Task findTaskWithId(int taskId) {
304b1f749906f5c27114d02ea0c3f8ce0dcea08fd3fWinson Chung        ArrayList<Task> tasks = mTaskList.getTasks();
305b1f749906f5c27114d02ea0c3f8ce0dcea08fd3fWinson Chung        int taskCount = tasks.size();
306b1f749906f5c27114d02ea0c3f8ce0dcea08fd3fWinson Chung        for (int i = 0; i < taskCount; i++) {
307b1f749906f5c27114d02ea0c3f8ce0dcea08fd3fWinson Chung            Task task = tasks.get(i);
308b1f749906f5c27114d02ea0c3f8ce0dcea08fd3fWinson Chung            if (task.key.id == taskId) {
309b1f749906f5c27114d02ea0c3f8ce0dcea08fd3fWinson Chung                return task;
310b1f749906f5c27114d02ea0c3f8ce0dcea08fd3fWinson Chung            }
311b1f749906f5c27114d02ea0c3f8ce0dcea08fd3fWinson Chung        }
312b1f749906f5c27114d02ea0c3f8ce0dcea08fd3fWinson Chung        return null;
313b1f749906f5c27114d02ea0c3f8ce0dcea08fd3fWinson Chung    }
314b1f749906f5c27114d02ea0c3f8ce0dcea08fd3fWinson Chung
315ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    /******** Filtering ********/
316303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
317303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Filters the stack into tasks similar to the one specified */
318c6a1623cc48581380b698ae87b43bfafb9c935baWinson Chung    public void filterTasks(final Task t) {
319c6a1623cc48581380b698ae87b43bfafb9c935baWinson Chung        ArrayList<Task> oldStack = new ArrayList<Task>(mTaskList.getTasks());
320c6a1623cc48581380b698ae87b43bfafb9c935baWinson Chung
321303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        // Set the task list filter
322c6a1623cc48581380b698ae87b43bfafb9c935baWinson Chung        boolean filtered = mTaskList.setFilter(new TaskFilter() {
323303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            @Override
324c6a1623cc48581380b698ae87b43bfafb9c935baWinson Chung            public boolean acceptTask(Task at, int i) {
325c6a1623cc48581380b698ae87b43bfafb9c935baWinson Chung                return t.key.baseIntent.getComponent().getPackageName().equals(
326c6a1623cc48581380b698ae87b43bfafb9c935baWinson Chung                        at.key.baseIntent.getComponent().getPackageName());
327303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            }
328303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        });
329c6a1623cc48581380b698ae87b43bfafb9c935baWinson Chung        if (filtered && mCb != null) {
330c6a1623cc48581380b698ae87b43bfafb9c935baWinson Chung            mCb.onStackFiltered(this, oldStack, t);
331303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        }
332303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
333303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
334303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Unfilters the current stack */
335303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    public void unfilterTasks() {
336c6a1623cc48581380b698ae87b43bfafb9c935baWinson Chung        ArrayList<Task> oldStack = new ArrayList<Task>(mTaskList.getTasks());
337c6a1623cc48581380b698ae87b43bfafb9c935baWinson Chung
338303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        // Unset the filter, then update the virtual scroll
339303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mTaskList.removeFilter();
340303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        if (mCb != null) {
341c6a1623cc48581380b698ae87b43bfafb9c935baWinson Chung            mCb.onStackUnfiltered(this, oldStack);
342303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        }
343303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
344303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
345303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Returns whether tasks are currently filtered */
346303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    public boolean hasFilteredTasks() {
347303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        return mTaskList.hasFilter();
348303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
349303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
350ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    /******** Grouping ********/
351ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
352ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    /** Adds a group to the set */
353ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    public void addGroup(TaskGrouping group) {
354ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        mGroups.add(group);
355ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        mAffinitiesGroups.put(group.affiliation, group);
356ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    }
357ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
358ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    public void removeGroup(TaskGrouping group) {
359ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        mGroups.remove(group);
360ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        mAffinitiesGroups.remove(group.affiliation);
361ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    }
362ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
363ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    /** Returns the group with the specified affiliation. */
364083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung    public TaskGrouping getGroupWithAffiliation(int affiliation) {
365ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        return mAffinitiesGroups.get(affiliation);
366ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    }
367ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
368ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    /**
369ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung     * Temporary: This method will simulate affiliation groups by
370ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung     */
371ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung    public void createAffiliatedGroupings(RecentsConfiguration config) {
372ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        if (Constants.DebugFlags.App.EnableSimulatedTaskGroups) {
373ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            HashMap<Task.TaskKey, Task> taskMap = new HashMap<Task.TaskKey, Task>();
374ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            // Sort all tasks by increasing firstActiveTime of the task
375ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            ArrayList<Task> tasks = mTaskList.getTasks();
376ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            Collections.sort(tasks, new Comparator<Task>() {
377ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                @Override
378ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                public int compare(Task task, Task task2) {
379ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    return (int) (task.key.firstActiveTime - task2.key.firstActiveTime);
380ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                }
381ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            });
382ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            // Create groups when sequential packages are the same
383ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            NamedCounter counter = new NamedCounter("task-group", "");
384ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            int taskCount = tasks.size();
385ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            String prevPackage = "";
386083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung            int prevAffiliation = -1;
387a433fa9c17772f563163ff7db177d091d6aebd5bWinson Chung            Random r = new Random();
388012ef36a6c5e9745d112c734aed916cab052558cWinson Chung            int groupCountDown = Constants.DebugFlags.App.TaskAffiliationsGroupCount;
389ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            for (int i = 0; i < taskCount; i++) {
390ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                Task t = tasks.get(i);
391ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                String packageName = t.key.baseIntent.getComponent().getPackageName();
392a433fa9c17772f563163ff7db177d091d6aebd5bWinson Chung                packageName = "pkg";
393ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                TaskGrouping group;
394a433fa9c17772f563163ff7db177d091d6aebd5bWinson Chung                if (packageName.equals(prevPackage) && groupCountDown > 0) {
395ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    group = getGroupWithAffiliation(prevAffiliation);
396a433fa9c17772f563163ff7db177d091d6aebd5bWinson Chung                    groupCountDown--;
397ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                } else {
398083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung                    int affiliation = IndividualTaskIdOffset + t.key.id;
399ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    group = new TaskGrouping(affiliation);
400ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    addGroup(group);
401ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    prevAffiliation = affiliation;
402ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    prevPackage = packageName;
403012ef36a6c5e9745d112c734aed916cab052558cWinson Chung                    groupCountDown = Constants.DebugFlags.App.TaskAffiliationsGroupCount;
404ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                }
405ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                group.addTask(t);
406ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                taskMap.put(t.key, t);
407ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            }
408ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            // Sort groups by increasing latestActiveTime of the group
409ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            Collections.sort(mGroups, new Comparator<TaskGrouping>() {
410ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                @Override
411ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                public int compare(TaskGrouping taskGrouping, TaskGrouping taskGrouping2) {
412ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    return (int) (taskGrouping.latestActiveTimeInGroup -
413ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                            taskGrouping2.latestActiveTimeInGroup);
414ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                }
415ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            });
416ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            // Sort group tasks by increasing firstActiveTime of the task, and also build a new list of
417ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            // tasks
418ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            int taskIndex = 0;
419ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            int groupCount = mGroups.size();
420ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            for (int i = 0; i < groupCount; i++) {
421ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                TaskGrouping group = mGroups.get(i);
422083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung                Collections.sort(group.mTaskKeys, new Comparator<Task.TaskKey>() {
423ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    @Override
424ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    public int compare(Task.TaskKey taskKey, Task.TaskKey taskKey2) {
425ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                        return (int) (taskKey.firstActiveTime - taskKey2.firstActiveTime);
426ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    }
427ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                });
428083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung                ArrayList<Task.TaskKey> groupTasks = group.mTaskKeys;
429ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                int groupTaskCount = groupTasks.size();
430ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                for (int j = 0; j < groupTaskCount; j++) {
431ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    tasks.set(taskIndex, taskMap.get(groupTasks.get(j)));
432ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    taskIndex++;
433ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                }
434ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            }
435ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            mTaskList.set(tasks);
436ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        } else {
437083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung            // Create the task groups
438ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung            HashMap<Task.TaskKey, Task> tasksMap = new HashMap<Task.TaskKey, Task>();
439ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            ArrayList<Task> tasks = mTaskList.getTasks();
440ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            int taskCount = tasks.size();
441ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            for (int i = 0; i < taskCount; i++) {
442ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                Task t = tasks.get(i);
443083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung                TaskGrouping group;
444083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung                int affiliation = t.taskAffiliation > 0 ? t.taskAffiliation :
445083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung                        IndividualTaskIdOffset + t.key.id;
446083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung                if (mAffinitiesGroups.containsKey(affiliation)) {
447083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung                    group = getGroupWithAffiliation(affiliation);
448083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung                } else {
449083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung                    group = new TaskGrouping(affiliation);
450083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung                    addGroup(group);
451083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung                }
452ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                group.addTask(t);
453ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                tasksMap.put(t.key, t);
454ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung            }
455ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung            // Update the task colors for each of the groups
456ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung            float minAlpha = config.taskBarViewAffiliationColorMinAlpha;
457ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung            int taskGroupCount = mGroups.size();
458ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung            for (int i = 0; i < taskGroupCount; i++) {
459ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                TaskGrouping group = mGroups.get(i);
460ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                taskCount = group.getTaskCount();
461ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                // Ignore the groups that only have one task
462ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                if (taskCount <= 1) continue;
463ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                // Calculate the group color distribution
464ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                int affiliationColor = tasksMap.get(group.mTaskKeys.get(0)).taskAffiliationColor;
465ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                float alphaStep = (1f - minAlpha) / taskCount;
466ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                float alpha = 1f;
467ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                for (int j = 0; j < taskCount; j++) {
468ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                    Task t = tasksMap.get(group.mTaskKeys.get(j));
469a0e88b5013d708ac6ed6518817d83c64c87ae4b1Winson Chung                    t.colorPrimary = Utilities.getColorWithOverlay(affiliationColor, Color.WHITE,
470a0e88b5013d708ac6ed6518817d83c64c87ae4b1Winson Chung                            alpha);
471ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                    alpha -= alphaStep;
472ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                }
473ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            }
474ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        }
475ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    }
476ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
477303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    @Override
478303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    public String toString() {
479303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        String str = "Tasks:\n";
480303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        for (Task t : mTaskList.getTasks()) {
481303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            str += "  " + t.toString() + "\n";
482303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        }
483303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        return str;
484303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
48598e8f7ac5e75a47abaa0061aab343b9f06770258Winson Chung}
486