TaskStack.java revision d952961977a0eb6c1fefcb0707d1c61741515f68
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
193e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winsonimport android.animation.Animator;
203e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winsonimport android.animation.AnimatorSet;
21882072baacaee4ecd43f0209b691a9af746462f2Winsonimport android.animation.ObjectAnimator;
223e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winsonimport android.animation.PropertyValuesHolder;
233e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winsonimport android.animation.RectEvaluator;
24e7f138c7f0a190c86cec10fb32fa106aacae4093Winsonimport android.content.ComponentName;
2535f3050959e43bf378f9a0adcaef13729206c7e4Winsonimport android.content.Context;
263e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winsonimport android.content.res.Configuration;
273e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winsonimport android.content.res.Resources;
28ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chungimport android.graphics.Color;
29be7607af8875236b9cf7bdb5f5aa089c207529afWinsonimport android.graphics.Rect;
30be7607af8875236b9cf7bdb5f5aa089c207529afWinsonimport android.graphics.RectF;
31882072baacaee4ecd43f0209b691a9af746462f2Winsonimport android.graphics.drawable.ColorDrawable;
325500390a006f2bbea565068234774a36cea076c0Winsonimport android.util.ArrayMap;
335500390a006f2bbea565068234774a36cea076c0Winsonimport android.util.ArraySet;
342b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chungimport android.util.SparseArray;
353e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winsonimport android.view.animation.Interpolator;
36c0d7058b14c24cd07912f5629c26b39b7b4673d5Winson
373e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winsonimport com.android.internal.policy.DockedDividerUtils;
382536c7ed446203ea12b38cf05a88e603f8d1b768Winsonimport com.android.systemui.R;
39e7f138c7f0a190c86cec10fb32fa106aacae4093Winsonimport com.android.systemui.recents.Recents;
403e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winsonimport com.android.systemui.recents.RecentsConfiguration;
41c742f973b1e506732911c156c5869fd377afc5bfWinsonimport com.android.systemui.recents.RecentsDebugFlags;
42ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chungimport com.android.systemui.recents.misc.NamedCounter;
43e7f138c7f0a190c86cec10fb32fa106aacae4093Winsonimport com.android.systemui.recents.misc.SystemServicesProxy;
44a0e88b5013d708ac6ed6518817d83c64c87ae4b1Winson Chungimport com.android.systemui.recents.misc.Utilities;
45eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winsonimport com.android.systemui.recents.views.DropTarget;
468aa9959413a06c3d2ff75e0c7be9e3cb7ac7cd2eWinsonimport com.android.systemui.recents.views.TaskViewAnimation;
47303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
48303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chungimport java.util.ArrayList;
49ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chungimport java.util.Collections;
50ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chungimport java.util.Comparator;
51303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chungimport java.util.List;
52a433fa9c17772f563163ff7db177d091d6aebd5bWinson Chungimport java.util.Random;
53303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
54be7607af8875236b9cf7bdb5f5aa089c207529afWinsonimport static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT;
55be7607af8875236b9cf7bdb5f5aa089c207529afWinsonimport static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
56eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winsonimport static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
57eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winsonimport static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
585500390a006f2bbea565068234774a36cea076c0Winsonimport static android.view.WindowManager.DOCKED_BOTTOM;
595500390a006f2bbea565068234774a36cea076c0Winsonimport static android.view.WindowManager.DOCKED_INVALID;
603e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winsonimport static android.view.WindowManager.DOCKED_LEFT;
613e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winsonimport static android.view.WindowManager.DOCKED_RIGHT;
623e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winsonimport static android.view.WindowManager.DOCKED_TOP;
63be7607af8875236b9cf7bdb5f5aa089c207529afWinson
64303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
65303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung/**
66303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung * An interface for a task filter to query whether a particular task should show in a stack.
67303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung */
68303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chunginterface TaskFilter {
69303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Returns whether the filter accepts the specified task */
702b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung    public boolean acceptTask(SparseArray<Task> taskIdMap, Task t, int index);
71303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung}
72303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
73303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung/**
74303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung * A list of filtered tasks.
75303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung */
76303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chungclass FilteredTaskList {
77eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson
78eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson    ArrayList<Task> mTasks = new ArrayList<>();
79eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson    ArrayList<Task> mFilteredTasks = new ArrayList<>();
805500390a006f2bbea565068234774a36cea076c0Winson    ArrayMap<Task.TaskKey, Integer> mTaskIndices = new ArrayMap<>();
81303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    TaskFilter mFilter;
82303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
83303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Sets the task filter, saving the current touch state */
84c6a1623cc48581380b698ae87b43bfafb9c935baWinson Chung    boolean setFilter(TaskFilter filter) {
855500390a006f2bbea565068234774a36cea076c0Winson        ArrayList<Task> prevFilteredTasks = new ArrayList<>(mFilteredTasks);
86303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mFilter = filter;
87303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        updateFilteredTasks();
88b44c24fb50845dfbc1f49e78085cf5e01a32067fWinson Chung        if (!prevFilteredTasks.equals(mFilteredTasks)) {
89b44c24fb50845dfbc1f49e78085cf5e01a32067fWinson Chung            return true;
90b44c24fb50845dfbc1f49e78085cf5e01a32067fWinson Chung        } else {
91b44c24fb50845dfbc1f49e78085cf5e01a32067fWinson Chung            return false;
92b44c24fb50845dfbc1f49e78085cf5e01a32067fWinson Chung        }
93303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
94303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
958f0e3a68cdd3b2403ff8a1677f90b998f4175f40Winson    /**
968f0e3a68cdd3b2403ff8a1677f90b998f4175f40Winson     * Resets the task list, but does not remove the filter.
978f0e3a68cdd3b2403ff8a1677f90b998f4175f40Winson     */
98bc571a980704dc767838935e83c6aed231c406e9Winson Chung    void reset() {
99bc571a980704dc767838935e83c6aed231c406e9Winson Chung        mTasks.clear();
100bc571a980704dc767838935e83c6aed231c406e9Winson Chung        mFilteredTasks.clear();
101bc571a980704dc767838935e83c6aed231c406e9Winson Chung        mTaskIndices.clear();
102bc571a980704dc767838935e83c6aed231c406e9Winson Chung    }
103bc571a980704dc767838935e83c6aed231c406e9Winson Chung
104303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Removes the task filter and returns the previous touch state */
105303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    void removeFilter() {
106303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mFilter = null;
107303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        updateFilteredTasks();
108303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
109303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
110303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Adds a new task to the task list */
111303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    void add(Task t) {
112303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mTasks.add(t);
113303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        updateFilteredTasks();
114303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
115303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
116eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson    /**
117eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson     * Moves the given task.
118eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson     */
119eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson    public void moveTaskToStack(Task task, int insertIndex, int newStackId) {
120eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson        int taskIndex = indexOf(task);
121eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson        if (taskIndex != insertIndex) {
122eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson            mTasks.remove(taskIndex);
123eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson            if (taskIndex < insertIndex) {
124eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson                insertIndex--;
125eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson            }
126eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson            mTasks.add(insertIndex, task);
127eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson        }
128eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson
129eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson        // Update the stack id now, after we've moved the task, and before we update the
130eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson        // filtered tasks
131eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson        task.setStackId(newStackId);
132eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson        updateFilteredTasks();
133eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson    }
134eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson
135303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Sets the list of tasks */
136303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    void set(List<Task> tasks) {
137303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mTasks.clear();
138303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mTasks.addAll(tasks);
139303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        updateFilteredTasks();
140303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
141303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
142303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Removes a task from the base list only if it is in the filtered list */
143303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    boolean remove(Task t) {
144303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        if (mFilteredTasks.contains(t)) {
145303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            boolean removed = mTasks.remove(t);
146303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            updateFilteredTasks();
147303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            return removed;
148303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        }
149303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        return false;
150303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
151303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
152303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Returns the index of this task in the list of filtered tasks */
153303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    int indexOf(Task t) {
15423746d51d922d3df2cdd2635d0c133366c754438Winson        if (t != null && mTaskIndices.containsKey(t.key)) {
155a4ccb86ddc8f9f486aee25fb836f4aff97bf7679Winson Chung            return mTaskIndices.get(t.key);
156a4ccb86ddc8f9f486aee25fb836f4aff97bf7679Winson Chung        }
157a4ccb86ddc8f9f486aee25fb836f4aff97bf7679Winson Chung        return -1;
158303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
159303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
160303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Returns the size of the list of filtered tasks */
161303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    int size() {
162303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        return mFilteredTasks.size();
163303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
164303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
165303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Returns whether the filtered list contains this task */
166303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    boolean contains(Task t) {
167ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        return mTaskIndices.containsKey(t.key);
168303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
169303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
170303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Updates the list of filtered tasks whenever the base task list changes */
171303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    private void updateFilteredTasks() {
172303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mFilteredTasks.clear();
173303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        if (mFilter != null) {
1742b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung            // Create a sparse array from task id to Task
1752b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung            SparseArray<Task> taskIdMap = new SparseArray<>();
176303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            int taskCount = mTasks.size();
177303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            for (int i = 0; i < taskCount; i++) {
178303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                Task t = mTasks.get(i);
1792b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung                taskIdMap.put(t.key.id, t);
1802b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung            }
1812b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung
1822b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung            for (int i = 0; i < taskCount; i++) {
1832b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung                Task t = mTasks.get(i);
1842b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung                if (mFilter.acceptTask(taskIdMap, t, i)) {
185303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                    mFilteredTasks.add(t);
186303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung                }
187303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            }
188303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        } else {
189303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            mFilteredTasks.addAll(mTasks);
190303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        }
191ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        updateFilteredTaskIndices();
192ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    }
193ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
194ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    /** Updates the mapping of tasks to indices. */
195ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    private void updateFilteredTaskIndices() {
196ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        int taskCount = mFilteredTasks.size();
1975500390a006f2bbea565068234774a36cea076c0Winson        mTaskIndices.clear();
198ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        for (int i = 0; i < taskCount; i++) {
199ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            Task t = mFilteredTasks.get(i);
200ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            mTaskIndices.put(t.key, i);
201ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        }
202303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
203303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
204303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Returns whether this task list is filtered */
205303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    boolean hasFilter() {
206303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        return (mFilter != null);
207303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
208303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
209303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Returns the list of filtered tasks */
210303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    ArrayList<Task> getTasks() {
211303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        return mFilteredTasks;
212303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
213303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung}
214303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
215303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung/**
216303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung * The task stack contains a list of multiple tasks.
217303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung */
218303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chungpublic class TaskStack {
219ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
220ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    /** Task stack callbacks */
22104dfe0d26b944324ee920001f40d74cff47281d6Winson Chung    public interface TaskStackCallbacks {
222062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        /**
223062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung         * Notifies when a new task has been added to the stack.
224062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung         */
225062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        void onStackTaskAdded(TaskStack stack, Task newTask);
226062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung
227062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        /**
228062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung         * Notifies when a task has been removed from the stack.
229062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung         */
230aaf33bc2b27fa0c4b59484059434a0fad3187af4Winson        void onStackTaskRemoved(TaskStack stack, Task removedTask, boolean wasFrontMostTask,
2318aa9959413a06c3d2ff75e0c7be9e3cb7ac7cd2eWinson            Task newFrontMostTask, TaskViewAnimation animation);
232a0731a1a2611d5a89c5960fe39a7ff09cc8fd5eaWinson
233062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        /**
234062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung         * Notifies when a task has been removed from the history.
235062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung         */
2368aa9959413a06c3d2ff75e0c7be9e3cb7ac7cd2eWinson        void onHistoryTaskRemoved(TaskStack stack, Task removedTask, TaskViewAnimation animation);
23704dfe0d26b944324ee920001f40d74cff47281d6Winson Chung    }
23804dfe0d26b944324ee920001f40d74cff47281d6Winson Chung
239250608a5cd08862f4752a924d51710805850db8aWinson    /**
240250608a5cd08862f4752a924d51710805850db8aWinson     * The various possible dock states when dragging and dropping a task.
241250608a5cd08862f4752a924d51710805850db8aWinson     */
242f0d1c44a59a10707baa0cca8dd377302260710c1Winson    public static class DockState implements DropTarget {
243f0d1c44a59a10707baa0cca8dd377302260710c1Winson
244f0d1c44a59a10707baa0cca8dd377302260710c1Winson        private static final int DOCK_AREA_ALPHA = 192;
2453e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson        public static final DockState NONE = new DockState(DOCKED_INVALID, -1, 80, null, null, null);
2463e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson        public static final DockState LEFT = new DockState(DOCKED_LEFT,
247f0d1c44a59a10707baa0cca8dd377302260710c1Winson                DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, DOCK_AREA_ALPHA,
2483e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                new RectF(0, 0, 0.125f, 1), new RectF(0, 0, 0.125f, 1),
2493e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                new RectF(0, 0, 0.5f, 1));
2503e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson        public static final DockState TOP = new DockState(DOCKED_TOP,
251f0d1c44a59a10707baa0cca8dd377302260710c1Winson                DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT, DOCK_AREA_ALPHA,
2523e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                new RectF(0, 0, 1, 0.125f), new RectF(0, 0, 1, 0.125f),
2533e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                new RectF(0, 0, 1, 0.5f));
2543e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson        public static final DockState RIGHT = new DockState(DOCKED_RIGHT,
255f0d1c44a59a10707baa0cca8dd377302260710c1Winson                DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT, DOCK_AREA_ALPHA,
2563e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                new RectF(0.875f, 0, 1, 1), new RectF(0.875f, 0, 1, 1),
2573e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                new RectF(0.5f, 0, 1, 1));
2583e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson        public static final DockState BOTTOM = new DockState(DOCKED_BOTTOM,
259f0d1c44a59a10707baa0cca8dd377302260710c1Winson                DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT, DOCK_AREA_ALPHA,
2603e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                new RectF(0, 0.875f, 1, 1), new RectF(0, 0.875f, 1, 1),
2613e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                new RectF(0, 0.5f, 1, 1));
262eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson
263eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson        @Override
2643e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson        public boolean acceptsDrop(int x, int y, int width, int height, boolean isCurrentTarget) {
2653e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson            return isCurrentTarget
2663e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                    ? areaContainsPoint(expandedTouchDockArea, width, height, x, y)
2673e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                    : areaContainsPoint(touchArea, width, height, x, y);
268eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson        }
269be7607af8875236b9cf7bdb5f5aa089c207529afWinson
270882072baacaee4ecd43f0209b691a9af746462f2Winson        // Represents the view state of this dock state
271882072baacaee4ecd43f0209b691a9af746462f2Winson        public class ViewState {
272882072baacaee4ecd43f0209b691a9af746462f2Winson            public final int dockAreaAlpha;
273882072baacaee4ecd43f0209b691a9af746462f2Winson            public final ColorDrawable dockAreaOverlay;
2743e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson            private AnimatorSet dockAreaOverlayAnimator;
275882072baacaee4ecd43f0209b691a9af746462f2Winson
276882072baacaee4ecd43f0209b691a9af746462f2Winson            private ViewState(int alpha) {
277882072baacaee4ecd43f0209b691a9af746462f2Winson                dockAreaAlpha = alpha;
278882072baacaee4ecd43f0209b691a9af746462f2Winson                dockAreaOverlay = new ColorDrawable(0xFFffffff);
279882072baacaee4ecd43f0209b691a9af746462f2Winson                dockAreaOverlay.setAlpha(0);
280882072baacaee4ecd43f0209b691a9af746462f2Winson            }
281882072baacaee4ecd43f0209b691a9af746462f2Winson
282882072baacaee4ecd43f0209b691a9af746462f2Winson            /**
2833e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson             * Creates a new bounds and alpha animation.
284882072baacaee4ecd43f0209b691a9af746462f2Winson             */
2853e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson            public void startAnimation(Rect bounds, int alpha, int duration,
2863e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                    Interpolator interpolator, boolean animateAlpha, boolean animateBounds) {
2873e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                if (dockAreaOverlayAnimator != null) {
2883e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                    dockAreaOverlayAnimator.cancel();
2893e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                }
2903e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson
2913e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                ArrayList<Animator> animators = new ArrayList<>();
292882072baacaee4ecd43f0209b691a9af746462f2Winson                if (dockAreaOverlay.getAlpha() != alpha) {
2933e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                    if (animateAlpha) {
2943e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                        animators.add(ObjectAnimator.ofInt(dockAreaOverlay,
2953e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                                Utilities.DRAWABLE_ALPHA, dockAreaOverlay.getAlpha(), alpha));
2963e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                    } else {
2973e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                        dockAreaOverlay.setAlpha(alpha);
2983e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                    }
2993e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                }
3003e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                if (bounds != null && !dockAreaOverlay.getBounds().equals(bounds)) {
3013e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                    if (animateBounds) {
3023e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                        PropertyValuesHolder prop = PropertyValuesHolder.ofObject(
3033e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                                Utilities.DRAWABLE_RECT, new RectEvaluator(new Rect()),
3043e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                                dockAreaOverlay.getBounds(), bounds);
3053e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                        animators.add(ObjectAnimator.ofPropertyValuesHolder(dockAreaOverlay, prop));
3063e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                    } else {
3073e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                        dockAreaOverlay.setBounds(bounds);
308882072baacaee4ecd43f0209b691a9af746462f2Winson                    }
3093e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                }
3103e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                if (!animators.isEmpty()) {
3113e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                    dockAreaOverlayAnimator = new AnimatorSet();
3123e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                    dockAreaOverlayAnimator.playTogether(animators);
313882072baacaee4ecd43f0209b691a9af746462f2Winson                    dockAreaOverlayAnimator.setDuration(duration);
3143e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                    dockAreaOverlayAnimator.setInterpolator(interpolator);
315882072baacaee4ecd43f0209b691a9af746462f2Winson                    dockAreaOverlayAnimator.start();
316882072baacaee4ecd43f0209b691a9af746462f2Winson                }
317882072baacaee4ecd43f0209b691a9af746462f2Winson            }
318882072baacaee4ecd43f0209b691a9af746462f2Winson        }
319882072baacaee4ecd43f0209b691a9af746462f2Winson
3203e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson        public final int dockSide;
321be7607af8875236b9cf7bdb5f5aa089c207529afWinson        public final int createMode;
322882072baacaee4ecd43f0209b691a9af746462f2Winson        public final ViewState viewState;
323882072baacaee4ecd43f0209b691a9af746462f2Winson        private final RectF touchArea;
3243e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson        private final RectF dockArea;
3253e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson        private final RectF expandedTouchDockArea;
326be7607af8875236b9cf7bdb5f5aa089c207529afWinson
327be7607af8875236b9cf7bdb5f5aa089c207529afWinson        /**
328be7607af8875236b9cf7bdb5f5aa089c207529afWinson         * @param createMode used to pass to ActivityManager to dock the task
329be7607af8875236b9cf7bdb5f5aa089c207529afWinson         * @param touchArea the area in which touch will initiate this dock state
330eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson         * @param dockArea the visible dock area
3313e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson         * @param expandedTouchDockArea the areain which touch will continue to dock after entering
3323e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson         *                              the initial touch area.  This is also the new dock area to
3333e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson         *                              draw.
334be7607af8875236b9cf7bdb5f5aa089c207529afWinson         */
3353e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson        DockState(int dockSide, int createMode, int dockAreaAlpha, RectF touchArea, RectF dockArea,
3363e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                  RectF expandedTouchDockArea) {
3373e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson            this.dockSide = dockSide;
338be7607af8875236b9cf7bdb5f5aa089c207529afWinson            this.createMode = createMode;
339882072baacaee4ecd43f0209b691a9af746462f2Winson            this.viewState = new ViewState(dockAreaAlpha);
340be7607af8875236b9cf7bdb5f5aa089c207529afWinson            this.dockArea = dockArea;
341882072baacaee4ecd43f0209b691a9af746462f2Winson            this.touchArea = touchArea;
3423e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson            this.expandedTouchDockArea = expandedTouchDockArea;
343be7607af8875236b9cf7bdb5f5aa089c207529afWinson        }
344be7607af8875236b9cf7bdb5f5aa089c207529afWinson
345be7607af8875236b9cf7bdb5f5aa089c207529afWinson        /**
3463e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson         * Returns whether {@param x} and {@param y} are contained in the area scaled to the
347be7607af8875236b9cf7bdb5f5aa089c207529afWinson         * given {@param width} and {@param height}.
348be7607af8875236b9cf7bdb5f5aa089c207529afWinson         */
3493e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson        public boolean areaContainsPoint(RectF area, int width, int height, float x, float y) {
3503e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson            int left = (int) (area.left * width);
3513e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson            int top = (int) (area.top * height);
3523e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson            int right = (int) (area.right * width);
3533e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson            int bottom = (int) (area.bottom * height);
354be7607af8875236b9cf7bdb5f5aa089c207529afWinson            return x >= left && y >= top && x <= right && y <= bottom;
355be7607af8875236b9cf7bdb5f5aa089c207529afWinson        }
356be7607af8875236b9cf7bdb5f5aa089c207529afWinson
357be7607af8875236b9cf7bdb5f5aa089c207529afWinson        /**
358be7607af8875236b9cf7bdb5f5aa089c207529afWinson         * Returns the docked task bounds with the given {@param width} and {@param height}.
359be7607af8875236b9cf7bdb5f5aa089c207529afWinson         */
3603e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson        public Rect getPreDockedBounds(int width, int height) {
361be7607af8875236b9cf7bdb5f5aa089c207529afWinson            return new Rect((int) (dockArea.left * width), (int) (dockArea.top * height),
362be7607af8875236b9cf7bdb5f5aa089c207529afWinson                    (int) (dockArea.right * width), (int) (dockArea.bottom * height));
363be7607af8875236b9cf7bdb5f5aa089c207529afWinson        }
3643e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson
3653e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson        /**
3663e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson         * Returns the expanded docked task bounds with the given {@param width} and
3673e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson         * {@param height}.
3683e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson         */
3693e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson        public Rect getDockedBounds(int width, int height, int dividerSize, Rect insets,
3703e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                Resources res) {
3713e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson            // Calculate the docked task bounds
3723e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson            boolean isHorizontalDivision =
3733e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                    res.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
3743e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson            int position = DockedDividerUtils.calculateMiddlePosition(isHorizontalDivision,
3753e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                    insets, width, height, dividerSize);
3763e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson            Rect newWindowBounds = new Rect();
3773e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson            DockedDividerUtils.calculateBoundsForPosition(position, dockSide, newWindowBounds,
3783e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                    width, height, dividerSize);
3793e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson            return newWindowBounds;
3803e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson        }
3813e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson
3823e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson        /**
3833e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson         * Returns the task stack bounds with the given {@param width} and
3843e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson         * {@param height}.
3853e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson         */
3863e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson        public Rect getDockedTaskStackBounds(int width, int height, int dividerSize, Rect insets,
3873e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                Resources res) {
3883e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson            RecentsConfiguration config = Recents.getConfiguration();
3893e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson
3903e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson            // Calculate the inverse docked task bounds
3913e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson            boolean isHorizontalDivision =
3923e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                    res.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
3933e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson            int position = DockedDividerUtils.calculateMiddlePosition(isHorizontalDivision,
3943e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                    insets, width, height, dividerSize);
3953e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson            Rect newWindowBounds = new Rect();
3963e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson            DockedDividerUtils.calculateBoundsForPosition(position,
3973e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                    DockedDividerUtils.invertDockSide(dockSide), newWindowBounds, width, height,
3983e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                    dividerSize);
3993e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson
4003e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson            // Calculate the task stack bounds from the new window bounds
4013e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson            Rect searchBarSpaceBounds = new Rect();
4023e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson            Rect taskStackBounds = new Rect();
403d952961977a0eb6c1fefcb0707d1c61741515f68Winson            // If the task stack bounds is specifically under the dock area, then ignore the top
404d952961977a0eb6c1fefcb0707d1c61741515f68Winson            // inset
405d952961977a0eb6c1fefcb0707d1c61741515f68Winson            int top = dockArea.bottom < 1f
406d952961977a0eb6c1fefcb0707d1c61741515f68Winson                    ? 0
407d952961977a0eb6c1fefcb0707d1c61741515f68Winson                    : insets.top;
408d952961977a0eb6c1fefcb0707d1c61741515f68Winson            config.getTaskStackBounds(newWindowBounds, top, insets.right,
4093e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson                    searchBarSpaceBounds, taskStackBounds);
4103e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson            return taskStackBounds;
4113e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson        }
412be7607af8875236b9cf7bdb5f5aa089c207529afWinson    }
413be7607af8875236b9cf7bdb5f5aa089c207529afWinson
414250608a5cd08862f4752a924d51710805850db8aWinson    // A comparator that sorts tasks by their last active time
415250608a5cd08862f4752a924d51710805850db8aWinson    private Comparator<Task> LAST_ACTIVE_TIME_COMPARATOR = new Comparator<Task>() {
416250608a5cd08862f4752a924d51710805850db8aWinson        @Override
417250608a5cd08862f4752a924d51710805850db8aWinson        public int compare(Task o1, Task o2) {
418250608a5cd08862f4752a924d51710805850db8aWinson            return Long.compare(o1.key.lastActiveTime, o2.key.lastActiveTime);
419250608a5cd08862f4752a924d51710805850db8aWinson        }
420250608a5cd08862f4752a924d51710805850db8aWinson    };
421250608a5cd08862f4752a924d51710805850db8aWinson
422509d0d0c9e2ee165d04e898fea59f8941ac7138dWinson Chung    // A comparator that sorts tasks by their last active time and freeform state
423509d0d0c9e2ee165d04e898fea59f8941ac7138dWinson Chung    private Comparator<Task> FREEFORM_LAST_ACTIVE_TIME_COMPARATOR = new Comparator<Task>() {
424509d0d0c9e2ee165d04e898fea59f8941ac7138dWinson Chung        @Override
425509d0d0c9e2ee165d04e898fea59f8941ac7138dWinson Chung        public int compare(Task o1, Task o2) {
426509d0d0c9e2ee165d04e898fea59f8941ac7138dWinson Chung            if (o1.isFreeformTask() && !o2.isFreeformTask()) {
427509d0d0c9e2ee165d04e898fea59f8941ac7138dWinson Chung                return 1;
428509d0d0c9e2ee165d04e898fea59f8941ac7138dWinson Chung            } else if (o2.isFreeformTask() && !o1.isFreeformTask()) {
429509d0d0c9e2ee165d04e898fea59f8941ac7138dWinson Chung                return -1;
430509d0d0c9e2ee165d04e898fea59f8941ac7138dWinson Chung            }
431509d0d0c9e2ee165d04e898fea59f8941ac7138dWinson Chung            return Long.compare(o1.key.lastActiveTime, o2.key.lastActiveTime);
432509d0d0c9e2ee165d04e898fea59f8941ac7138dWinson Chung        }
433509d0d0c9e2ee165d04e898fea59f8941ac7138dWinson Chung    };
434509d0d0c9e2ee165d04e898fea59f8941ac7138dWinson Chung
435509d0d0c9e2ee165d04e898fea59f8941ac7138dWinson Chung
436083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung    // The task offset to apply to a task id as a group affiliation
437083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung    static final int IndividualTaskIdOffset = 1 << 16;
438083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung
439062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung    ArrayList<Task> mRawTaskList = new ArrayList<>();
440250608a5cd08862f4752a924d51710805850db8aWinson    FilteredTaskList mStackTaskList = new FilteredTaskList();
441250608a5cd08862f4752a924d51710805850db8aWinson    FilteredTaskList mHistoryTaskList = new FilteredTaskList();
442303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    TaskStackCallbacks mCb;
443303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
4448f0e3a68cdd3b2403ff8a1677f90b998f4175f40Winson    ArrayList<TaskGrouping> mGroups = new ArrayList<>();
4455500390a006f2bbea565068234774a36cea076c0Winson    ArrayMap<Integer, TaskGrouping> mAffinitiesGroups = new ArrayMap<>();
4468f0e3a68cdd3b2403ff8a1677f90b998f4175f40Winson
4478f0e3a68cdd3b2403ff8a1677f90b998f4175f40Winson    public TaskStack() {
4488f0e3a68cdd3b2403ff8a1677f90b998f4175f40Winson        // Ensure that we only show non-docked tasks
449250608a5cd08862f4752a924d51710805850db8aWinson        mStackTaskList.setFilter(new TaskFilter() {
4508f0e3a68cdd3b2403ff8a1677f90b998f4175f40Winson            @Override
4512b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung            public boolean acceptTask(SparseArray<Task> taskIdMap, Task t, int index) {
4522b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung                if (t.isAffiliatedTask()) {
4530583d3d18812d31d50228a6f29cb15b3219c9e94Winson Chung                    // If this task is affiliated with another parent in the stack, then the
4540583d3d18812d31d50228a6f29cb15b3219c9e94Winson Chung                    // historical state of this task depends on the state of the parent task
455296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung                    Task parentTask = taskIdMap.get(t.affiliationTaskId);
4562b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung                    if (parentTask != null) {
4572b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung                        t = parentTask;
4582b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung                    }
4592b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung                }
4600583d3d18812d31d50228a6f29cb15b3219c9e94Winson Chung                return !t.isHistorical;
461250608a5cd08862f4752a924d51710805850db8aWinson            }
462250608a5cd08862f4752a924d51710805850db8aWinson        });
463250608a5cd08862f4752a924d51710805850db8aWinson        mHistoryTaskList.setFilter(new TaskFilter() {
464250608a5cd08862f4752a924d51710805850db8aWinson            @Override
4652b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung            public boolean acceptTask(SparseArray<Task> taskIdMap, Task t, int index) {
4662b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung                if (t.isAffiliatedTask()) {
4670583d3d18812d31d50228a6f29cb15b3219c9e94Winson Chung                    // If this task is affiliated with another parent in the stack, then the
4680583d3d18812d31d50228a6f29cb15b3219c9e94Winson Chung                    // historical state of this task depends on the state of the parent task
469296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung                    Task parentTask = taskIdMap.get(t.affiliationTaskId);
4702b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung                    if (parentTask != null) {
4712b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung                        t = parentTask;
4722b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung                    }
4732b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung                }
4740583d3d18812d31d50228a6f29cb15b3219c9e94Winson Chung                return t.isHistorical;
4758f0e3a68cdd3b2403ff8a1677f90b998f4175f40Winson            }
4768f0e3a68cdd3b2403ff8a1677f90b998f4175f40Winson        });
4778f0e3a68cdd3b2403ff8a1677f90b998f4175f40Winson    }
478303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
479d16c565a607de754379fe699a4def21bd0e3de2fWinson Chung    /** Sets the callbacks for this task stack. */
480303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    public void setCallbacks(TaskStackCallbacks cb) {
481303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        mCb = cb;
482303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
483303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
484bc571a980704dc767838935e83c6aed231c406e9Winson Chung    /** Resets this TaskStack. */
485bc571a980704dc767838935e83c6aed231c406e9Winson Chung    public void reset() {
486bc571a980704dc767838935e83c6aed231c406e9Winson Chung        mCb = null;
487250608a5cd08862f4752a924d51710805850db8aWinson        mStackTaskList.reset();
488250608a5cd08862f4752a924d51710805850db8aWinson        mHistoryTaskList.reset();
489bc571a980704dc767838935e83c6aed231c406e9Winson Chung        mGroups.clear();
490bc571a980704dc767838935e83c6aed231c406e9Winson Chung        mAffinitiesGroups.clear();
491bc571a980704dc767838935e83c6aed231c406e9Winson Chung    }
492bc571a980704dc767838935e83c6aed231c406e9Winson Chung
493eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson    /**
494eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson     * Moves the given task to either the front of the freeform workspace or the stack.
495eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson     */
496eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson    public void moveTaskToStack(Task task, int newStackId) {
497eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson        // Find the index to insert into
498250608a5cd08862f4752a924d51710805850db8aWinson        ArrayList<Task> taskList = mStackTaskList.getTasks();
499eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson        int taskCount = taskList.size();
500eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson        if (!task.isFreeformTask() && (newStackId == FREEFORM_WORKSPACE_STACK_ID)) {
501eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson            // Insert freeform tasks at the front
502250608a5cd08862f4752a924d51710805850db8aWinson            mStackTaskList.moveTaskToStack(task, taskCount, newStackId);
503eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson        } else if (task.isFreeformTask() && (newStackId == FULLSCREEN_WORKSPACE_STACK_ID)) {
504eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson            // Insert after the first stacked task
505eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson            int insertIndex = 0;
506eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson            for (int i = taskCount - 1; i >= 0; i--) {
507eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson                if (!taskList.get(i).isFreeformTask()) {
508eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson                    insertIndex = i + 1;
509eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson                    break;
510eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson                }
511eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson            }
512250608a5cd08862f4752a924d51710805850db8aWinson            mStackTaskList.moveTaskToStack(task, insertIndex, newStackId);
513eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson        }
514eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson    }
515eca4ab6e99bcb2a7b31b8b4b1c3b5474297b6b25Winson
5166ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung    /** Does the actual work associated with removing the task. */
517250608a5cd08862f4752a924d51710805850db8aWinson    void removeTaskImpl(FilteredTaskList taskList, Task t) {
5186ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung        // Remove the task from the list
519250608a5cd08862f4752a924d51710805850db8aWinson        taskList.remove(t);
5206ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung        // Remove it from the group as well, and if it is empty, remove the group
5216ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung        TaskGrouping group = t.group;
5224e5fb2f4e1ed4eb119a201541ad89aafac8c53feWinson Chung        if (group != null) {
5234e5fb2f4e1ed4eb119a201541ad89aafac8c53feWinson Chung            group.removeTask(t);
5244e5fb2f4e1ed4eb119a201541ad89aafac8c53feWinson Chung            if (group.getTaskCount() == 0) {
5254e5fb2f4e1ed4eb119a201541ad89aafac8c53feWinson Chung                removeGroup(group);
5264e5fb2f4e1ed4eb119a201541ad89aafac8c53feWinson Chung            }
5276ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung        }
5286ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung    }
5296ac8bd6198f67b64aea2258bdb5f8ed371b5bec1Winson Chung
5308aa9959413a06c3d2ff75e0c7be9e3cb7ac7cd2eWinson    /**
5318aa9959413a06c3d2ff75e0c7be9e3cb7ac7cd2eWinson     * Removes a task from the stack, with an additional {@param animation} hint to the callbacks on
5328aa9959413a06c3d2ff75e0c7be9e3cb7ac7cd2eWinson     * how they should update themselves.
5338aa9959413a06c3d2ff75e0c7be9e3cb7ac7cd2eWinson     */
5348aa9959413a06c3d2ff75e0c7be9e3cb7ac7cd2eWinson    public void removeTask(Task t, TaskViewAnimation animation) {
535250608a5cd08862f4752a924d51710805850db8aWinson        if (mStackTaskList.contains(t)) {
53635a8b04140598a5b5c4865254b942adb6a830991Winson            boolean wasFrontMostTask = (getStackFrontMostTask(false /* includeFreeform */) == t);
537250608a5cd08862f4752a924d51710805850db8aWinson            removeTaskImpl(mStackTaskList, t);
53835a8b04140598a5b5c4865254b942adb6a830991Winson            Task newFrontMostTask = getStackFrontMostTask(false  /* includeFreeform */);
539303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            if (mCb != null) {
540ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                // Notify that a task has been removed
5418aa9959413a06c3d2ff75e0c7be9e3cb7ac7cd2eWinson                mCb.onStackTaskRemoved(this, t, wasFrontMostTask, newFrontMostTask, animation);
542303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            }
543250608a5cd08862f4752a924d51710805850db8aWinson        } else if (mHistoryTaskList.contains(t)) {
544250608a5cd08862f4752a924d51710805850db8aWinson            removeTaskImpl(mHistoryTaskList, t);
545303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            if (mCb != null) {
546ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                // Notify that a task has been removed
5478aa9959413a06c3d2ff75e0c7be9e3cb7ac7cd2eWinson                mCb.onHistoryTaskRemoved(this, t, animation);
548303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            }
549303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        }
5503e8747414520ee348cf4b9c4a6afd9ff80b5a8f8Winson        mRawTaskList.remove(t);
551250608a5cd08862f4752a924d51710805850db8aWinson    }
552250608a5cd08862f4752a924d51710805850db8aWinson
553250608a5cd08862f4752a924d51710805850db8aWinson    /**
554250608a5cd08862f4752a924d51710805850db8aWinson     * Sets a few tasks in one go, without calling any callbacks.
555062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung     *
556062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung     * @param tasks the new set of tasks to replace the current set.
557062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung     * @param notifyStackChanges whether or not to callback on specific changes to the list of tasks.
558250608a5cd08862f4752a924d51710805850db8aWinson     */
559062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung    public void setTasks(List<Task> tasks, boolean notifyStackChanges) {
560062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        // Compute a has set for each of the tasks
5615500390a006f2bbea565068234774a36cea076c0Winson        ArrayMap<Task.TaskKey, Task> currentTasksMap = createTaskKeyMapFromList(mRawTaskList);
5625500390a006f2bbea565068234774a36cea076c0Winson        ArrayMap<Task.TaskKey, Task> newTasksMap = createTaskKeyMapFromList(tasks);
563062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung
564062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        ArrayList<Task> newTasks = new ArrayList<>();
565062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung
566062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        // Disable notifications if there are no callbacks
567062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        if (mCb == null) {
568062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung            notifyStackChanges = false;
569062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        }
570062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung
571062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        // Remove any tasks that no longer exist
572062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        int taskCount = mRawTaskList.size();
573062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        for (int i = 0; i < taskCount; i++) {
574062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung            Task task = mRawTaskList.get(i);
575062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung            if (!newTasksMap.containsKey(task.key)) {
576062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung                if (notifyStackChanges) {
5778aa9959413a06c3d2ff75e0c7be9e3cb7ac7cd2eWinson                    mCb.onStackTaskRemoved(this, task, i == (taskCount - 1), null,
5788aa9959413a06c3d2ff75e0c7be9e3cb7ac7cd2eWinson                            TaskViewAnimation.IMMEDIATE);
579062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung                }
580062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung            }
5819756755db76aeda2065322aa3c26e1a19578d45fWinson Chung            task.setGroup(null);
582062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        }
583062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung
584062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        // Add any new tasks
585062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        taskCount = tasks.size();
586062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        for (int i = 0; i < taskCount; i++) {
587062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung            Task task = tasks.get(i);
588062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung            if (!currentTasksMap.containsKey(task.key)) {
589062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung                if (notifyStackChanges) {
590062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung                    mCb.onStackTaskAdded(this, task);
591062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung                }
592062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung                newTasks.add(task);
593062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung            } else {
594062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung                newTasks.add(currentTasksMap.get(task.key));
595062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung            }
596062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        }
597062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung
598062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        // Sort all the tasks to ensure they are ordered correctly
599509d0d0c9e2ee165d04e898fea59f8941ac7138dWinson Chung        Collections.sort(newTasks, FREEFORM_LAST_ACTIVE_TIME_COMPARATOR);
600062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung
601062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        // Filter out the historical tasks from this new list
602250608a5cd08862f4752a924d51710805850db8aWinson        ArrayList<Task> stackTasks = new ArrayList<>();
603250608a5cd08862f4752a924d51710805850db8aWinson        ArrayList<Task> historyTasks = new ArrayList<>();
604062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        int newTaskCount = newTasks.size();
605062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        for (int i = 0; i < newTaskCount; i++) {
606062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung            Task task = newTasks.get(i);
607250608a5cd08862f4752a924d51710805850db8aWinson            if (task.isHistorical) {
608250608a5cd08862f4752a924d51710805850db8aWinson                historyTasks.add(task);
609250608a5cd08862f4752a924d51710805850db8aWinson            } else {
610250608a5cd08862f4752a924d51710805850db8aWinson                stackTasks.add(task);
611303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            }
612303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        }
613062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung
614250608a5cd08862f4752a924d51710805850db8aWinson        mStackTaskList.set(stackTasks);
615250608a5cd08862f4752a924d51710805850db8aWinson        mHistoryTaskList.set(historyTasks);
616062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        mRawTaskList.clear();
617062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        mRawTaskList.addAll(newTasks);
6189756755db76aeda2065322aa3c26e1a19578d45fWinson Chung        mGroups.clear();
6199756755db76aeda2065322aa3c26e1a19578d45fWinson Chung        mAffinitiesGroups.clear();
620303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
621303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
622931c51f54599a227422b2a1c71e922e1458e0291Winson Chung    /**
623931c51f54599a227422b2a1c71e922e1458e0291Winson Chung     * Gets the front-most task in the stack.
624931c51f54599a227422b2a1c71e922e1458e0291Winson Chung     */
62535a8b04140598a5b5c4865254b942adb6a830991Winson    public Task getStackFrontMostTask(boolean includeFreeformTasks) {
626931c51f54599a227422b2a1c71e922e1458e0291Winson Chung        ArrayList<Task> stackTasks = mStackTaskList.getTasks();
627931c51f54599a227422b2a1c71e922e1458e0291Winson Chung        if (stackTasks.isEmpty()) {
628931c51f54599a227422b2a1c71e922e1458e0291Winson Chung            return null;
629931c51f54599a227422b2a1c71e922e1458e0291Winson Chung        }
630931c51f54599a227422b2a1c71e922e1458e0291Winson Chung        for (int i = stackTasks.size() - 1; i >= 0; i--) {
631931c51f54599a227422b2a1c71e922e1458e0291Winson Chung            Task task = stackTasks.get(i);
63235a8b04140598a5b5c4865254b942adb6a830991Winson            if (!task.isFreeformTask() || includeFreeformTasks) {
633931c51f54599a227422b2a1c71e922e1458e0291Winson Chung                return task;
634931c51f54599a227422b2a1c71e922e1458e0291Winson Chung            }
635931c51f54599a227422b2a1c71e922e1458e0291Winson Chung        }
636931c51f54599a227422b2a1c71e922e1458e0291Winson Chung        return null;
637ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    }
638ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
63904400672962d2e12132f9465928cbf7615c147c4Winson Chung    /** Gets the task keys */
64004400672962d2e12132f9465928cbf7615c147c4Winson Chung    public ArrayList<Task.TaskKey> getTaskKeys() {
6418f0e3a68cdd3b2403ff8a1677f90b998f4175f40Winson        ArrayList<Task.TaskKey> taskKeys = new ArrayList<>();
642250608a5cd08862f4752a924d51710805850db8aWinson        ArrayList<Task> tasks = computeAllTasksList();
64304400672962d2e12132f9465928cbf7615c147c4Winson Chung        int taskCount = tasks.size();
64404400672962d2e12132f9465928cbf7615c147c4Winson Chung        for (int i = 0; i < taskCount; i++) {
645250608a5cd08862f4752a924d51710805850db8aWinson            Task task = tasks.get(i);
646250608a5cd08862f4752a924d51710805850db8aWinson            taskKeys.add(task.key);
64704400672962d2e12132f9465928cbf7615c147c4Winson Chung        }
64804400672962d2e12132f9465928cbf7615c147c4Winson Chung        return taskKeys;
64904400672962d2e12132f9465928cbf7615c147c4Winson Chung    }
65004400672962d2e12132f9465928cbf7615c147c4Winson Chung
651250608a5cd08862f4752a924d51710805850db8aWinson    /**
652250608a5cd08862f4752a924d51710805850db8aWinson     * Returns the set of "active" (non-historical) tasks in the stack that have been used recently.
653250608a5cd08862f4752a924d51710805850db8aWinson     */
654250608a5cd08862f4752a924d51710805850db8aWinson    public ArrayList<Task> getStackTasks() {
655250608a5cd08862f4752a924d51710805850db8aWinson        return mStackTaskList.getTasks();
656250608a5cd08862f4752a924d51710805850db8aWinson    }
657250608a5cd08862f4752a924d51710805850db8aWinson
658250608a5cd08862f4752a924d51710805850db8aWinson    /**
659250608a5cd08862f4752a924d51710805850db8aWinson     * Returns the set of tasks that are inactive. These tasks will be presented in a separate
660250608a5cd08862f4752a924d51710805850db8aWinson     * history view.
661250608a5cd08862f4752a924d51710805850db8aWinson     */
662250608a5cd08862f4752a924d51710805850db8aWinson    public ArrayList<Task> getHistoricalTasks() {
663250608a5cd08862f4752a924d51710805850db8aWinson        return mHistoryTaskList.getTasks();
664303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
665303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
666250608a5cd08862f4752a924d51710805850db8aWinson    /**
667f24f21695f5609d06402cf61e3500d408b99bdcbWinson     * Returns the set of "freeform" tasks in the stack.
668f24f21695f5609d06402cf61e3500d408b99bdcbWinson     */
669f24f21695f5609d06402cf61e3500d408b99bdcbWinson    public ArrayList<Task> getFreeformTasks() {
670f24f21695f5609d06402cf61e3500d408b99bdcbWinson        ArrayList<Task> freeformTasks = new ArrayList<>();
671f24f21695f5609d06402cf61e3500d408b99bdcbWinson        ArrayList<Task> tasks = mStackTaskList.getTasks();
672f24f21695f5609d06402cf61e3500d408b99bdcbWinson        int taskCount = tasks.size();
673f24f21695f5609d06402cf61e3500d408b99bdcbWinson        for (int i = 0; i < taskCount; i++) {
674f24f21695f5609d06402cf61e3500d408b99bdcbWinson            Task task = tasks.get(i);
675f24f21695f5609d06402cf61e3500d408b99bdcbWinson            if (task.isFreeformTask()) {
676f24f21695f5609d06402cf61e3500d408b99bdcbWinson                freeformTasks.add(task);
677f24f21695f5609d06402cf61e3500d408b99bdcbWinson            }
678f24f21695f5609d06402cf61e3500d408b99bdcbWinson        }
679f24f21695f5609d06402cf61e3500d408b99bdcbWinson        return freeformTasks;
680f24f21695f5609d06402cf61e3500d408b99bdcbWinson    }
681f24f21695f5609d06402cf61e3500d408b99bdcbWinson
682f24f21695f5609d06402cf61e3500d408b99bdcbWinson    /**
683250608a5cd08862f4752a924d51710805850db8aWinson     * Computes a set of all the active and historical tasks ordered by their last active time.
684250608a5cd08862f4752a924d51710805850db8aWinson     */
685250608a5cd08862f4752a924d51710805850db8aWinson    public ArrayList<Task> computeAllTasksList() {
686250608a5cd08862f4752a924d51710805850db8aWinson        ArrayList<Task> tasks = new ArrayList<>();
687250608a5cd08862f4752a924d51710805850db8aWinson        tasks.addAll(mStackTaskList.getTasks());
688250608a5cd08862f4752a924d51710805850db8aWinson        tasks.addAll(mHistoryTaskList.getTasks());
689250608a5cd08862f4752a924d51710805850db8aWinson        Collections.sort(tasks, LAST_ACTIVE_TIME_COMPARATOR);
690250608a5cd08862f4752a924d51710805850db8aWinson        return tasks;
691303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
692303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
69336a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson    /**
6944b057c6787624b75613769a857ccdf51114bb7f2Winson     * Returns the number of stack and freeform tasks.
695250608a5cd08862f4752a924d51710805850db8aWinson     */
6964b057c6787624b75613769a857ccdf51114bb7f2Winson    public int getTaskCount() {
697250608a5cd08862f4752a924d51710805850db8aWinson        return mStackTaskList.size();
698250608a5cd08862f4752a924d51710805850db8aWinson    }
699250608a5cd08862f4752a924d51710805850db8aWinson
700250608a5cd08862f4752a924d51710805850db8aWinson    /**
7014b057c6787624b75613769a857ccdf51114bb7f2Winson     * Returns the number of stack tasks.
7024b057c6787624b75613769a857ccdf51114bb7f2Winson     */
7034b057c6787624b75613769a857ccdf51114bb7f2Winson    public int getStackTaskCount() {
7044b057c6787624b75613769a857ccdf51114bb7f2Winson        ArrayList<Task> tasks = mStackTaskList.getTasks();
7054b057c6787624b75613769a857ccdf51114bb7f2Winson        int stackCount = 0;
7064b057c6787624b75613769a857ccdf51114bb7f2Winson        int taskCount = tasks.size();
7074b057c6787624b75613769a857ccdf51114bb7f2Winson        for (int i = 0; i < taskCount; i++) {
7084b057c6787624b75613769a857ccdf51114bb7f2Winson            Task task = tasks.get(i);
7094b057c6787624b75613769a857ccdf51114bb7f2Winson            if (!task.isFreeformTask()) {
7104b057c6787624b75613769a857ccdf51114bb7f2Winson                stackCount++;
7114b057c6787624b75613769a857ccdf51114bb7f2Winson            }
7124b057c6787624b75613769a857ccdf51114bb7f2Winson        }
7134b057c6787624b75613769a857ccdf51114bb7f2Winson        return stackCount;
7144b057c6787624b75613769a857ccdf51114bb7f2Winson    }
7154b057c6787624b75613769a857ccdf51114bb7f2Winson
7164b057c6787624b75613769a857ccdf51114bb7f2Winson    /**
7174b057c6787624b75613769a857ccdf51114bb7f2Winson     * Returns the number of freeform tasks.
718f0d1c44a59a10707baa0cca8dd377302260710c1Winson     */
7194b057c6787624b75613769a857ccdf51114bb7f2Winson    public int getFreeformTaskCount() {
720f0d1c44a59a10707baa0cca8dd377302260710c1Winson        ArrayList<Task> tasks = mStackTaskList.getTasks();
721f0d1c44a59a10707baa0cca8dd377302260710c1Winson        int freeformCount = 0;
722f0d1c44a59a10707baa0cca8dd377302260710c1Winson        int taskCount = tasks.size();
723f0d1c44a59a10707baa0cca8dd377302260710c1Winson        for (int i = 0; i < taskCount; i++) {
724f0d1c44a59a10707baa0cca8dd377302260710c1Winson            Task task = tasks.get(i);
725f0d1c44a59a10707baa0cca8dd377302260710c1Winson            if (task.isFreeformTask()) {
726f0d1c44a59a10707baa0cca8dd377302260710c1Winson                freeformCount++;
727f0d1c44a59a10707baa0cca8dd377302260710c1Winson            }
728f0d1c44a59a10707baa0cca8dd377302260710c1Winson        }
729f0d1c44a59a10707baa0cca8dd377302260710c1Winson        return freeformCount;
730f0d1c44a59a10707baa0cca8dd377302260710c1Winson    }
731f0d1c44a59a10707baa0cca8dd377302260710c1Winson
732f0d1c44a59a10707baa0cca8dd377302260710c1Winson    /**
733250608a5cd08862f4752a924d51710805850db8aWinson     * Returns the task in stack tasks which is the launch target.
73436a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson     */
73536a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson    public Task getLaunchTarget() {
736250608a5cd08862f4752a924d51710805850db8aWinson        ArrayList<Task> tasks = mStackTaskList.getTasks();
73736a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson        int taskCount = tasks.size();
73836a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson        for (int i = 0; i < taskCount; i++) {
73936a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson            Task task = tasks.get(i);
74036a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson            if (task.isLaunchTarget) {
74136a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson                return task;
74236a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson            }
74336a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson        }
74436a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson        return null;
74536a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson    }
74636a5a2c7003ef8157f276b411c3fda47ad2f75e3Winson
747303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    /** Returns the index of this task in this current task stack */
748250608a5cd08862f4752a924d51710805850db8aWinson    public int indexOfStackTask(Task t) {
749250608a5cd08862f4752a924d51710805850db8aWinson        return mStackTaskList.indexOf(t);
750303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
751303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung
752b1f749906f5c27114d02ea0c3f8ce0dcea08fd3fWinson Chung    /** Finds the task with the specified task id. */
753b1f749906f5c27114d02ea0c3f8ce0dcea08fd3fWinson Chung    public Task findTaskWithId(int taskId) {
754250608a5cd08862f4752a924d51710805850db8aWinson        ArrayList<Task> tasks = computeAllTasksList();
755250608a5cd08862f4752a924d51710805850db8aWinson        for (Task task : tasks) {
756b1f749906f5c27114d02ea0c3f8ce0dcea08fd3fWinson Chung            if (task.key.id == taskId) {
757b1f749906f5c27114d02ea0c3f8ce0dcea08fd3fWinson Chung                return task;
758b1f749906f5c27114d02ea0c3f8ce0dcea08fd3fWinson Chung            }
759b1f749906f5c27114d02ea0c3f8ce0dcea08fd3fWinson Chung        }
760b1f749906f5c27114d02ea0c3f8ce0dcea08fd3fWinson Chung        return null;
761b1f749906f5c27114d02ea0c3f8ce0dcea08fd3fWinson Chung    }
762b1f749906f5c27114d02ea0c3f8ce0dcea08fd3fWinson Chung
763ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    /******** Grouping ********/
764ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
765ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    /** Adds a group to the set */
766ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    public void addGroup(TaskGrouping group) {
767ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        mGroups.add(group);
768ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        mAffinitiesGroups.put(group.affiliation, group);
769ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    }
770ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
771ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    public void removeGroup(TaskGrouping group) {
772ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        mGroups.remove(group);
773ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        mAffinitiesGroups.remove(group.affiliation);
774ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    }
775ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
776ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    /** Returns the group with the specified affiliation. */
777083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung    public TaskGrouping getGroupWithAffiliation(int affiliation) {
778ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        return mAffinitiesGroups.get(affiliation);
779ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    }
780ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
781ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    /**
782ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung     * Temporary: This method will simulate affiliation groups by
783ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung     */
78435f3050959e43bf378f9a0adcaef13729206c7e4Winson    public void createAffiliatedGroupings(Context context) {
7856e6bd8776f850a21a3733a03dfa32b04f06163d9Winson        if (RecentsDebugFlags.Static.EnableMockTaskGroups) {
7865500390a006f2bbea565068234774a36cea076c0Winson            ArrayMap<Task.TaskKey, Task> taskMap = new ArrayMap<>();
787ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            // Sort all tasks by increasing firstActiveTime of the task
788250608a5cd08862f4752a924d51710805850db8aWinson            ArrayList<Task> tasks = mStackTaskList.getTasks();
789ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            Collections.sort(tasks, new Comparator<Task>() {
790ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                @Override
791ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                public int compare(Task task, Task task2) {
79216bc2a7f379edd7796bb5aa4400e1b7c14376a08Winson Chung                    return Long.compare(task.key.firstActiveTime, task2.key.firstActiveTime);
793ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                }
794ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            });
795ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            // Create groups when sequential packages are the same
796ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            NamedCounter counter = new NamedCounter("task-group", "");
797ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            int taskCount = tasks.size();
798ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            String prevPackage = "";
799083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung            int prevAffiliation = -1;
800a433fa9c17772f563163ff7db177d091d6aebd5bWinson Chung            Random r = new Random();
8016e6bd8776f850a21a3733a03dfa32b04f06163d9Winson            int groupCountDown = RecentsDebugFlags.Static.MockTaskGroupsTaskCount;
802ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            for (int i = 0; i < taskCount; i++) {
803ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                Task t = tasks.get(i);
804e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                String packageName = t.key.getComponent().getPackageName();
805a433fa9c17772f563163ff7db177d091d6aebd5bWinson Chung                packageName = "pkg";
806ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                TaskGrouping group;
807a433fa9c17772f563163ff7db177d091d6aebd5bWinson Chung                if (packageName.equals(prevPackage) && groupCountDown > 0) {
808ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    group = getGroupWithAffiliation(prevAffiliation);
809a433fa9c17772f563163ff7db177d091d6aebd5bWinson Chung                    groupCountDown--;
810ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                } else {
811083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung                    int affiliation = IndividualTaskIdOffset + t.key.id;
812ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    group = new TaskGrouping(affiliation);
813ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    addGroup(group);
814ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    prevAffiliation = affiliation;
815ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    prevPackage = packageName;
8166e6bd8776f850a21a3733a03dfa32b04f06163d9Winson                    groupCountDown = RecentsDebugFlags.Static.MockTaskGroupsTaskCount;
817ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                }
818ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                group.addTask(t);
819ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                taskMap.put(t.key, t);
820ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            }
821ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            // Sort groups by increasing latestActiveTime of the group
822ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            Collections.sort(mGroups, new Comparator<TaskGrouping>() {
823ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                @Override
824ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                public int compare(TaskGrouping taskGrouping, TaskGrouping taskGrouping2) {
825509d0d0c9e2ee165d04e898fea59f8941ac7138dWinson Chung                    return Long.compare(taskGrouping.latestActiveTimeInGroup,
826ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                            taskGrouping2.latestActiveTimeInGroup);
827ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                }
828ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            });
8292b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung            // Sort group tasks by increasing firstActiveTime of the task, and also build a new list
8302b9ef6548be89d36ea7629f4a3d8ba7bba1422ceWinson Chung            // of tasks
831ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            int taskIndex = 0;
832ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            int groupCount = mGroups.size();
833ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            for (int i = 0; i < groupCount; i++) {
834ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                TaskGrouping group = mGroups.get(i);
835083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung                Collections.sort(group.mTaskKeys, new Comparator<Task.TaskKey>() {
836ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    @Override
837ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    public int compare(Task.TaskKey taskKey, Task.TaskKey taskKey2) {
838509d0d0c9e2ee165d04e898fea59f8941ac7138dWinson Chung                        return Long.compare(taskKey.firstActiveTime, taskKey2.firstActiveTime);
839ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    }
840ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                });
841083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung                ArrayList<Task.TaskKey> groupTasks = group.mTaskKeys;
842ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                int groupTaskCount = groupTasks.size();
843ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                for (int j = 0; j < groupTaskCount; j++) {
844ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    tasks.set(taskIndex, taskMap.get(groupTasks.get(j)));
845ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                    taskIndex++;
846ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                }
847ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            }
848250608a5cd08862f4752a924d51710805850db8aWinson            mStackTaskList.set(tasks);
849ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        } else {
850083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung            // Create the task groups
8515500390a006f2bbea565068234774a36cea076c0Winson            ArrayMap<Task.TaskKey, Task> tasksMap = new ArrayMap<>();
852250608a5cd08862f4752a924d51710805850db8aWinson            ArrayList<Task> tasks = mStackTaskList.getTasks();
853ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            int taskCount = tasks.size();
854ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            for (int i = 0; i < taskCount; i++) {
855ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                Task t = tasks.get(i);
856083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung                TaskGrouping group;
85765c851e6e9e08656744b6f66d3da188e3283b17dWinson                if (RecentsDebugFlags.Static.EnableAffiliatedTaskGroups) {
85865c851e6e9e08656744b6f66d3da188e3283b17dWinson                    int affiliation = t.affiliationTaskId > 0 ? t.affiliationTaskId :
85965c851e6e9e08656744b6f66d3da188e3283b17dWinson                            IndividualTaskIdOffset + t.key.id;
86065c851e6e9e08656744b6f66d3da188e3283b17dWinson                    if (mAffinitiesGroups.containsKey(affiliation)) {
86165c851e6e9e08656744b6f66d3da188e3283b17dWinson                        group = getGroupWithAffiliation(affiliation);
86265c851e6e9e08656744b6f66d3da188e3283b17dWinson                    } else {
86365c851e6e9e08656744b6f66d3da188e3283b17dWinson                        group = new TaskGrouping(affiliation);
86465c851e6e9e08656744b6f66d3da188e3283b17dWinson                        addGroup(group);
86565c851e6e9e08656744b6f66d3da188e3283b17dWinson                    }
866083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung                } else {
86765c851e6e9e08656744b6f66d3da188e3283b17dWinson                    group = new TaskGrouping(t.key.id);
868083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung                    addGroup(group);
869083baf99ff1228e96ede96aac88c8200c4fdc2b2Winson Chung                }
870ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung                group.addTask(t);
871ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                tasksMap.put(t.key, t);
872ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung            }
873ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung            // Update the task colors for each of the groups
87435f3050959e43bf378f9a0adcaef13729206c7e4Winson            float minAlpha = context.getResources().getFloat(
87535f3050959e43bf378f9a0adcaef13729206c7e4Winson                    R.dimen.recents_task_affiliation_color_min_alpha_percentage);
876ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung            int taskGroupCount = mGroups.size();
877ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung            for (int i = 0; i < taskGroupCount; i++) {
878ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                TaskGrouping group = mGroups.get(i);
879ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                taskCount = group.getTaskCount();
880ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                // Ignore the groups that only have one task
881ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                if (taskCount <= 1) continue;
882ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                // Calculate the group color distribution
883296278a0679375b8c43962a9e3c9bb4e8ab201e7Winson Chung                int affiliationColor = tasksMap.get(group.mTaskKeys.get(0)).affiliationColor;
884ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                float alphaStep = (1f - minAlpha) / taskCount;
885ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                float alpha = 1f;
886ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                for (int j = 0; j < taskCount; j++) {
887ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                    Task t = tasksMap.get(group.mTaskKeys.get(j));
888a0e88b5013d708ac6ed6518817d83c64c87ae4b1Winson Chung                    t.colorPrimary = Utilities.getColorWithOverlay(affiliationColor, Color.WHITE,
889a0e88b5013d708ac6ed6518817d83c64c87ae4b1Winson Chung                            alpha);
890ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                    alpha -= alphaStep;
891ec396d6399c5c31d697d81e94aff459e9771b0c6Winson Chung                }
892ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung            }
893ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung        }
894ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung    }
895ffa2ec664479bff6b4b61d4c349d9db2cb37ca16Winson Chung
896e7f138c7f0a190c86cec10fb32fa106aacae4093Winson    /**
897e7f138c7f0a190c86cec10fb32fa106aacae4093Winson     * Computes the components of tasks in this stack that have been removed as a result of a change
898e7f138c7f0a190c86cec10fb32fa106aacae4093Winson     * in the specified package.
899e7f138c7f0a190c86cec10fb32fa106aacae4093Winson     */
9005500390a006f2bbea565068234774a36cea076c0Winson    public ArraySet<ComponentName> computeComponentsRemoved(String packageName, int userId) {
901e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        // Identify all the tasks that should be removed as a result of the package being removed.
902e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        // Using a set to ensure that we callback once per unique component.
903e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        SystemServicesProxy ssp = Recents.getSystemServices();
9045500390a006f2bbea565068234774a36cea076c0Winson        ArraySet<ComponentName> existingComponents = new ArraySet<>();
9055500390a006f2bbea565068234774a36cea076c0Winson        ArraySet<ComponentName> removedComponents = new ArraySet<>();
906e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        ArrayList<Task.TaskKey> taskKeys = getTaskKeys();
907e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        for (Task.TaskKey t : taskKeys) {
908e7f138c7f0a190c86cec10fb32fa106aacae4093Winson            // Skip if this doesn't apply to the current user
909e7f138c7f0a190c86cec10fb32fa106aacae4093Winson            if (t.userId != userId) continue;
910e7f138c7f0a190c86cec10fb32fa106aacae4093Winson
911e7f138c7f0a190c86cec10fb32fa106aacae4093Winson            ComponentName cn = t.getComponent();
912e7f138c7f0a190c86cec10fb32fa106aacae4093Winson            if (cn.getPackageName().equals(packageName)) {
913e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                if (existingComponents.contains(cn)) {
914e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                    // If we know that the component still exists in the package, then skip
915e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                    continue;
916e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                }
917e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                if (ssp.getActivityInfo(cn, userId) != null) {
918e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                    existingComponents.add(cn);
919e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                } else {
920e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                    removedComponents.add(cn);
921e7f138c7f0a190c86cec10fb32fa106aacae4093Winson                }
922e7f138c7f0a190c86cec10fb32fa106aacae4093Winson            }
923e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        }
924e7f138c7f0a190c86cec10fb32fa106aacae4093Winson        return removedComponents;
925e7f138c7f0a190c86cec10fb32fa106aacae4093Winson    }
926e7f138c7f0a190c86cec10fb32fa106aacae4093Winson
927303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    @Override
928303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    public String toString() {
929250608a5cd08862f4752a924d51710805850db8aWinson        String str = "Stack Tasks:\n";
930250608a5cd08862f4752a924d51710805850db8aWinson        for (Task t : mStackTaskList.getTasks()) {
931250608a5cd08862f4752a924d51710805850db8aWinson            str += "  " + t.toString() + "\n";
932250608a5cd08862f4752a924d51710805850db8aWinson        }
933250608a5cd08862f4752a924d51710805850db8aWinson        str += "Historical Tasks:\n";
934250608a5cd08862f4752a924d51710805850db8aWinson        for (Task t : mHistoryTaskList.getTasks()) {
935303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung            str += "  " + t.toString() + "\n";
936303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        }
937303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung        return str;
938303e1ff1fec8b240b587bb18b981247a99833aa8Winson Chung    }
939062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung
940062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung    /**
941062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung     * Given a list of tasks, returns a map of each task's key to the task.
942062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung     */
9435500390a006f2bbea565068234774a36cea076c0Winson    private ArrayMap<Task.TaskKey, Task> createTaskKeyMapFromList(List<Task> tasks) {
9445500390a006f2bbea565068234774a36cea076c0Winson        ArrayMap<Task.TaskKey, Task> map = new ArrayMap<>(tasks.size());
945062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        int taskCount = tasks.size();
946062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        for (int i = 0; i < taskCount; i++) {
947062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung            Task task = tasks.get(i);
948062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung            map.put(task.key, task);
949062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        }
950062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung        return map;
951062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung    }
952062667710edcad7a01d7ece3e2bc4a83ee2a2ca3Winson Chung}
953