TaskStack.java revision a433fa9c17772f563163ff7db177d091d6aebd5b
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
19ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chungimport com.android.systemui.recents.Constants;
20ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chungimport com.android.systemui.recents.misc.NamedCounter;
21303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
22303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chungimport java.util.ArrayList;
23ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chungimport java.util.Collections;
24ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chungimport java.util.Comparator;
25ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chungimport java.util.HashMap;
26303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chungimport java.util.List;
27a433fa9c17772f563163ff7db177d091d6aebd5bWinson Chungimport java.util.Random;
28303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
29303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
30303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung/**
31303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung * An interface for a task filter to query whether a particular task should show in a stack.
32303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung */
33303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chunginterface TaskFilter {
34303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Returns whether the filter accepts the specified task */
35303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    public boolean acceptTask(Task t, int index);
36303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung}
37303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
38303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung/**
39303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung * A list of filtered tasks.
40303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung */
41303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chungclass FilteredTaskList {
42303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    ArrayList<Task> mTasks = new ArrayList<Task>();
43303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    ArrayList<Task> mFilteredTasks = new ArrayList<Task>();
44ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    HashMap<Task.TaskKey, Integer> mTaskIndices = new HashMap<Task.TaskKey, Integer>();
45303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    TaskFilter mFilter;
46303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
47303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Sets the task filter, saving the current touch state */
48c6a1623cc48581380b698ae87b43bfafb9c935baWinson Chung    boolean setFilter(TaskFilter filter) {
49c6a1623cc48581380b698ae87b43bfafb9c935baWinson Chung        ArrayList<Task> prevFilteredTasks = new ArrayList<Task>(mFilteredTasks);
50303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mFilter = filter;
51303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        updateFilteredTasks();
52b44c24fb50845dfbc1f49e78085cf5e01a32067fWinson Chung        if (!prevFilteredTasks.equals(mFilteredTasks)) {
53b44c24fb50845dfbc1f49e78085cf5e01a32067fWinson Chung            return true;
54b44c24fb50845dfbc1f49e78085cf5e01a32067fWinson Chung        } else {
55b44c24fb50845dfbc1f49e78085cf5e01a32067fWinson Chung            // If the tasks are exactly the same pre/post filter, then just reset it
56b44c24fb50845dfbc1f49e78085cf5e01a32067fWinson Chung            mFilter = null;
57b44c24fb50845dfbc1f49e78085cf5e01a32067fWinson Chung            return false;
58b44c24fb50845dfbc1f49e78085cf5e01a32067fWinson Chung        }
59303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
60303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
61303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Removes the task filter and returns the previous touch state */
62303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    void removeFilter() {
63303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mFilter = null;
64303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        updateFilteredTasks();
65303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
66303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
67303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Adds a new task to the task list */
68303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    void add(Task t) {
69303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mTasks.add(t);
70303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        updateFilteredTasks();
71303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
72303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
73303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Sets the list of tasks */
74303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    void set(List<Task> tasks) {
75303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mTasks.clear();
76303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mTasks.addAll(tasks);
77303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        updateFilteredTasks();
78303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
79303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
80303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Removes a task from the base list only if it is in the filtered list */
81303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    boolean remove(Task t) {
82303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        if (mFilteredTasks.contains(t)) {
83303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            boolean removed = mTasks.remove(t);
84303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            updateFilteredTasks();
85303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            return removed;
86303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        }
87303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        return false;
88303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
89303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
90303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Returns the index of this task in the list of filtered tasks */
91303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    int indexOf(Task t) {
92ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        return mTaskIndices.get(t.key);
93303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
94303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
95303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Returns the size of the list of filtered tasks */
96303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    int size() {
97303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        return mFilteredTasks.size();
98303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
99303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
100303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Returns whether the filtered list contains this task */
101303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    boolean contains(Task t) {
102ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        return mTaskIndices.containsKey(t.key);
103303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
104303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
105303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Updates the list of filtered tasks whenever the base task list changes */
106303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    private void updateFilteredTasks() {
107303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mFilteredTasks.clear();
108303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        if (mFilter != null) {
109303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            int taskCount = mTasks.size();
110303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            for (int i = 0; i < taskCount; i++) {
111303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                Task t = mTasks.get(i);
112303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                if (mFilter.acceptTask(t, i)) {
113303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                    mFilteredTasks.add(t);
114303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                }
115303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            }
116303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        } else {
117303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            mFilteredTasks.addAll(mTasks);
118303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        }
119ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        updateFilteredTaskIndices();
120ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    }
121ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
122ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    /** Updates the mapping of tasks to indices. */
123ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    private void updateFilteredTaskIndices() {
124ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        mTaskIndices.clear();
125ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        int taskCount = mFilteredTasks.size();
126ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        for (int i = 0; i < taskCount; i++) {
127ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            Task t = mFilteredTasks.get(i);
128ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            mTaskIndices.put(t.key, i);
129ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        }
130303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
131303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
132303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Returns whether this task list is filtered */
133303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    boolean hasFilter() {
134303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        return (mFilter != null);
135303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
136303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
137303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Returns the list of filtered tasks */
138303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    ArrayList<Task> getTasks() {
139303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        return mFilteredTasks;
140303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
141303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung}
142303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
143303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung/**
144303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung * The task stack contains a list of multiple tasks.
145303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung */
146303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chungpublic class TaskStack {
147ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
148ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    /** Task stack callbacks */
14904dfe0d26b944324ee920001f40d74cff47281d6Winson Chung    public interface TaskStackCallbacks {
15004dfe0d26b944324ee920001f40d74cff47281d6Winson Chung        /* Notifies when a task has been added to the stack */
15104dfe0d26b944324ee920001f40d74cff47281d6Winson Chung        public void onStackTaskAdded(TaskStack stack, Task t);
15204dfe0d26b944324ee920001f40d74cff47281d6Winson Chung        /* Notifies when a task has been removed from the stack */
15304dfe0d26b944324ee920001f40d74cff47281d6Winson Chung        public void onStackTaskRemoved(TaskStack stack, Task t);
15404dfe0d26b944324ee920001f40d74cff47281d6Winson Chung        /** Notifies when the stack was filtered */
15511ca76a53c60a1898956614315ae929668c523d6Winson Chung        public void onStackFiltered(TaskStack newStack, ArrayList<Task> curTasks, Task t);
15604dfe0d26b944324ee920001f40d74cff47281d6Winson Chung        /** Notifies when the stack was un-filtered */
15711ca76a53c60a1898956614315ae929668c523d6Winson Chung        public void onStackUnfiltered(TaskStack newStack, ArrayList<Task> curTasks);
15804dfe0d26b944324ee920001f40d74cff47281d6Winson Chung    }
15904dfe0d26b944324ee920001f40d74cff47281d6Winson Chung
160ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    /** A pair of indices representing the group and task positions in the stack and group. */
161ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    public static class GroupTaskIndex {
162ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        public int groupIndex; // Index in the stack
163ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        public int taskIndex;  // Index in the group
164ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
165ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        public GroupTaskIndex() {}
166ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
167ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        public GroupTaskIndex(int gi, int ti) {
168ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            groupIndex = gi;
169ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            taskIndex = ti;
170ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        }
171ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    }
172ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
173303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    FilteredTaskList mTaskList = new FilteredTaskList();
174303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    TaskStackCallbacks mCb;
175303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
176ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    ArrayList<TaskGrouping> mGroups = new ArrayList<TaskGrouping>();
177ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    HashMap<String, TaskGrouping> mAffinitiesGroups = new HashMap<String, TaskGrouping>();
178303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
179303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Sets the callbacks for this task stack */
180303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    public void setCallbacks(TaskStackCallbacks cb) {
181303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mCb = cb;
182303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
183303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
184303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Adds a new task */
185303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    public void addTask(Task t) {
186303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mTaskList.add(t);
187303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        if (mCb != null) {
188303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            mCb.onStackTaskAdded(this, t);
189303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        }
190303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
191303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
192303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Removes a task */
193303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    public void removeTask(Task t) {
194303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        if (mTaskList.contains(t)) {
195ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            // Remove the task from the list
196303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            mTaskList.remove(t);
197ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            // Remove it from the group as well, and if it is empty, remove the group
198ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            TaskGrouping group = t.group;
199ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            group.removeTask(t);
200ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            if (group.getTaskCount() == 0) {
201ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                removeGroup(group);
202ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            }
203303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            if (mCb != null) {
204ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                // Notify that a task has been removed
205303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                mCb.onStackTaskRemoved(this, t);
206303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            }
207303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        }
208303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
209303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
210303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Sets a few tasks in one go */
211303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    public void setTasks(List<Task> tasks) {
212ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        ArrayList<Task> taskList = mTaskList.getTasks();
213ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        int taskCount = taskList.size();
214303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        for (int i = 0; i < taskCount; i++) {
215ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            Task t = taskList.get(i);
216ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            // Remove the task from the list
217ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            mTaskList.remove(t);
218ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            // Remove it from the group as well, and if it is empty, remove the group
219ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            TaskGrouping group = t.group;
220ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            group.removeTask(t);
221ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            if (group.getTaskCount() == 0) {
222ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                removeGroup(group);
223ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            }
224303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            if (mCb != null) {
225ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                // Notify that a task has been removed
226303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                mCb.onStackTaskRemoved(this, t);
227303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            }
228303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        }
229303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mTaskList.set(tasks);
230303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        for (Task t : tasks) {
231303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            if (mCb != null) {
232303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                mCb.onStackTaskAdded(this, t);
233303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            }
234303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        }
235303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
236303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
237ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    /** Gets the front task */
238ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    public Task getFrontMostTask() {
239ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        return mTaskList.getTasks().get(mTaskList.size() - 1);
240ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    }
241ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
242303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Gets the tasks */
243303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    public ArrayList<Task> getTasks() {
244303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        return mTaskList.getTasks();
245303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
246303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
247303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Gets the number of tasks */
248303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    public int getTaskCount() {
249303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        return mTaskList.size();
250303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
251303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
252303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Returns the index of this task in this current task stack */
253303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    public int indexOfTask(Task t) {
254303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        return mTaskList.indexOf(t);
255303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
256303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
257ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    /******** Filtering ********/
258303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
259303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Filters the stack into tasks similar to the one specified */
260c6a1623cc48581380b698ae87b43bfafb9c935baWinson Chung    public void filterTasks(final Task t) {
261c6a1623cc48581380b698ae87b43bfafb9c935baWinson Chung        ArrayList<Task> oldStack = new ArrayList<Task>(mTaskList.getTasks());
262c6a1623cc48581380b698ae87b43bfafb9c935baWinson Chung
263303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        // Set the task list filter
264c6a1623cc48581380b698ae87b43bfafb9c935baWinson Chung        boolean filtered = mTaskList.setFilter(new TaskFilter() {
265303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            @Override
266c6a1623cc48581380b698ae87b43bfafb9c935baWinson Chung            public boolean acceptTask(Task at, int i) {
267c6a1623cc48581380b698ae87b43bfafb9c935baWinson Chung                return t.key.baseIntent.getComponent().getPackageName().equals(
268c6a1623cc48581380b698ae87b43bfafb9c935baWinson Chung                        at.key.baseIntent.getComponent().getPackageName());
269303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            }
270303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        });
271c6a1623cc48581380b698ae87b43bfafb9c935baWinson Chung        if (filtered && mCb != null) {
272c6a1623cc48581380b698ae87b43bfafb9c935baWinson Chung            mCb.onStackFiltered(this, oldStack, t);
273303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        }
274303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
275303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
276303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Unfilters the current stack */
277303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    public void unfilterTasks() {
278c6a1623cc48581380b698ae87b43bfafb9c935baWinson Chung        ArrayList<Task> oldStack = new ArrayList<Task>(mTaskList.getTasks());
279c6a1623cc48581380b698ae87b43bfafb9c935baWinson Chung
280303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        // Unset the filter, then update the virtual scroll
281303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mTaskList.removeFilter();
282303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        if (mCb != null) {
283c6a1623cc48581380b698ae87b43bfafb9c935baWinson Chung            mCb.onStackUnfiltered(this, oldStack);
284303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        }
285303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
286303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
287303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Returns whether tasks are currently filtered */
288303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    public boolean hasFilteredTasks() {
289303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        return mTaskList.hasFilter();
290303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
291303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
292ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    /******** Grouping ********/
293ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
294ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    /** Adds a group to the set */
295ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    public void addGroup(TaskGrouping group) {
296ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        mGroups.add(group);
297ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        mAffinitiesGroups.put(group.affiliation, group);
298ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    }
299ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
300ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    public void removeGroup(TaskGrouping group) {
301ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        mGroups.remove(group);
302ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        mAffinitiesGroups.remove(group.affiliation);
303ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    }
304ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
305ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    /** Returns the group with the specified affiliation. */
306ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    public TaskGrouping getGroupWithAffiliation(String affiliation) {
307ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        return mAffinitiesGroups.get(affiliation);
308ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    }
309ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
310ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    /**
311ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung     * Temporary: This method will simulate affiliation groups by
312ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung     */
313ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    public void createSimulatedAffiliatedGroupings() {
314ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        if (Constants.DebugFlags.App.EnableSimulatedTaskGroups) {
315ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            HashMap<Task.TaskKey, Task> taskMap = new HashMap<Task.TaskKey, Task>();
316ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            // Sort all tasks by increasing firstActiveTime of the task
317ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            ArrayList<Task> tasks = mTaskList.getTasks();
318ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            Collections.sort(tasks, new Comparator<Task>() {
319ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                @Override
320ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                public int compare(Task task, Task task2) {
321ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    return (int) (task.key.firstActiveTime - task2.key.firstActiveTime);
322ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                }
323ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            });
324ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            // Create groups when sequential packages are the same
325ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            NamedCounter counter = new NamedCounter("task-group", "");
326ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            int taskCount = tasks.size();
327ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            String prevPackage = "";
328ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            String prevAffiliation = "";
329a433fa9c17772f563163ff7db177d091d6aebd5bWinson Chung            Random r = new Random();
330a433fa9c17772f563163ff7db177d091d6aebd5bWinson Chung            int groupCountDown = 1000;
331ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            for (int i = 0; i < taskCount; i++) {
332ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                Task t = tasks.get(i);
333ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                String packageName = t.key.baseIntent.getComponent().getPackageName();
334a433fa9c17772f563163ff7db177d091d6aebd5bWinson Chung                packageName = "pkg";
335ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                TaskGrouping group;
336a433fa9c17772f563163ff7db177d091d6aebd5bWinson Chung                if (packageName.equals(prevPackage) && groupCountDown > 0) {
337ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    group = getGroupWithAffiliation(prevAffiliation);
338a433fa9c17772f563163ff7db177d091d6aebd5bWinson Chung                    groupCountDown--;
339ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                } else {
340ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    String affiliation = counter.nextName();
341ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    group = new TaskGrouping(affiliation);
342ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    addGroup(group);
343ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    prevAffiliation = affiliation;
344ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    prevPackage = packageName;
345a433fa9c17772f563163ff7db177d091d6aebd5bWinson Chung                    groupCountDown = 1000;
346ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                }
347ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                group.addTask(t);
348ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                taskMap.put(t.key, t);
349ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            }
350ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            // Sort groups by increasing latestActiveTime of the group
351ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            Collections.sort(mGroups, new Comparator<TaskGrouping>() {
352ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                @Override
353ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                public int compare(TaskGrouping taskGrouping, TaskGrouping taskGrouping2) {
354ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    return (int) (taskGrouping.latestActiveTimeInGroup -
355ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                            taskGrouping2.latestActiveTimeInGroup);
356ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                }
357ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            });
358ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            // Sort group tasks by increasing firstActiveTime of the task, and also build a new list of
359ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            // tasks
360ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            int taskIndex = 0;
361ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            int groupCount = mGroups.size();
362ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            for (int i = 0; i < groupCount; i++) {
363ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                TaskGrouping group = mGroups.get(i);
364ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                Collections.sort(group.mTasks, new Comparator<Task.TaskKey>() {
365ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    @Override
366ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    public int compare(Task.TaskKey taskKey, Task.TaskKey taskKey2) {
367ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                        return (int) (taskKey.firstActiveTime - taskKey2.firstActiveTime);
368ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    }
369ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                });
370ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                ArrayList<Task.TaskKey> groupTasks = group.mTasks;
371ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                int groupTaskCount = groupTasks.size();
372ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                for (int j = 0; j < groupTaskCount; j++) {
373ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    tasks.set(taskIndex, taskMap.get(groupTasks.get(j)));
374ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    taskIndex++;
375ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                }
376ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            }
377ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            mTaskList.set(tasks);
378ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        } else {
379ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            // Create a group per task
380ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            NamedCounter counter = new NamedCounter("task-group", "");
381ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            ArrayList<Task> tasks = mTaskList.getTasks();
382ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            int taskCount = tasks.size();
383ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            for (int i = 0; i < taskCount; i++) {
384ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                Task t = tasks.get(i);
385ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                TaskGrouping group = new TaskGrouping(counter.nextName());
386ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                addGroup(group);
387ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                group.addTask(t);
388ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            }
389ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        }
390ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    }
391ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
392303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    @Override
393303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    public String toString() {
394303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        String str = "Tasks:\n";
395303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        for (Task t : mTaskList.getTasks()) {
396303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            str += "  " + t.toString() + "\n";
397303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        }
398303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        return str;
399303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
400303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung}