TaskStack.java revision 8b1871d74137d7e36ba0fed5608772f51f62015b
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;
262536c7ed446203ea12b38cf05a88e603f8d1b768Winsonimport com.android.systemui.R;
27e7f138c7f0a190c86cec10fb32fa106aacae4093Winsonimport com.android.systemui.recents.Recents;
28c742f973b1e506732911c156c5869fd377afc5bfWinsonimport com.android.systemui.recents.RecentsDebugFlags;
29ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chungimport com.android.systemui.recents.misc.NamedCounter;
30e7f138c7f0a190c86cec10fb32fa106aacae4093Winsonimport com.android.systemui.recents.misc.SystemServicesProxy;
31a0e88b5013d708ac6ed6518817d83c64c87ae4b1Winson Chungimport com.android.systemui.recents.misc.Utilities;
32eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winsonimport com.android.systemui.recents.views.DropTarget;
33303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
34303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chungimport java.util.ArrayList;
35ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chungimport java.util.Collections;
36ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chungimport java.util.Comparator;
37ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chungimport java.util.HashMap;
38e7f138c7f0a190c86cec10fb32fa106aacae4093Winsonimport java.util.HashSet;
39303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chungimport java.util.List;
40a433fa9c17772f563163ff7db177d091d6aebd5bWinson Chungimport java.util.Random;
41303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
42be7607af8875236b9cf7bdb5f5aa089c207529afWinsonimport static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT;
43be7607af8875236b9cf7bdb5f5aa089c207529afWinsonimport static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
44eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winsonimport static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
45eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winsonimport static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
46be7607af8875236b9cf7bdb5f5aa089c207529afWinson
47303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
48303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung/**
49303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung * An interface for a task filter to query whether a particular task should show in a stack.
50303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung */
51303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chunginterface TaskFilter {
52303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Returns whether the filter accepts the specified task */
53303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    public boolean acceptTask(Task t, int index);
54303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung}
55303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
56303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung/**
57303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung * A list of filtered tasks.
58303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung */
59303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chungclass FilteredTaskList {
60eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson
61eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson    private static final String TAG = "FilteredTaskList";
628b1871d74137d7e36ba0fed5608772f51f62015bWinson    private static final boolean DEBUG = false;
63eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson
64eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson    ArrayList<Task> mTasks = new ArrayList<>();
65eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson    ArrayList<Task> mFilteredTasks = new ArrayList<>();
66eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson    HashMap<Task.TaskKey, Integer> mTaskIndices = new HashMap<>();
67303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    TaskFilter mFilter;
68303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
69303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Sets the task filter, saving the current touch state */
70c6a1623cc48581380b698ae87b43bfafb9c935baWinson Chung    boolean setFilter(TaskFilter filter) {
71c6a1623cc48581380b698ae87b43bfafb9c935baWinson Chung        ArrayList<Task> prevFilteredTasks = new ArrayList<Task>(mFilteredTasks);
72303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mFilter = filter;
73303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        updateFilteredTasks();
74b44c24fb50845dfbc1f49e78085cf5e01a32067fWinson Chung        if (!prevFilteredTasks.equals(mFilteredTasks)) {
75b44c24fb50845dfbc1f49e78085cf5e01a32067fWinson Chung            return true;
76b44c24fb50845dfbc1f49e78085cf5e01a32067fWinson Chung        } else {
77b44c24fb50845dfbc1f49e78085cf5e01a32067fWinson Chung            // If the tasks are exactly the same pre/post filter, then just reset it
78b44c24fb50845dfbc1f49e78085cf5e01a32067fWinson Chung            mFilter = null;
79b44c24fb50845dfbc1f49e78085cf5e01a32067fWinson Chung            return false;
80b44c24fb50845dfbc1f49e78085cf5e01a32067fWinson Chung        }
81303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
82303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
83bc571a980704dc767838935e83c6aed231c406e9Winson Chung    /** Resets this FilteredTaskList. */
84bc571a980704dc767838935e83c6aed231c406e9Winson Chung    void reset() {
85bc571a980704dc767838935e83c6aed231c406e9Winson Chung        mTasks.clear();
86bc571a980704dc767838935e83c6aed231c406e9Winson Chung        mFilteredTasks.clear();
87bc571a980704dc767838935e83c6aed231c406e9Winson Chung        mTaskIndices.clear();
88bc571a980704dc767838935e83c6aed231c406e9Winson Chung        mFilter = null;
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) {
141a4ccb86ddc8f9f486aee25fb836f4aff97bf7679Winson Chung        if (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) {
161303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            int taskCount = mTasks.size();
162303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            for (int i = 0; i < taskCount; i++) {
163303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                Task t = mTasks.get(i);
164303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                if (mFilter.acceptTask(t, i)) {
165303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                    mFilteredTasks.add(t);
166303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                }
167303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            }
168303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        } else {
169303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            mFilteredTasks.addAll(mTasks);
170303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        }
171ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        updateFilteredTaskIndices();
172ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    }
173ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
174ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    /** Updates the mapping of tasks to indices. */
175ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    private void updateFilteredTaskIndices() {
176ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        mTaskIndices.clear();
177ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        int taskCount = mFilteredTasks.size();
178ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        for (int i = 0; i < taskCount; i++) {
179ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            Task t = mFilteredTasks.get(i);
180ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            mTaskIndices.put(t.key, i);
181ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        }
182303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
183303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
184303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Returns whether this task list is filtered */
185303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    boolean hasFilter() {
186303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        return (mFilter != null);
187303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
188303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
189303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Returns the list of filtered tasks */
190303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    ArrayList<Task> getTasks() {
191303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        return mFilteredTasks;
192303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
193303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung}
194303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
195303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung/**
196303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung * The task stack contains a list of multiple tasks.
197303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung */
198303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chungpublic class TaskStack {
199ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
200ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    /** Task stack callbacks */
20104dfe0d26b944324ee920001f40d74cff47281d6Winson Chung    public interface TaskStackCallbacks {
20204dfe0d26b944324ee920001f40d74cff47281d6Winson Chung        /* Notifies when a task has been added to the stack */
20304dfe0d26b944324ee920001f40d74cff47281d6Winson Chung        public void onStackTaskAdded(TaskStack stack, Task t);
20404dfe0d26b944324ee920001f40d74cff47281d6Winson Chung        /* Notifies when a task has been removed from the stack */
20542be431c3d129871d257768e185334d49c071ec5Winson        public void onStackTaskRemoved(TaskStack stack, Task removedTask, boolean wasFrontMostTask,
20642be431c3d129871d257768e185334d49c071ec5Winson                                       Task newFrontMostTask);
2076ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung        /* Notifies when all task has been removed from the stack */
2086ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung        public void onStackAllTasksRemoved(TaskStack stack, ArrayList<Task> removedTasks);
20904dfe0d26b944324ee920001f40d74cff47281d6Winson Chung        /** Notifies when the stack was filtered */
21011ca76a53c60a1898956614315ae929668c523d6Winson Chung        public void onStackFiltered(TaskStack newStack, ArrayList<Task> curTasks, Task t);
21104dfe0d26b944324ee920001f40d74cff47281d6Winson Chung        /** Notifies when the stack was un-filtered */
21211ca76a53c60a1898956614315ae929668c523d6Winson Chung        public void onStackUnfiltered(TaskStack newStack, ArrayList<Task> curTasks);
21304dfe0d26b944324ee920001f40d74cff47281d6Winson Chung    }
21404dfe0d26b944324ee920001f40d74cff47281d6Winson Chung
215be7607af8875236b9cf7bdb5f5aa089c207529afWinson
216eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson    public enum DockState implements DropTarget {
217eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson        NONE(-1, 96, null, null),
2184165d336b6cd69715eda7fbdfd272a878097170eWinson        LEFT(DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, 192,
219eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson                new RectF(0, 0, 0.25f, 1), new RectF(0, 0, 0.25f, 1)),
2204165d336b6cd69715eda7fbdfd272a878097170eWinson        TOP(DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, 192,
221eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson                new RectF(0, 0, 1, 0.25f), new RectF(0, 0, 1, 0.25f)),
2224165d336b6cd69715eda7fbdfd272a878097170eWinson        RIGHT(DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT, 192,
223eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson                new RectF(0.75f, 0, 1, 1), new RectF(0.75f, 0, 1, 1)),
2244165d336b6cd69715eda7fbdfd272a878097170eWinson        BOTTOM(DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT, 192,
225eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson                new RectF(0, 0.75f, 1, 1), new RectF(0, 0.75f, 1, 1));
226eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson
227eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson        @Override
228eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson        public boolean acceptsDrop(int x, int y, int width, int height) {
229eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson            return touchAreaContainsPoint(width, height, x, y);
230eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson        }
231be7607af8875236b9cf7bdb5f5aa089c207529afWinson
232882072baacaee4ecd43f0209b691a9af746462f2Winson        // Represents the view state of this dock state
233882072baacaee4ecd43f0209b691a9af746462f2Winson        public class ViewState {
234882072baacaee4ecd43f0209b691a9af746462f2Winson            public final int dockAreaAlpha;
235882072baacaee4ecd43f0209b691a9af746462f2Winson            public final ColorDrawable dockAreaOverlay;
236882072baacaee4ecd43f0209b691a9af746462f2Winson            private ObjectAnimator dockAreaOverlayAnimator;
237882072baacaee4ecd43f0209b691a9af746462f2Winson
238882072baacaee4ecd43f0209b691a9af746462f2Winson            private ViewState(int alpha) {
239882072baacaee4ecd43f0209b691a9af746462f2Winson                dockAreaAlpha = alpha;
240882072baacaee4ecd43f0209b691a9af746462f2Winson                dockAreaOverlay = new ColorDrawable(0xFFffffff);
241882072baacaee4ecd43f0209b691a9af746462f2Winson                dockAreaOverlay.setAlpha(0);
242882072baacaee4ecd43f0209b691a9af746462f2Winson            }
243882072baacaee4ecd43f0209b691a9af746462f2Winson
244882072baacaee4ecd43f0209b691a9af746462f2Winson            /**
245882072baacaee4ecd43f0209b691a9af746462f2Winson             * Creates a new alpha animation.
246882072baacaee4ecd43f0209b691a9af746462f2Winson             */
247882072baacaee4ecd43f0209b691a9af746462f2Winson            public void startAlphaAnimation(int alpha, int duration) {
248882072baacaee4ecd43f0209b691a9af746462f2Winson                if (dockAreaOverlay.getAlpha() != alpha) {
249882072baacaee4ecd43f0209b691a9af746462f2Winson                    if (dockAreaOverlayAnimator != null) {
250882072baacaee4ecd43f0209b691a9af746462f2Winson                        dockAreaOverlayAnimator.cancel();
251882072baacaee4ecd43f0209b691a9af746462f2Winson                    }
252882072baacaee4ecd43f0209b691a9af746462f2Winson                    dockAreaOverlayAnimator = ObjectAnimator.ofInt(dockAreaOverlay, "alpha", alpha);
253882072baacaee4ecd43f0209b691a9af746462f2Winson                    dockAreaOverlayAnimator.setDuration(duration);
254882072baacaee4ecd43f0209b691a9af746462f2Winson                    dockAreaOverlayAnimator.start();
255882072baacaee4ecd43f0209b691a9af746462f2Winson                }
256882072baacaee4ecd43f0209b691a9af746462f2Winson            }
257882072baacaee4ecd43f0209b691a9af746462f2Winson        }
258882072baacaee4ecd43f0209b691a9af746462f2Winson
259be7607af8875236b9cf7bdb5f5aa089c207529afWinson        public final int createMode;
260882072baacaee4ecd43f0209b691a9af746462f2Winson        public final ViewState viewState;
261be7607af8875236b9cf7bdb5f5aa089c207529afWinson        private final RectF dockArea;
262882072baacaee4ecd43f0209b691a9af746462f2Winson        private final RectF touchArea;
263be7607af8875236b9cf7bdb5f5aa089c207529afWinson
264be7607af8875236b9cf7bdb5f5aa089c207529afWinson        /**
265be7607af8875236b9cf7bdb5f5aa089c207529afWinson         * @param createMode used to pass to ActivityManager to dock the task
266be7607af8875236b9cf7bdb5f5aa089c207529afWinson         * @param touchArea the area in which touch will initiate this dock state
267eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson         * @param dockArea the visible dock area
268be7607af8875236b9cf7bdb5f5aa089c207529afWinson         */
269eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson        DockState(int createMode, int dockAreaAlpha, RectF touchArea, RectF dockArea) {
270be7607af8875236b9cf7bdb5f5aa089c207529afWinson            this.createMode = createMode;
271882072baacaee4ecd43f0209b691a9af746462f2Winson            this.viewState = new ViewState(dockAreaAlpha);
272be7607af8875236b9cf7bdb5f5aa089c207529afWinson            this.dockArea = dockArea;
273882072baacaee4ecd43f0209b691a9af746462f2Winson            this.touchArea = touchArea;
274be7607af8875236b9cf7bdb5f5aa089c207529afWinson        }
275be7607af8875236b9cf7bdb5f5aa089c207529afWinson
276be7607af8875236b9cf7bdb5f5aa089c207529afWinson        /**
277be7607af8875236b9cf7bdb5f5aa089c207529afWinson         * Returns whether {@param x} and {@param y} are contained in the touch area scaled to the
278be7607af8875236b9cf7bdb5f5aa089c207529afWinson         * given {@param width} and {@param height}.
279be7607af8875236b9cf7bdb5f5aa089c207529afWinson         */
280be7607af8875236b9cf7bdb5f5aa089c207529afWinson        public boolean touchAreaContainsPoint(int width, int height, float x, float y) {
281be7607af8875236b9cf7bdb5f5aa089c207529afWinson            int left = (int) (touchArea.left * width);
282be7607af8875236b9cf7bdb5f5aa089c207529afWinson            int top = (int) (touchArea.top * height);
283be7607af8875236b9cf7bdb5f5aa089c207529afWinson            int right = (int) (touchArea.right * width);
284be7607af8875236b9cf7bdb5f5aa089c207529afWinson            int bottom = (int) (touchArea.bottom * height);
285be7607af8875236b9cf7bdb5f5aa089c207529afWinson            return x >= left && y >= top && x <= right && y <= bottom;
286be7607af8875236b9cf7bdb5f5aa089c207529afWinson        }
287be7607af8875236b9cf7bdb5f5aa089c207529afWinson
288be7607af8875236b9cf7bdb5f5aa089c207529afWinson        /**
289be7607af8875236b9cf7bdb5f5aa089c207529afWinson         * Returns the docked task bounds with the given {@param width} and {@param height}.
290be7607af8875236b9cf7bdb5f5aa089c207529afWinson         */
291be7607af8875236b9cf7bdb5f5aa089c207529afWinson        public Rect getDockedBounds(int width, int height) {
292be7607af8875236b9cf7bdb5f5aa089c207529afWinson            return new Rect((int) (dockArea.left * width), (int) (dockArea.top * height),
293be7607af8875236b9cf7bdb5f5aa089c207529afWinson                    (int) (dockArea.right * width), (int) (dockArea.bottom * height));
294be7607af8875236b9cf7bdb5f5aa089c207529afWinson        }
295be7607af8875236b9cf7bdb5f5aa089c207529afWinson    }
296be7607af8875236b9cf7bdb5f5aa089c207529afWinson
297083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung    // The task offset to apply to a task id as a group affiliation
298083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung    static final int IndividualTaskIdOffset = 1 << 16;
299083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung
300303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    FilteredTaskList mTaskList = new FilteredTaskList();
301303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    TaskStackCallbacks mCb;
302303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
303ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    ArrayList<TaskGrouping> mGroups = new ArrayList<TaskGrouping>();
304083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung    HashMap<Integer, TaskGrouping> mAffinitiesGroups = new HashMap<Integer, TaskGrouping>();
305303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
306d16c565a607de754379fe699a4def21bd0e3de2fWinson Chung    /** Sets the callbacks for this task stack. */
307303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    public void setCallbacks(TaskStackCallbacks cb) {
308303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mCb = cb;
309303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
310303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
311bc571a980704dc767838935e83c6aed231c406e9Winson Chung    /** Resets this TaskStack. */
312bc571a980704dc767838935e83c6aed231c406e9Winson Chung    public void reset() {
313bc571a980704dc767838935e83c6aed231c406e9Winson Chung        mCb = null;
314bc571a980704dc767838935e83c6aed231c406e9Winson Chung        mTaskList.reset();
315bc571a980704dc767838935e83c6aed231c406e9Winson Chung        mGroups.clear();
316bc571a980704dc767838935e83c6aed231c406e9Winson Chung        mAffinitiesGroups.clear();
317bc571a980704dc767838935e83c6aed231c406e9Winson Chung    }
318bc571a980704dc767838935e83c6aed231c406e9Winson Chung
319303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Adds a new task */
320303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    public void addTask(Task t) {
321303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mTaskList.add(t);
322303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        if (mCb != null) {
323303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            mCb.onStackTaskAdded(this, t);
324303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        }
325303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
326303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
327eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson    /**
328eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson     * Moves the given task to either the front of the freeform workspace or the stack.
329eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson     */
330eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson    public void moveTaskToStack(Task task, int newStackId) {
331eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson        // Find the index to insert into
332eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson        ArrayList<Task> taskList = mTaskList.getTasks();
333eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson        int taskCount = taskList.size();
334eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson        if (!task.isFreeformTask() && (newStackId == FREEFORM_WORKSPACE_STACK_ID)) {
335eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson            // Insert freeform tasks at the front
336eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson            mTaskList.moveTaskToStack(task, taskCount, newStackId);
337eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson        } else if (task.isFreeformTask() && (newStackId == FULLSCREEN_WORKSPACE_STACK_ID)) {
338eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson            // Insert after the first stacked task
339eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson            int insertIndex = 0;
340eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson            for (int i = taskCount - 1; i >= 0; i--) {
341eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson                if (!taskList.get(i).isFreeformTask()) {
342eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson                    insertIndex = i + 1;
343eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson                    break;
344eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson                }
345eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson            }
346eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson            mTaskList.moveTaskToStack(task, insertIndex, newStackId);
347eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson        }
348eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson    }
349eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson
3506ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung    /** Does the actual work associated with removing the task. */
3516ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung    void removeTaskImpl(Task t) {
3526ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung        // Remove the task from the list
3536ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung        mTaskList.remove(t);
3546ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung        // Remove it from the group as well, and if it is empty, remove the group
3556ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung        TaskGrouping group = t.group;
3566ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung        group.removeTask(t);
3576ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung        if (group.getTaskCount() == 0) {
3586ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung            removeGroup(group);
3596ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung        }
3606ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung        // Update the lock-to-app state
3616ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung        t.lockToThisTask = false;
3626ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung    }
3636ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung
364303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Removes a task */
365303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    public void removeTask(Task t) {
366303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        if (mTaskList.contains(t)) {
36742be431c3d129871d257768e185334d49c071ec5Winson            boolean wasFrontMostTask = (getFrontMostTask() == t);
3686ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung            removeTaskImpl(t);
36982c8c5e9872b984ba6f43b01da0c7731fd5bf762Winson Chung            Task newFrontMostTask = getFrontMostTask();
37056e09b42a0f1670970872bef611a8036904ad6bfJason Monk            if (newFrontMostTask != null && newFrontMostTask.lockToTaskEnabled) {
37156e09b42a0f1670970872bef611a8036904ad6bfJason Monk                newFrontMostTask.lockToThisTask = true;
3721f24c7e37bc794057a156a730c7e4b53b01212edWinson Chung            }
373303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            if (mCb != null) {
374ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                // Notify that a task has been removed
37542be431c3d129871d257768e185334d49c071ec5Winson                mCb.onStackTaskRemoved(this, t, wasFrontMostTask, newFrontMostTask);
376303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            }
377303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        }
378303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
379303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
3806ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung    /** Removes all tasks */
3816ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung    public void removeAllTasks() {
3826ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung        ArrayList<Task> taskList = new ArrayList<Task>(mTaskList.getTasks());
3836ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung        int taskCount = taskList.size();
3846ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung        for (int i = taskCount - 1; i >= 0; i--) {
3856ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung            Task t = taskList.get(i);
3866ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung            removeTaskImpl(t);
3876ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung        }
3886ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung        if (mCb != null) {
3896ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung            // Notify that all tasks have been removed
3906ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung            mCb.onStackAllTasksRemoved(this, taskList);
3916ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung        }
3926ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung    }
3936ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung
394303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Sets a few tasks in one go */
395303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    public void setTasks(List<Task> tasks) {
396ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        ArrayList<Task> taskList = mTaskList.getTasks();
397ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        int taskCount = taskList.size();
3986ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung        for (int i = taskCount - 1; i >= 0; i--) {
399ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            Task t = taskList.get(i);
4006ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung            removeTaskImpl(t);
401303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            if (mCb != null) {
402ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                // Notify that a task has been removed
40342be431c3d129871d257768e185334d49c071ec5Winson                mCb.onStackTaskRemoved(this, t, false, null);
404303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            }
405303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        }
406303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mTaskList.set(tasks);
407303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        for (Task t : tasks) {
408303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            if (mCb != null) {
409303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                mCb.onStackTaskAdded(this, t);
410303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            }
411303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        }
412303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
413303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
414ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    /** Gets the front task */
415ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    public Task getFrontMostTask() {
4161f24c7e37bc794057a156a730c7e4b53b01212edWinson Chung        if (mTaskList.size() == 0) return null;
417ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        return mTaskList.getTasks().get(mTaskList.size() - 1);
418ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    }
419ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
42004400672962d2e12132f9465928cbf7615c147c4Winson Chung    /** Gets the task keys */
42104400672962d2e12132f9465928cbf7615c147c4Winson Chung    public ArrayList<Task.TaskKey> getTaskKeys() {
42204400672962d2e12132f9465928cbf7615c147c4Winson Chung        ArrayList<Task.TaskKey> taskKeys = new ArrayList<Task.TaskKey>();
42304400672962d2e12132f9465928cbf7615c147c4Winson Chung        ArrayList<Task> tasks = mTaskList.getTasks();
42404400672962d2e12132f9465928cbf7615c147c4Winson Chung        int taskCount = tasks.size();
42504400672962d2e12132f9465928cbf7615c147c4Winson Chung        for (int i = 0; i < taskCount; i++) {
42604400672962d2e12132f9465928cbf7615c147c4Winson Chung            taskKeys.add(tasks.get(i).key);
42704400672962d2e12132f9465928cbf7615c147c4Winson Chung        }
42804400672962d2e12132f9465928cbf7615c147c4Winson Chung        return taskKeys;
42904400672962d2e12132f9465928cbf7615c147c4Winson Chung    }
43004400672962d2e12132f9465928cbf7615c147c4Winson Chung
431303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Gets the tasks */
432303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    public ArrayList<Task> getTasks() {
433303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        return mTaskList.getTasks();
434303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
435303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
436303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Gets the number of tasks */
437303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    public int getTaskCount() {
438303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        return mTaskList.size();
439303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
440303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
44136a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson    /**
44236a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson     * Returns the task in this stack which is the launch target.
44336a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson     */
44436a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson    public Task getLaunchTarget() {
44536a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson        ArrayList<Task> tasks = mTaskList.getTasks();
44636a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson        int taskCount = tasks.size();
44736a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson        for (int i = 0; i < taskCount; i++) {
44836a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson            Task task = tasks.get(i);
44936a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson            if (task.isLaunchTarget) {
45036a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson                return task;
45136a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson            }
45236a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson        }
45336a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson        return null;
45436a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson    }
45536a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson
456303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Returns the index of this task in this current task stack */
457303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    public int indexOfTask(Task t) {
458303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        return mTaskList.indexOf(t);
459303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
460303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
461b1f749906f5c27114d02ea0c3f8ce0dcea08fd3fWinson Chung    /** Finds the task with the specified task id. */
462b1f749906f5c27114d02ea0c3f8ce0dcea08fd3fWinson Chung    public Task findTaskWithId(int taskId) {
463b1f749906f5c27114d02ea0c3f8ce0dcea08fd3fWinson Chung        ArrayList<Task> tasks = mTaskList.getTasks();
464b1f749906f5c27114d02ea0c3f8ce0dcea08fd3fWinson Chung        int taskCount = tasks.size();
465b1f749906f5c27114d02ea0c3f8ce0dcea08fd3fWinson Chung        for (int i = 0; i < taskCount; i++) {
466b1f749906f5c27114d02ea0c3f8ce0dcea08fd3fWinson Chung            Task task = tasks.get(i);
467b1f749906f5c27114d02ea0c3f8ce0dcea08fd3fWinson Chung            if (task.key.id == taskId) {
468b1f749906f5c27114d02ea0c3f8ce0dcea08fd3fWinson Chung                return task;
469b1f749906f5c27114d02ea0c3f8ce0dcea08fd3fWinson Chung            }
470b1f749906f5c27114d02ea0c3f8ce0dcea08fd3fWinson Chung        }
471b1f749906f5c27114d02ea0c3f8ce0dcea08fd3fWinson Chung        return null;
472b1f749906f5c27114d02ea0c3f8ce0dcea08fd3fWinson Chung    }
473b1f749906f5c27114d02ea0c3f8ce0dcea08fd3fWinson Chung
47436a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson    /**
47536a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson     * Returns whether this stack has freeform tasks.
47636a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson     */
47736a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson    public boolean hasFreeformTasks() {
47836a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson        ArrayList<Task> tasks = mTaskList.getTasks();
47936a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson        int taskCount = tasks.size();
48036a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson        for (int i = 0; i < taskCount; i++) {
48136a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson            Task task = tasks.get(i);
48236a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson            if (task.isFreeformTask()) {
48336a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson                return true;
48436a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson            }
48536a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson        }
48636a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson        return false;
48736a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson    }
48836a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson
489ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    /******** Filtering ********/
490303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
491303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Filters the stack into tasks similar to the one specified */
492c6a1623cc48581380b698ae87b43bfafb9c935baWinson Chung    public void filterTasks(final Task t) {
493c6a1623cc48581380b698ae87b43bfafb9c935baWinson Chung        ArrayList<Task> oldStack = new ArrayList<Task>(mTaskList.getTasks());
494c6a1623cc48581380b698ae87b43bfafb9c935baWinson Chung
495303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        // Set the task list filter
496c6a1623cc48581380b698ae87b43bfafb9c935baWinson Chung        boolean filtered = mTaskList.setFilter(new TaskFilter() {
497303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            @Override
498c6a1623cc48581380b698ae87b43bfafb9c935baWinson Chung            public boolean acceptTask(Task at, int i) {
499e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                return t.key.getComponent().getPackageName().equals(
500e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                        at.key.getComponent().getPackageName());
501303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            }
502303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        });
503c6a1623cc48581380b698ae87b43bfafb9c935baWinson Chung        if (filtered && mCb != null) {
504c6a1623cc48581380b698ae87b43bfafb9c935baWinson Chung            mCb.onStackFiltered(this, oldStack, t);
505303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        }
506303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
507303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
508303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Unfilters the current stack */
509303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    public void unfilterTasks() {
510c6a1623cc48581380b698ae87b43bfafb9c935baWinson Chung        ArrayList<Task> oldStack = new ArrayList<Task>(mTaskList.getTasks());
511c6a1623cc48581380b698ae87b43bfafb9c935baWinson Chung
512303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        // Unset the filter, then update the virtual scroll
513303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mTaskList.removeFilter();
514303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        if (mCb != null) {
515c6a1623cc48581380b698ae87b43bfafb9c935baWinson Chung            mCb.onStackUnfiltered(this, oldStack);
516303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        }
517303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
518303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
519303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Returns whether tasks are currently filtered */
520303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    public boolean hasFilteredTasks() {
521303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        return mTaskList.hasFilter();
522303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
523303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
524ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    /******** Grouping ********/
525ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
526ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    /** Adds a group to the set */
527ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    public void addGroup(TaskGrouping group) {
528ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        mGroups.add(group);
529ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        mAffinitiesGroups.put(group.affiliation, group);
530ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    }
531ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
532ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    public void removeGroup(TaskGrouping group) {
533ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        mGroups.remove(group);
534ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        mAffinitiesGroups.remove(group.affiliation);
535ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    }
536ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
537ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    /** Returns the group with the specified affiliation. */
538083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung    public TaskGrouping getGroupWithAffiliation(int affiliation) {
539ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        return mAffinitiesGroups.get(affiliation);
540ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    }
541ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
542ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    /**
543ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung     * Temporary: This method will simulate affiliation groups by
544ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung     */
54535f3050959e43bf378f9a0adcaef13729206c7e4Winson    public void createAffiliatedGroupings(Context context) {
546c742f973b1e506732911c156c5869fd377afc5bfWinson        if (RecentsDebugFlags.Static.EnableSimulatedTaskGroups) {
547ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            HashMap<Task.TaskKey, Task> taskMap = new HashMap<Task.TaskKey, Task>();
548ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            // Sort all tasks by increasing firstActiveTime of the task
549ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            ArrayList<Task> tasks = mTaskList.getTasks();
550ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            Collections.sort(tasks, new Comparator<Task>() {
551ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                @Override
552ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                public int compare(Task task, Task task2) {
553ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    return (int) (task.key.firstActiveTime - task2.key.firstActiveTime);
554ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                }
555ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            });
556ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            // Create groups when sequential packages are the same
557ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            NamedCounter counter = new NamedCounter("task-group", "");
558ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            int taskCount = tasks.size();
559ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            String prevPackage = "";
560083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung            int prevAffiliation = -1;
561a433fa9c17772f563163ff7db177d091d6aebd5bWinson Chung            Random r = new Random();
562c742f973b1e506732911c156c5869fd377afc5bfWinson            int groupCountDown = RecentsDebugFlags.Static.TaskAffiliationsGroupCount;
563ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            for (int i = 0; i < taskCount; i++) {
564ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                Task t = tasks.get(i);
565e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                String packageName = t.key.getComponent().getPackageName();
566a433fa9c17772f563163ff7db177d091d6aebd5bWinson Chung                packageName = "pkg";
567ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                TaskGrouping group;
568a433fa9c17772f563163ff7db177d091d6aebd5bWinson Chung                if (packageName.equals(prevPackage) && groupCountDown > 0) {
569ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    group = getGroupWithAffiliation(prevAffiliation);
570a433fa9c17772f563163ff7db177d091d6aebd5bWinson Chung                    groupCountDown--;
571ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                } else {
572083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung                    int affiliation = IndividualTaskIdOffset + t.key.id;
573ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    group = new TaskGrouping(affiliation);
574ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    addGroup(group);
575ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    prevAffiliation = affiliation;
576ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    prevPackage = packageName;
577c742f973b1e506732911c156c5869fd377afc5bfWinson                    groupCountDown = RecentsDebugFlags.Static.TaskAffiliationsGroupCount;
578ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                }
579ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                group.addTask(t);
580ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                taskMap.put(t.key, t);
581ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            }
582ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            // Sort groups by increasing latestActiveTime of the group
583ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            Collections.sort(mGroups, new Comparator<TaskGrouping>() {
584ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                @Override
585ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                public int compare(TaskGrouping taskGrouping, TaskGrouping taskGrouping2) {
586ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    return (int) (taskGrouping.latestActiveTimeInGroup -
587ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                            taskGrouping2.latestActiveTimeInGroup);
588ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                }
589ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            });
590ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            // Sort group tasks by increasing firstActiveTime of the task, and also build a new list of
591ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            // tasks
592ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            int taskIndex = 0;
593ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            int groupCount = mGroups.size();
594ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            for (int i = 0; i < groupCount; i++) {
595ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                TaskGrouping group = mGroups.get(i);
596083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung                Collections.sort(group.mTaskKeys, new Comparator<Task.TaskKey>() {
597ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    @Override
598ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    public int compare(Task.TaskKey taskKey, Task.TaskKey taskKey2) {
599ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                        return (int) (taskKey.firstActiveTime - taskKey2.firstActiveTime);
600ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    }
601ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                });
602083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung                ArrayList<Task.TaskKey> groupTasks = group.mTaskKeys;
603ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                int groupTaskCount = groupTasks.size();
604ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                for (int j = 0; j < groupTaskCount; j++) {
605ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    tasks.set(taskIndex, taskMap.get(groupTasks.get(j)));
606ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    taskIndex++;
607ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                }
608ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            }
609ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            mTaskList.set(tasks);
610ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        } else {
611083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung            // Create the task groups
612ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung            HashMap<Task.TaskKey, Task> tasksMap = new HashMap<Task.TaskKey, Task>();
613ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            ArrayList<Task> tasks = mTaskList.getTasks();
614ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            int taskCount = tasks.size();
615ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            for (int i = 0; i < taskCount; i++) {
616ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                Task t = tasks.get(i);
617083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung                TaskGrouping group;
618083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung                int affiliation = t.taskAffiliation > 0 ? t.taskAffiliation :
619083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung                        IndividualTaskIdOffset + t.key.id;
620083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung                if (mAffinitiesGroups.containsKey(affiliation)) {
621083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung                    group = getGroupWithAffiliation(affiliation);
622083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung                } else {
623083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung                    group = new TaskGrouping(affiliation);
624083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung                    addGroup(group);
625083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung                }
626ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                group.addTask(t);
627ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                tasksMap.put(t.key, t);
628ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung            }
629ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung            // Update the task colors for each of the groups
63035f3050959e43bf378f9a0adcaef13729206c7e4Winson            float minAlpha = context.getResources().getFloat(
63135f3050959e43bf378f9a0adcaef13729206c7e4Winson                    R.dimen.recents_task_affiliation_color_min_alpha_percentage);
632ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung            int taskGroupCount = mGroups.size();
633ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung            for (int i = 0; i < taskGroupCount; i++) {
634ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                TaskGrouping group = mGroups.get(i);
635ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                taskCount = group.getTaskCount();
636ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                // Ignore the groups that only have one task
637ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                if (taskCount <= 1) continue;
638ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                // Calculate the group color distribution
639ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                int affiliationColor = tasksMap.get(group.mTaskKeys.get(0)).taskAffiliationColor;
640ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                float alphaStep = (1f - minAlpha) / taskCount;
641ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                float alpha = 1f;
642ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                for (int j = 0; j < taskCount; j++) {
643ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                    Task t = tasksMap.get(group.mTaskKeys.get(j));
644a0e88b5013d708ac6ed6518817d83c64c87ae4b1Winson Chung                    t.colorPrimary = Utilities.getColorWithOverlay(affiliationColor, Color.WHITE,
645a0e88b5013d708ac6ed6518817d83c64c87ae4b1Winson Chung                            alpha);
646ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                    alpha -= alphaStep;
647ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                }
648ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            }
649ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        }
650ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    }
651ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
652e7f138c7f0a190c86cec10fb32fa106aacae4093Winson    /**
653e7f138c7f0a190c86cec10fb32fa106aacae4093Winson     * Computes the components of tasks in this stack that have been removed as a result of a change
654e7f138c7f0a190c86cec10fb32fa106aacae4093Winson     * in the specified package.
655e7f138c7f0a190c86cec10fb32fa106aacae4093Winson     */
656e7f138c7f0a190c86cec10fb32fa106aacae4093Winson    public HashSet<ComponentName> computeComponentsRemoved(String packageName, int userId) {
657e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        // Identify all the tasks that should be removed as a result of the package being removed.
658e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        // Using a set to ensure that we callback once per unique component.
659e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        SystemServicesProxy ssp = Recents.getSystemServices();
660e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        HashSet<ComponentName> existingComponents = new HashSet<>();
661e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        HashSet<ComponentName> removedComponents = new HashSet<>();
662e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        ArrayList<Task.TaskKey> taskKeys = getTaskKeys();
663e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        for (Task.TaskKey t : taskKeys) {
664e7f138c7f0a190c86cec10fb32fa106aacae4093Winson            // Skip if this doesn't apply to the current user
665e7f138c7f0a190c86cec10fb32fa106aacae4093Winson            if (t.userId != userId) continue;
666e7f138c7f0a190c86cec10fb32fa106aacae4093Winson
667e7f138c7f0a190c86cec10fb32fa106aacae4093Winson            ComponentName cn = t.getComponent();
668e7f138c7f0a190c86cec10fb32fa106aacae4093Winson            if (cn.getPackageName().equals(packageName)) {
669e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                if (existingComponents.contains(cn)) {
670e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                    // If we know that the component still exists in the package, then skip
671e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                    continue;
672e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                }
673e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                if (ssp.getActivityInfo(cn, userId) != null) {
674e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                    existingComponents.add(cn);
675e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                } else {
676e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                    removedComponents.add(cn);
677e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                }
678e7f138c7f0a190c86cec10fb32fa106aacae4093Winson            }
679e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        }
680e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        return removedComponents;
681e7f138c7f0a190c86cec10fb32fa106aacae4093Winson    }
682e7f138c7f0a190c86cec10fb32fa106aacae4093Winson
683303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    @Override
684303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    public String toString() {
685303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        String str = "Tasks:\n";
686303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        for (Task t : mTaskList.getTasks()) {
687303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            str += "  " + t.toString() + "\n";
688303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        }
689303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        return str;
690303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
691303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung}