blob: 356841fa89c04b6bda8de5115ef75401dae8b74a [file] [log] [blame]
Winson Chung303e1ff2014-03-07 15:06:19 -08001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.systemui.recents.views;
18
19import android.app.ActivityOptions;
Winson Chung9f9679d2014-04-11 16:49:09 -070020import android.app.TaskStackBuilder;
Winson Chungc620baf2014-03-19 17:15:29 -070021import android.content.ActivityNotFoundException;
Winson Chung9f49df92014-05-07 18:08:34 -070022import android.content.ComponentName;
Winson Chung303e1ff2014-03-07 15:06:19 -080023import android.content.Context;
24import android.content.Intent;
25import android.graphics.Bitmap;
26import android.graphics.Canvas;
27import android.graphics.Rect;
Winson Chung9f9679d2014-04-11 16:49:09 -070028import android.net.Uri;
Winson Chung9f9679d2014-04-11 16:49:09 -070029import android.provider.Settings;
Winson Chung8e548f72014-06-24 14:40:53 -070030import android.util.AttributeSet;
Winson Chungecd9b302014-04-16 17:07:18 -070031import android.view.LayoutInflater;
Winson Chung303e1ff2014-03-07 15:06:19 -080032import android.view.View;
Winson Chung653f70c22014-05-19 14:49:42 -070033import android.view.WindowInsets;
Winson Chung303e1ff2014-03-07 15:06:19 -080034import android.widget.FrameLayout;
Winson Chung303e1ff2014-03-07 15:06:19 -080035import com.android.systemui.recents.Constants;
36import com.android.systemui.recents.RecentsConfiguration;
Winson Chung1f24c7e2014-07-11 17:06:48 -070037import com.android.systemui.recents.misc.Console;
38import com.android.systemui.recents.misc.SystemServicesProxy;
Winson Chungff88d7b2014-07-17 12:30:07 -070039import com.android.systemui.recents.misc.Utilities;
Winson Chungf1fbd772014-06-24 18:06:58 -070040import com.android.systemui.recents.model.RecentsPackageMonitor;
41import com.android.systemui.recents.model.RecentsTaskLoader;
Winson Chung303e1ff2014-03-07 15:06:19 -080042import com.android.systemui.recents.model.Task;
43import com.android.systemui.recents.model.TaskStack;
44
45import java.util.ArrayList;
Winson Chung82c8c5e2014-07-14 17:31:41 -070046import java.util.HashSet;
Winson Chung303e1ff2014-03-07 15:06:19 -080047
Winson Chung303e1ff2014-03-07 15:06:19 -080048/**
49 * This view is the the top level layout that contains TaskStacks (which are laid out according
50 * to their SpaceNode bounds.
51 */
Winson Chung9f49df92014-05-07 18:08:34 -070052public class RecentsView extends FrameLayout implements TaskStackView.TaskStackViewCallbacks,
53 RecentsPackageMonitor.PackageCallbacks {
Winson Chung47c4c692014-03-17 10:17:11 -070054
55 /** The RecentsView callbacks */
56 public interface RecentsViewCallbacks {
Winson Chung7aceb9a2014-07-03 13:38:01 -070057 public void onTaskViewClicked();
58 public void onAllTaskViewsDismissed();
Winson Chungcdbbb7e2014-06-24 12:11:49 -070059 public void onExitToHomeAnimationTriggered();
Winson Chung47c4c692014-03-17 10:17:11 -070060 }
61
Winson Chungd42a6cf2014-06-03 16:24:04 -070062 RecentsConfiguration mConfig;
63 LayoutInflater mInflater;
Winson Chungdcfa7972014-07-22 12:27:13 -070064 DebugOverlayView mDebugOverlay;
Winson Chungd42a6cf2014-06-03 16:24:04 -070065
Winson Chungdcfa7972014-07-22 12:27:13 -070066 ArrayList<TaskStack> mStacks;
Winson Chungecd9b302014-04-16 17:07:18 -070067 View mSearchBar;
Winson Chung47c4c692014-03-17 10:17:11 -070068 RecentsViewCallbacks mCb;
Winson Chung303e1ff2014-03-07 15:06:19 -080069
70 public RecentsView(Context context) {
71 super(context);
Winson Chung8e548f72014-06-24 14:40:53 -070072 }
73
74 public RecentsView(Context context, AttributeSet attrs) {
75 this(context, attrs, 0);
76 }
77
78 public RecentsView(Context context, AttributeSet attrs, int defStyleAttr) {
79 this(context, attrs, defStyleAttr, 0);
80 }
81
82 public RecentsView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
83 super(context, attrs, defStyleAttr, defStyleRes);
Winson Chungd42a6cf2014-06-03 16:24:04 -070084 mConfig = RecentsConfiguration.getInstance();
Winson Chungecd9b302014-04-16 17:07:18 -070085 mInflater = LayoutInflater.from(context);
Winson Chung303e1ff2014-03-07 15:06:19 -080086 }
87
Winson Chung47c4c692014-03-17 10:17:11 -070088 /** Sets the callbacks */
89 public void setCallbacks(RecentsViewCallbacks cb) {
90 mCb = cb;
91 }
92
Winson Chungdcfa7972014-07-22 12:27:13 -070093 /** Sets the debug overlay */
94 public void setDebugOverlay(DebugOverlayView overlay) {
95 mDebugOverlay = overlay;
96 }
Winson Chung303e1ff2014-03-07 15:06:19 -080097
Winson Chungdcfa7972014-07-22 12:27:13 -070098 /** Set/get the bsp root node */
99 public void setTaskStacks(ArrayList<TaskStack> stacks) {
Winson Chung7aceb9a2014-07-03 13:38:01 -0700100 // Remove all TaskStackViews (but leave the search bar)
101 int childCount = getChildCount();
102 for (int i = childCount - 1; i >= 0; i--) {
103 View v = getChildAt(i);
104 if (v != mSearchBar) {
105 removeViewAt(i);
106 }
107 }
108
Winson Chung04dfe0d2014-03-14 14:06:29 -0700109 // Create and add all the stacks for this partition of space.
Winson Chungdcfa7972014-07-22 12:27:13 -0700110 mStacks = stacks;
111 int numStacks = mStacks.size();
112 for (int i = 0; i < numStacks; i++) {
113 TaskStack stack = mStacks.get(i);
Winson Chung303e1ff2014-03-07 15:06:19 -0800114 TaskStackView stackView = new TaskStackView(getContext(), stack);
115 stackView.setCallbacks(this);
Winson Chungdcfa7972014-07-22 12:27:13 -0700116 // Enable debug mode drawing
117 if (mConfig.debugModeEnabled) {
118 stackView.setDebugOverlay(mDebugOverlay);
119 }
Winson Chung303e1ff2014-03-07 15:06:19 -0800120 addView(stackView);
121 }
122 }
123
Winson Chung1e8d71b2014-05-16 17:05:22 -0700124 /** Launches the focused task from the first stack if possible */
125 public boolean launchFocusedTask() {
126 // Get the first stack view
127 int childCount = getChildCount();
128 for (int i = 0; i < childCount; i++) {
129 View child = getChildAt(i);
Winson Chung7aceb9a2014-07-03 13:38:01 -0700130 if (child != mSearchBar) {
Winson Chung1e8d71b2014-05-16 17:05:22 -0700131 TaskStackView stackView = (TaskStackView) child;
132 TaskStack stack = stackView.mStack;
133 // Iterate the stack views and try and find the focused task
134 int taskCount = stackView.getChildCount();
135 for (int j = 0; j < taskCount; j++) {
136 TaskView tv = (TaskView) stackView.getChildAt(j);
137 Task task = tv.getTask();
138 if (tv.isFocusedTask()) {
Winson Chung1f24c7e2014-07-11 17:06:48 -0700139 onTaskViewClicked(stackView, tv, stack, task, false);
Winson Chung1e8d71b2014-05-16 17:05:22 -0700140 return true;
141 }
142 }
143 }
144 }
Winson Chung1e8d71b2014-05-16 17:05:22 -0700145 return false;
146 }
147
Winson Chungdcfa7972014-07-22 12:27:13 -0700148 /** Launches the task that Recents was launched from, if possible */
149 public boolean launchPreviousTask() {
Winson Chung47c4c692014-03-17 10:17:11 -0700150 // Get the first stack view
Winson Chung303e1ff2014-03-07 15:06:19 -0800151 int childCount = getChildCount();
152 for (int i = 0; i < childCount; i++) {
Winson Chungecd9b302014-04-16 17:07:18 -0700153 View child = getChildAt(i);
Winson Chung7aceb9a2014-07-03 13:38:01 -0700154 if (child != mSearchBar) {
Winson Chungecd9b302014-04-16 17:07:18 -0700155 TaskStackView stackView = (TaskStackView) child;
156 TaskStack stack = stackView.mStack;
157 ArrayList<Task> tasks = stack.getTasks();
Winson Chung47c4c692014-03-17 10:17:11 -0700158
Winson Chungdcfa7972014-07-22 12:27:13 -0700159 // Find the launch task in the stack
Winson Chungecd9b302014-04-16 17:07:18 -0700160 if (!tasks.isEmpty()) {
Winson Chungdcfa7972014-07-22 12:27:13 -0700161 int taskCount = tasks.size();
162 for (int j = 0; j < taskCount; j++) {
163 if (tasks.get(j).isLaunchTarget) {
164 Task task = tasks.get(j);
165 TaskView tv = stackView.getChildViewForTask(task);
166 onTaskViewClicked(stackView, tv, stack, task, false);
167 return true;
Winson Chungecd9b302014-04-16 17:07:18 -0700168 }
Winson Chung303e1ff2014-03-07 15:06:19 -0800169 }
170 }
Winson Chung303e1ff2014-03-07 15:06:19 -0800171 }
172 }
173 return false;
174 }
175
Winson Chung24cf1522014-05-29 12:03:33 -0700176 /** Requests all task stacks to start their enter-recents animation */
Winson Chung969f5862014-06-16 17:08:24 -0700177 public void startEnterRecentsAnimation(ViewAnimation.TaskViewEnterContext ctx) {
Winson Chung24cf1522014-05-29 12:03:33 -0700178 int childCount = getChildCount();
179 for (int i = 0; i < childCount; i++) {
180 View child = getChildAt(i);
Winson Chung7aceb9a2014-07-03 13:38:01 -0700181 if (child != mSearchBar) {
Winson Chung24cf1522014-05-29 12:03:33 -0700182 TaskStackView stackView = (TaskStackView) child;
Winson Chung969f5862014-06-16 17:08:24 -0700183 stackView.startEnterRecentsAnimation(ctx);
Winson Chung24cf1522014-05-29 12:03:33 -0700184 }
185 }
186 }
187
Winson Chungd42a6cf2014-06-03 16:24:04 -0700188 /** Requests all task stacks to start their exit-recents animation */
Winson Chung969f5862014-06-16 17:08:24 -0700189 public void startExitToHomeAnimation(ViewAnimation.TaskViewExitContext ctx) {
Winson Chungd7b2cb12014-06-26 15:08:50 -0700190 int childCount = getChildCount();
191 for (int i = 0; i < childCount; i++) {
192 View child = getChildAt(i);
Winson Chung7aceb9a2014-07-03 13:38:01 -0700193 if (child != mSearchBar) {
Winson Chungd7b2cb12014-06-26 15:08:50 -0700194 TaskStackView stackView = (TaskStackView) child;
195 stackView.startExitToHomeAnimation(ctx);
Winson Chungd42a6cf2014-06-03 16:24:04 -0700196 }
197 }
198
Winson Chung969f5862014-06-16 17:08:24 -0700199 // Notify of the exit animation
Winson Chungcdbbb7e2014-06-24 12:11:49 -0700200 mCb.onExitToHomeAnimationTriggered();
Winson Chungd42a6cf2014-06-03 16:24:04 -0700201 }
202
Winson Chungf7bca432014-04-30 17:11:13 -0700203 /** Adds the search bar */
204 public void setSearchBar(View searchBar) {
205 // Create the search bar (and hide it if we have no recent tasks)
Winson Chung814086d2014-05-07 15:01:14 -0700206 if (Constants.DebugFlags.App.EnableSearchLayout) {
Winson Chungf7bca432014-04-30 17:11:13 -0700207 // Remove the previous search bar if one exists
208 if (mSearchBar != null && indexOfChild(mSearchBar) > -1) {
209 removeView(mSearchBar);
Winson Chungecd9b302014-04-16 17:07:18 -0700210 }
Winson Chungf7bca432014-04-30 17:11:13 -0700211 // Add the new search bar
212 if (searchBar != null) {
213 mSearchBar = searchBar;
Winson Chungf7bca432014-04-30 17:11:13 -0700214 addView(mSearchBar);
Winson Chungf7bca432014-04-30 17:11:13 -0700215 }
216 }
Winson Chungecd9b302014-04-16 17:07:18 -0700217 }
218
Winson Chung772b6b12014-07-03 15:54:02 -0700219 /** Returns whether there is currently a search bar */
220 public boolean hasSearchBar() {
221 return mSearchBar != null;
222 }
223
224 /** Sets the visibility of the search bar */
225 public void setSearchBarVisibility(int visibility) {
226 if (mSearchBar != null) {
227 mSearchBar.setVisibility(visibility);
228 }
229 }
230
Winson Chungf7bca432014-04-30 17:11:13 -0700231 /**
232 * This is called with the full size of the window since we are handling our own insets.
233 */
Winson Chung303e1ff2014-03-07 15:06:19 -0800234 @Override
235 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
236 int width = MeasureSpec.getSize(widthMeasureSpec);
237 int height = MeasureSpec.getSize(heightMeasureSpec);
Winson Chungbd912972014-03-18 14:36:35 -0700238
Winson Chungf7bca432014-04-30 17:11:13 -0700239 // Get the search bar bounds and measure the search bar layout
Winson Chungecd9b302014-04-16 17:07:18 -0700240 if (mSearchBar != null) {
Winson Chungf7bca432014-04-30 17:11:13 -0700241 Rect searchBarSpaceBounds = new Rect();
Winson Chungdcfa7972014-07-22 12:27:13 -0700242 mConfig.getSearchBarBounds(width, height, mConfig.systemInsets.top, searchBarSpaceBounds);
Winson Chungf7bca432014-04-30 17:11:13 -0700243 mSearchBar.measure(
244 MeasureSpec.makeMeasureSpec(searchBarSpaceBounds.width(), MeasureSpec.EXACTLY),
245 MeasureSpec.makeMeasureSpec(searchBarSpaceBounds.height(), MeasureSpec.EXACTLY));
Winson Chungecd9b302014-04-16 17:07:18 -0700246 }
247
Winson Chungf7bca432014-04-30 17:11:13 -0700248 Rect taskStackBounds = new Rect();
Winson Chungdcfa7972014-07-22 12:27:13 -0700249 mConfig.getTaskStackBounds(width, height, mConfig.systemInsets.top,
250 mConfig.systemInsets.right, taskStackBounds);
Winson Chung303e1ff2014-03-07 15:06:19 -0800251
Winson Chungdcfa7972014-07-22 12:27:13 -0700252 // Measure each TaskStackView with the full width and height of the window since the
253 // transition view is a child of that stack view
Winson Chung303e1ff2014-03-07 15:06:19 -0800254 int childCount = getChildCount();
255 for (int i = 0; i < childCount; i++) {
Winson Chungecd9b302014-04-16 17:07:18 -0700256 View child = getChildAt(i);
Winson Chung7aceb9a2014-07-03 13:38:01 -0700257 if (child != mSearchBar && child.getVisibility() != GONE) {
Winson Chungdcfa7972014-07-22 12:27:13 -0700258 TaskStackView tsv = (TaskStackView) child;
259 // Set the insets to be the top/left inset + search bounds
260 tsv.setStackInsetRect(taskStackBounds);
261 tsv.measure(widthMeasureSpec, heightMeasureSpec);
Winson Chung303e1ff2014-03-07 15:06:19 -0800262 }
263 }
264
265 setMeasuredDimension(width, height);
266 }
267
Winson Chungf7bca432014-04-30 17:11:13 -0700268 /**
269 * This is called with the full size of the window since we are handling our own insets.
270 */
Winson Chung303e1ff2014-03-07 15:06:19 -0800271 @Override
272 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
Winson Chungf7bca432014-04-30 17:11:13 -0700273 // Get the search bar bounds so that we lay it out
Winson Chungecd9b302014-04-16 17:07:18 -0700274 if (mSearchBar != null) {
Winson Chungf7bca432014-04-30 17:11:13 -0700275 Rect searchBarSpaceBounds = new Rect();
Winson Chungdcfa7972014-07-22 12:27:13 -0700276 mConfig.getSearchBarBounds(getMeasuredWidth(), getMeasuredHeight(),
277 mConfig.systemInsets.top, searchBarSpaceBounds);
278 mSearchBar.layout(searchBarSpaceBounds.left, searchBarSpaceBounds.top,
279 searchBarSpaceBounds.right, searchBarSpaceBounds.bottom);
Winson Chungecd9b302014-04-16 17:07:18 -0700280 }
281
Winson Chungdcfa7972014-07-22 12:27:13 -0700282 // Layout each TaskStackView with the full width and height of the window since the
283 // transition view is a child of that stack view
Winson Chung303e1ff2014-03-07 15:06:19 -0800284 int childCount = getChildCount();
285 for (int i = 0; i < childCount; i++) {
Winson Chungecd9b302014-04-16 17:07:18 -0700286 View child = getChildAt(i);
Winson Chung7aceb9a2014-07-03 13:38:01 -0700287 if (child != mSearchBar && child.getVisibility() != GONE) {
Winson Chungdcfa7972014-07-22 12:27:13 -0700288 child.layout(left, top, left + child.getMeasuredWidth(),
289 top + child.getMeasuredHeight());
Winson Chung303e1ff2014-03-07 15:06:19 -0800290 }
291 }
292 }
293
Winson Chung8eaeb7d2014-06-25 15:10:59 -0700294 @Override
Winson Chung8eaeb7d2014-06-25 15:10:59 -0700295 public WindowInsets onApplyWindowInsets(WindowInsets insets) {
Winson Chung8eaeb7d2014-06-25 15:10:59 -0700296 // Update the configuration with the latest system insets and trigger a relayout
297 mConfig.updateSystemInsets(insets.getSystemWindowInsets());
298 requestLayout();
Winson Chungdcfa7972014-07-22 12:27:13 -0700299 return insets.consumeSystemWindowInsets();
Winson Chung8eaeb7d2014-06-25 15:10:59 -0700300 }
301
Winson Chunga26fb782014-06-12 17:52:39 -0700302 /** Notifies each task view of the user interaction. */
303 public void onUserInteraction() {
304 // Get the first stack view
305 TaskStackView stackView = null;
306 int childCount = getChildCount();
307 for (int i = 0; i < childCount; i++) {
308 View child = getChildAt(i);
Winson Chung7aceb9a2014-07-03 13:38:01 -0700309 if (child != mSearchBar) {
Winson Chunga26fb782014-06-12 17:52:39 -0700310 stackView = (TaskStackView) child;
311 stackView.onUserInteraction();
312 }
313 }
314 }
315
Winson Chung1e8d71b2014-05-16 17:05:22 -0700316 /** Focuses the next task in the first stack view */
317 public void focusNextTask(boolean forward) {
318 // Get the first stack view
319 TaskStackView stackView = null;
320 int childCount = getChildCount();
321 for (int i = 0; i < childCount; i++) {
322 View child = getChildAt(i);
Winson Chung7aceb9a2014-07-03 13:38:01 -0700323 if (child != mSearchBar) {
Winson Chung1e8d71b2014-05-16 17:05:22 -0700324 stackView = (TaskStackView) child;
325 break;
326 }
327 }
328
329 if (stackView != null) {
330 stackView.focusNextTask(forward);
331 }
332 }
333
Winson Chung303e1ff2014-03-07 15:06:19 -0800334 /** Unfilters any filtered stacks */
335 public boolean unfilterFilteredStacks() {
Winson Chungdcfa7972014-07-22 12:27:13 -0700336 if (mStacks != null) {
Winson Chung303e1ff2014-03-07 15:06:19 -0800337 // Check if there are any filtered stacks and unfilter them before we back out of Recents
338 boolean stacksUnfiltered = false;
Winson Chungdcfa7972014-07-22 12:27:13 -0700339 int numStacks = mStacks.size();
340 for (int i = 0; i < numStacks; i++) {
341 TaskStack stack = mStacks.get(i);
Winson Chung303e1ff2014-03-07 15:06:19 -0800342 if (stack.hasFilteredTasks()) {
343 stack.unfilterTasks();
344 stacksUnfiltered = true;
345 }
346 }
347 return stacksUnfiltered;
348 }
349 return false;
350 }
351
Winson Chung47c4c692014-03-17 10:17:11 -0700352 /**** TaskStackView.TaskStackCallbacks Implementation ****/
Winson Chung303e1ff2014-03-07 15:06:19 -0800353
354 @Override
Winson Chung7aceb9a2014-07-03 13:38:01 -0700355 public void onTaskViewClicked(final TaskStackView stackView, final TaskView tv,
Winson Chung1f24c7e2014-07-11 17:06:48 -0700356 final TaskStack stack, final Task task, final boolean lockToTask) {
Winson Chung47c4c692014-03-17 10:17:11 -0700357 // Notify any callbacks of the launching of a new task
358 if (mCb != null) {
Winson Chung7aceb9a2014-07-03 13:38:01 -0700359 mCb.onTaskViewClicked();
Winson Chung47c4c692014-03-17 10:17:11 -0700360 }
361
Winson Chunge0e45bc2014-06-17 17:56:17 -0700362 // Upfront the processing of the thumbnail
Winson Chungffa2ec62014-07-03 15:54:42 -0700363 TaskViewTransform transform = new TaskViewTransform();
Winson Chunge0e45bc2014-06-17 17:56:17 -0700364 View sourceView = tv;
365 int offsetX = 0;
366 int offsetY = 0;
367 int stackScroll = stackView.getStackScroll();
368 if (tv == null) {
369 // If there is no actual task view, then use the stack view as the source view
370 // and then offset to the expected transform rect, but bound this to just
371 // outside the display rect (to ensure we don't animate from too far away)
372 sourceView = stackView;
Winson Chunga433fa92014-07-08 21:50:31 -0700373 transform = stackView.getStackAlgorithm().getStackTransform(task, stackScroll, transform);
Winson Chunge0e45bc2014-06-17 17:56:17 -0700374 offsetX = transform.rect.left;
375 offsetY = Math.min(transform.rect.top, mConfig.displayRect.height());
376 } else {
Winson Chunga433fa92014-07-08 21:50:31 -0700377 transform = stackView.getStackAlgorithm().getStackTransform(task, stackScroll, transform);
Winson Chunge0e45bc2014-06-17 17:56:17 -0700378 }
379
380 // Compute the thumbnail to scale up from
Winson Chung1f24c7e2014-07-11 17:06:48 -0700381 final SystemServicesProxy ssp =
382 RecentsTaskLoader.getInstance().getSystemServicesProxy();
Winson Chunge0e45bc2014-06-17 17:56:17 -0700383 ActivityOptions opts = null;
384 int thumbnailWidth = transform.rect.width();
385 int thumbnailHeight = transform.rect.height();
386 if (task.thumbnail != null && thumbnailWidth > 0 && thumbnailHeight > 0 &&
387 task.thumbnail.getWidth() > 0 && task.thumbnail.getHeight() > 0) {
388 // Resize the thumbnail to the size of the view that we are animating from
389 Bitmap b = Bitmap.createBitmap(thumbnailWidth, thumbnailHeight,
390 Bitmap.Config.ARGB_8888);
391 Canvas c = new Canvas(b);
392 c.drawBitmap(task.thumbnail,
393 new Rect(0, 0, task.thumbnail.getWidth(), task.thumbnail.getHeight()),
394 new Rect(0, 0, thumbnailWidth, thumbnailHeight), null);
395 c.setBitmap(null);
Winson Chung1f24c7e2014-07-11 17:06:48 -0700396 ActivityOptions.OnAnimationStartedListener animStartedListener = null;
397 if (lockToTask) {
398 animStartedListener = new ActivityOptions.OnAnimationStartedListener() {
399 boolean mTriggered = false;
400 @Override
401 public void onAnimationStarted() {
402 if (!mTriggered) {
403 postDelayed(new Runnable() {
404 @Override
405 public void run() {
406 ssp.lockCurrentTask();
407 }
408 }, 350);
409 mTriggered = true;
410 }
411 }
412 };
413 }
Winson Chunge0e45bc2014-06-17 17:56:17 -0700414 opts = ActivityOptions.makeThumbnailScaleUpAnimation(sourceView,
Winson Chung1f24c7e2014-07-11 17:06:48 -0700415 b, offsetX, offsetY, animStartedListener);
Winson Chunge0e45bc2014-06-17 17:56:17 -0700416 }
417
418 final ActivityOptions launchOpts = opts;
Winson Chung303e1ff2014-03-07 15:06:19 -0800419 final Runnable launchRunnable = new Runnable() {
420 @Override
421 public void run() {
Winson Chung4be04452014-03-24 17:22:30 -0700422 if (task.isActive) {
423 // Bring an active task to the foreground
Craig Mautnerdc00cbe2014-07-20 17:48:47 -0700424 ssp.moveTaskToFront(task.key.id, launchOpts);
Winson Chung4be04452014-03-24 17:22:30 -0700425 } else {
Winson Chung5393dff2014-05-08 14:25:43 -0700426 // Launch the activity anew with the desired animation
Winson Chungc6a16232014-04-01 14:04:48 -0700427 Intent i = new Intent(task.key.baseIntent);
Winson Chungdc9b7e72014-07-16 11:25:22 -0700428 i.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
429 | Intent.FLAG_ACTIVITY_TASK_ON_HOME);
Winson Chungff88d7b2014-07-17 12:30:07 -0700430 if (!Utilities.isDocument(i)) {
Winson Chungdc9b7e72014-07-16 11:25:22 -0700431 i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
432 }
Winson Chung4be04452014-03-24 17:22:30 -0700433 try {
Craig Mautnerdc00cbe2014-07-20 17:48:47 -0700434 ssp.startActivityFromRecents(task.key.id, launchOpts);
435 if (launchOpts == null && lockToTask) {
436 ssp.lockCurrentTask();
Winson Chung4be04452014-03-24 17:22:30 -0700437 }
438 } catch (ActivityNotFoundException anfe) {
439 Console.logError(getContext(), "Could not start Activity");
440 }
Winson Chung5393dff2014-05-08 14:25:43 -0700441
442 // And clean up the old task
Winson Chung7aceb9a2014-07-03 13:38:01 -0700443 onTaskViewDismissed(task);
Winson Chung303e1ff2014-03-07 15:06:19 -0800444 }
445 }
446 };
447
448 // Launch the app right away if there is no task view, otherwise, animate the icon out first
Winson Chung814086d2014-05-07 15:01:14 -0700449 if (tv == null) {
Winson Chung47c4c692014-03-17 10:17:11 -0700450 post(launchRunnable);
Winson Chung303e1ff2014-03-07 15:06:19 -0800451 } else {
Winson Chung969f5862014-06-16 17:08:24 -0700452 stackView.animateOnLaunchingTask(tv, launchRunnable);
Winson Chung303e1ff2014-03-07 15:06:19 -0800453 }
454 }
Winson Chung9f9679d2014-04-11 16:49:09 -0700455
456 @Override
Winson Chung7aceb9a2014-07-03 13:38:01 -0700457 public void onTaskViewAppInfoClicked(Task t) {
Winson Chung9f9679d2014-04-11 16:49:09 -0700458 // Create a new task stack with the application info details activity
459 Intent baseIntent = t.key.baseIntent;
460 Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
461 Uri.fromParts("package", baseIntent.getComponent().getPackageName(), null));
462 intent.setComponent(intent.resolveActivity(getContext().getPackageManager()));
463 TaskStackBuilder.create(getContext())
464 .addNextIntentWithParentStack(intent).startActivities();
465 }
Winson Chung9f49df92014-05-07 18:08:34 -0700466
Winson Chung5393dff2014-05-08 14:25:43 -0700467 @Override
Winson Chung7aceb9a2014-07-03 13:38:01 -0700468 public void onTaskViewDismissed(Task t) {
Winson Chung5393dff2014-05-08 14:25:43 -0700469 // Remove any stored data from the loader. We currently don't bother notifying the views
Winson Chung7aceb9a2014-07-03 13:38:01 -0700470 // that the data has been unloaded because at the point we call onTaskViewDismissed(), the views
Winson Chung5393dff2014-05-08 14:25:43 -0700471 // either don't need to be updated, or have already been removed.
472 RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
473 loader.deleteTaskData(t, false);
474
475 // Remove the old task from activity manager
Winson Chung5393dff2014-05-08 14:25:43 -0700476 RecentsTaskLoader.getInstance().getSystemServicesProxy().removeTask(t.key.id,
Winson Chungff88d7b2014-07-17 12:30:07 -0700477 Utilities.isDocument(t.key.baseIntent));
Winson Chung5393dff2014-05-08 14:25:43 -0700478 }
479
Winson Chung8e548f72014-06-24 14:40:53 -0700480 @Override
Winson Chung7aceb9a2014-07-03 13:38:01 -0700481 public void onAllTaskViewsDismissed() {
482 mCb.onAllTaskViewsDismissed();
Winson Chungd7b2cb12014-06-26 15:08:50 -0700483 }
484
485 @Override
Winson Chung8e548f72014-06-24 14:40:53 -0700486 public void onTaskStackFilterTriggered() {
487 // Hide the search bar
488 if (mSearchBar != null) {
489 mSearchBar.animate()
490 .alpha(0f)
491 .setStartDelay(0)
492 .setInterpolator(mConfig.fastOutSlowInInterpolator)
493 .setDuration(mConfig.filteringCurrentViewsAnimDuration)
494 .withLayer()
495 .start();
496 }
497 }
498
499 @Override
500 public void onTaskStackUnfilterTriggered() {
501 // Show the search bar
502 if (mSearchBar != null) {
503 mSearchBar.animate()
504 .alpha(1f)
505 .setStartDelay(0)
506 .setInterpolator(mConfig.fastOutSlowInInterpolator)
507 .setDuration(mConfig.filteringNewViewsAnimDuration)
508 .withLayer()
509 .start();
510 }
511 }
512
Winson Chung9f49df92014-05-07 18:08:34 -0700513 /**** RecentsPackageMonitor.PackageCallbacks Implementation ****/
514
515 @Override
Winson Chung82c8c5e2014-07-14 17:31:41 -0700516 public void onComponentRemoved(HashSet<ComponentName> cns) {
Winson Chung9f49df92014-05-07 18:08:34 -0700517 // Propagate this event down to each task stack view
518 int childCount = getChildCount();
519 for (int i = 0; i < childCount; i++) {
520 View child = getChildAt(i);
Winson Chung7aceb9a2014-07-03 13:38:01 -0700521 if (child != mSearchBar) {
Winson Chung9f49df92014-05-07 18:08:34 -0700522 TaskStackView stackView = (TaskStackView) child;
523 stackView.onComponentRemoved(cns);
524 }
525 }
526 }
Winson Chung303e1ff2014-03-07 15:06:19 -0800527}