blob: d18389f43a1ff45a31956bb11adb8b89b9f0e6ad [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
Winson Chung303e1ff2014-03-07 15:06:19 -080019import android.content.Context;
Winson Chung303e1ff2014-03-07 15:06:19 -080020import android.graphics.Canvas;
21import android.graphics.Rect;
Winson4165d3362015-10-10 14:40:35 -070022import android.graphics.drawable.Drawable;
Winson83c1b072015-11-09 10:48:04 -080023import android.os.Handler;
Winson882072b2015-10-12 11:26:33 -070024import android.util.ArraySet;
Winson Chung8e548f72014-06-24 14:40:53 -070025import android.util.AttributeSet;
Filip Gruszczynski170192a2015-08-16 17:46:34 -070026import android.view.AppTransitionAnimationSpec;
Winson Chungecd9b302014-04-16 17:07:18 -070027import android.view.LayoutInflater;
Winsonbe7607a2015-10-01 17:24:51 -070028import android.view.MotionEvent;
Winson Chung303e1ff2014-03-07 15:06:19 -080029import android.view.View;
Winson Chung653f70c22014-05-19 14:49:42 -070030import android.view.WindowInsets;
Winson35f30502015-09-28 11:24:36 -070031import android.view.animation.AnimationUtils;
32import android.view.animation.Interpolator;
Winson Chung303e1ff2014-03-07 15:06:19 -080033import android.widget.FrameLayout;
Jorim Jaggi2f7d2922015-10-29 13:08:29 +010034import com.android.internal.annotations.GuardedBy;
Winson Chung5c9f4b92015-06-25 16:16:46 -070035import com.android.internal.logging.MetricsLogger;
Winson Chungd16c5652015-01-26 16:11:07 -080036import com.android.systemui.R;
Winsone7f138c2015-10-22 16:15:21 -070037import com.android.systemui.recents.Recents;
Winsonbe7607a2015-10-01 17:24:51 -070038import com.android.systemui.recents.RecentsActivity;
Winson Chungaee097c2015-04-02 18:16:02 -070039import com.android.systemui.recents.RecentsAppWidgetHostView;
Winson Chung303e1ff2014-03-07 15:06:19 -080040import com.android.systemui.recents.RecentsConfiguration;
Winson2536c7e2015-10-01 15:49:31 -070041import com.android.systemui.recents.events.EventBus;
Winson13d30662015-11-06 15:30:29 -080042import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent;
Winson412e1802015-10-20 16:57:57 -070043import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
Jorim Jaggidd98d412015-11-18 15:57:38 -080044import com.android.systemui.recents.events.ui.DraggingInRecentsEndedEvent;
45import com.android.systemui.recents.events.ui.DraggingInRecentsEvent;
Winsoneca4ab62015-11-04 10:50:28 -080046import com.android.systemui.recents.events.ui.dragndrop.DragDropTargetChangedEvent;
Winsonbe7607a2015-10-01 17:24:51 -070047import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
48import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
Winson Chung1f24c7e2014-07-11 17:06:48 -070049import com.android.systemui.recents.misc.SystemServicesProxy;
Winson Chung303e1ff2014-03-07 15:06:19 -080050import com.android.systemui.recents.model.Task;
51import com.android.systemui.recents.model.TaskStack;
52
53import java.util.ArrayList;
Winson Chung6ac8bd62015-01-07 16:38:35 -080054import java.util.List;
Winson Chung303e1ff2014-03-07 15:06:19 -080055
Wale Ogunwale3797c222015-10-27 14:21:58 -070056import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
Winson412e1802015-10-20 16:57:57 -070057
Winson Chung303e1ff2014-03-07 15:06:19 -080058/**
59 * This view is the the top level layout that contains TaskStacks (which are laid out according
60 * to their SpaceNode bounds.
61 */
Winsone6c90732015-09-24 16:06:29 -070062public class RecentsView extends FrameLayout implements TaskStackView.TaskStackViewCallbacks {
Winson Chung47c4c692014-03-17 10:17:11 -070063
Jorim Jaggi6e18e002015-06-02 17:07:39 -070064 private static final String TAG = "RecentsView";
Winson0d14d4d2015-10-26 17:05:04 -070065 private static final boolean DEBUG = false;
Jorim Jaggi6e18e002015-06-02 17:07:39 -070066
Filip Gruszczynski14b4e572015-11-03 15:53:55 -080067 private int mStackViewVisibility = View.VISIBLE;
Filip Gruszczynski170192a2015-08-16 17:46:34 -070068
Winson Chung47c4c692014-03-17 10:17:11 -070069 /** The RecentsView callbacks */
70 public interface RecentsViewCallbacks {
Winson Chung7aceb9a2014-07-03 13:38:01 -070071 public void onAllTaskViewsDismissed();
Winson Chung47c4c692014-03-17 10:17:11 -070072 }
73
Winson Chungd42a6cf2014-06-03 16:24:04 -070074 LayoutInflater mInflater;
Winson83c1b072015-11-09 10:48:04 -080075 Handler mHandler;
Winson Chungd42a6cf2014-06-03 16:24:04 -070076
Winson Chungdcfa7972014-07-22 12:27:13 -070077 ArrayList<TaskStack> mStacks;
Winson147ecaf2015-09-16 16:49:55 -070078 TaskStackView mTaskStackView;
Winson Chungaee097c2015-04-02 18:16:02 -070079 RecentsAppWidgetHostView mSearchBar;
Winson Chung47c4c692014-03-17 10:17:11 -070080 RecentsViewCallbacks mCb;
Winsonbe7607a2015-10-01 17:24:51 -070081
Winson83c1b072015-11-09 10:48:04 -080082 RecentsTransitionHelper mTransitionHelper;
Winsonbe7607a2015-10-01 17:24:51 -070083 RecentsViewTouchHandler mTouchHandler;
84 DragView mDragView;
Winson882072b2015-10-12 11:26:33 -070085 TaskStack.DockState[] mVisibleDockStates = {
86 TaskStack.DockState.LEFT,
87 TaskStack.DockState.TOP,
88 TaskStack.DockState.RIGHT,
89 TaskStack.DockState.BOTTOM,
90 };
Winsonbe7607a2015-10-01 17:24:51 -070091
Winson35f30502015-09-28 11:24:36 -070092 Interpolator mFastOutSlowInInterpolator;
93
94 Rect mSystemInsets = new Rect();
Winson Chung303e1ff2014-03-07 15:06:19 -080095
96 public RecentsView(Context context) {
97 super(context);
Winson Chung8e548f72014-06-24 14:40:53 -070098 }
99
100 public RecentsView(Context context, AttributeSet attrs) {
101 this(context, attrs, 0);
102 }
103
104 public RecentsView(Context context, AttributeSet attrs, int defStyleAttr) {
105 this(context, attrs, defStyleAttr, 0);
106 }
107
108 public RecentsView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
109 super(context, attrs, defStyleAttr, defStyleRes);
Winsonbe7607a2015-10-01 17:24:51 -0700110 setWillNotDraw(false);
Winson Chungecd9b302014-04-16 17:07:18 -0700111 mInflater = LayoutInflater.from(context);
Winson83c1b072015-11-09 10:48:04 -0800112 mHandler = new Handler();
113 mTransitionHelper = new RecentsTransitionHelper(getContext(), mHandler);
Winson35f30502015-09-28 11:24:36 -0700114 mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
115 com.android.internal.R.interpolator.fast_out_slow_in);
Winsonbe7607a2015-10-01 17:24:51 -0700116 mTouchHandler = new RecentsViewTouchHandler(this);
Winson Chungd16c5652015-01-26 16:11:07 -0800117 }
118
Winson Chung47c4c692014-03-17 10:17:11 -0700119 /** Sets the callbacks */
120 public void setCallbacks(RecentsViewCallbacks cb) {
121 mCb = cb;
122 }
123
Winson Chungdcfa7972014-07-22 12:27:13 -0700124 /** Set/get the bsp root node */
Winson147ecaf2015-09-16 16:49:55 -0700125 public void setTaskStack(TaskStack stack) {
Winson53ec42c2015-10-28 15:55:35 -0700126 RecentsConfiguration config = Recents.getConfiguration();
127 if (config.getLaunchState().launchedReuseTaskStackViews) {
Winson147ecaf2015-09-16 16:49:55 -0700128 if (mTaskStackView != null) {
129 // If onRecentsHidden is not triggered, we need to the stack view again here
130 mTaskStackView.reset();
131 mTaskStackView.setStack(stack);
132 } else {
133 mTaskStackView = new TaskStackView(getContext(), stack);
134 mTaskStackView.setCallbacks(this);
135 addView(mTaskStackView);
136 }
137 } else {
138 if (mTaskStackView != null) {
139 removeView(mTaskStackView);
140 }
141 mTaskStackView = new TaskStackView(getContext(), stack);
142 mTaskStackView.setCallbacks(this);
143 addView(mTaskStackView);
Winson Chung303e1ff2014-03-07 15:06:19 -0800144 }
Filip Gruszczynski14b4e572015-11-03 15:53:55 -0800145 mTaskStackView.setVisibility(mStackViewVisibility);
Winson Chung02d49272014-08-29 13:57:29 -0700146
Winson Chungb0a28ea2014-10-28 15:21:35 -0700147 // Trigger a new layout
148 requestLayout();
Winson Chung19fc1172014-07-31 18:40:03 -0700149 }
150
Skuhne8aa7d162015-03-20 13:40:53 -0700151 /** Gets the next task in the stack - or if the last - the top task */
152 public Task getNextTaskOrTopTask(Task taskToSearch) {
Chong Zhang0fa656b2015-08-31 15:17:21 -0700153 Task returnTask = null;
Skuhne8aa7d162015-03-20 13:40:53 -0700154 boolean found = false;
Winson147ecaf2015-09-16 16:49:55 -0700155 if (mTaskStackView != null) {
156 TaskStack stack = mTaskStackView.getStack();
Skuhne8aa7d162015-03-20 13:40:53 -0700157 ArrayList<Task> taskList = stack.getTasks();
158 // Iterate the stack views and try and find the focused task
159 for (int j = taskList.size() - 1; j >= 0; --j) {
160 Task task = taskList.get(j);
161 // Return the next task in the line.
162 if (found)
163 return task;
164 // Remember the first possible task as the top task.
165 if (returnTask == null)
166 returnTask = task;
167 if (task == taskToSearch)
168 found = true;
169 }
170 }
171 return returnTask;
172 }
173
Winson Chung1e8d71b2014-05-16 17:05:22 -0700174 /** Launches the focused task from the first stack if possible */
175 public boolean launchFocusedTask() {
Winson147ecaf2015-09-16 16:49:55 -0700176 if (mTaskStackView != null) {
177 TaskStack stack = mTaskStackView.getStack();
Winson142af422015-11-09 10:39:57 -0800178 Task task = mTaskStackView.getFocusedTask();
179 if (task != null) {
180 TaskView taskView = mTaskStackView.getChildViewForTask(task);
Winson83c1b072015-11-09 10:48:04 -0800181 onTaskViewClicked(mTaskStackView, taskView, stack, task, false, null,
Winson142af422015-11-09 10:39:57 -0800182 INVALID_STACK_ID);
183 return true;
Winson Chung1e8d71b2014-05-16 17:05:22 -0700184 }
185 }
Winson Chung1e8d71b2014-05-16 17:05:22 -0700186 return false;
187 }
188
Skuhne8aa7d162015-03-20 13:40:53 -0700189 /** Launches a given task. */
Filip Gruszczynskif48b5852015-10-13 10:28:22 -0700190 public boolean launchTask(Task task, Rect taskBounds, int destinationStack) {
Winson147ecaf2015-09-16 16:49:55 -0700191 if (mTaskStackView != null) {
192 TaskStack stack = mTaskStackView.getStack();
Skuhne8aa7d162015-03-20 13:40:53 -0700193 // Iterate the stack views and try and find the given task.
Winson147ecaf2015-09-16 16:49:55 -0700194 List<TaskView> taskViews = mTaskStackView.getTaskViews();
Skuhne8aa7d162015-03-20 13:40:53 -0700195 int taskViewCount = taskViews.size();
196 for (int j = 0; j < taskViewCount; j++) {
197 TaskView tv = taskViews.get(j);
198 if (tv.getTask() == task) {
Winson83c1b072015-11-09 10:48:04 -0800199 onTaskViewClicked(mTaskStackView, tv, stack, task, false,
Filip Gruszczynskif48b5852015-10-13 10:28:22 -0700200 taskBounds, destinationStack);
Skuhne8aa7d162015-03-20 13:40:53 -0700201 return true;
202 }
203 }
204 }
205 return false;
206 }
207
Winson Chung24cf1522014-05-29 12:03:33 -0700208 /** Requests all task stacks to start their enter-recents animation */
Winson Chung969f5862014-06-16 17:08:24 -0700209 public void startEnterRecentsAnimation(ViewAnimation.TaskViewEnterContext ctx) {
Winson Chung740c3ac2014-11-12 16:14:38 -0800210 // We have to increment/decrement the post animation trigger in case there are no children
211 // to ensure that it runs
212 ctx.postAnimationTrigger.increment();
Winson147ecaf2015-09-16 16:49:55 -0700213 if (mTaskStackView != null) {
214 mTaskStackView.startEnterRecentsAnimation(ctx);
Winson Chung24cf1522014-05-29 12:03:33 -0700215 }
Winson Chung740c3ac2014-11-12 16:14:38 -0800216 ctx.postAnimationTrigger.decrement();
Winson Chung24cf1522014-05-29 12:03:33 -0700217 }
218
Winson Chungd42a6cf2014-06-03 16:24:04 -0700219 /** Requests all task stacks to start their exit-recents animation */
Winson Chung969f5862014-06-16 17:08:24 -0700220 public void startExitToHomeAnimation(ViewAnimation.TaskViewExitContext ctx) {
Winson Chunga91c2932014-11-07 15:02:38 -0800221 // We have to increment/decrement the post animation trigger in case there are no children
222 // to ensure that it runs
223 ctx.postAnimationTrigger.increment();
Winson147ecaf2015-09-16 16:49:55 -0700224 if (mTaskStackView != null) {
225 mTaskStackView.startExitToHomeAnimation(ctx);
Winson Chungd42a6cf2014-06-03 16:24:04 -0700226 }
Winson Chunga91c2932014-11-07 15:02:38 -0800227 ctx.postAnimationTrigger.decrement();
Winson Chungd42a6cf2014-06-03 16:24:04 -0700228
Winson13d30662015-11-06 15:30:29 -0800229 // If we are going home, cancel the previous task's window transition
230 EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(null));
231
Winson Chung969f5862014-06-16 17:08:24 -0700232 // Notify of the exit animation
Winson412e1802015-10-20 16:57:57 -0700233 EventBus.getDefault().send(new DismissRecentsToHomeAnimationStarted());
Winson Chungd42a6cf2014-06-03 16:24:04 -0700234 }
235
Winson Chungf7bca432014-04-30 17:11:13 -0700236 /** Adds the search bar */
Winson Chungaee097c2015-04-02 18:16:02 -0700237 public void setSearchBar(RecentsAppWidgetHostView searchBar) {
Winson Chungaf3bb692015-06-03 17:31:39 -0700238 // Remove the previous search bar if one exists
239 if (mSearchBar != null && indexOfChild(mSearchBar) > -1) {
240 removeView(mSearchBar);
241 }
242 // Add the new search bar
243 if (searchBar != null) {
244 mSearchBar = searchBar;
245 addView(mSearchBar);
Winson Chungf7bca432014-04-30 17:11:13 -0700246 }
Winson Chungecd9b302014-04-16 17:07:18 -0700247 }
248
Winson Chung772b6b12014-07-03 15:54:02 -0700249 /** Returns whether there is currently a search bar */
Winson Chungaee097c2015-04-02 18:16:02 -0700250 public boolean hasValidSearchBar() {
251 return mSearchBar != null && !mSearchBar.isReinflateRequired();
Winson Chung772b6b12014-07-03 15:54:02 -0700252 }
253
254 /** Sets the visibility of the search bar */
255 public void setSearchBarVisibility(int visibility) {
256 if (mSearchBar != null) {
257 mSearchBar.setVisibility(visibility);
Winson Chung012ef362014-07-31 18:36:25 -0700258 // Always bring the search bar to the top
259 mSearchBar.bringToFront();
Winson Chung772b6b12014-07-03 15:54:02 -0700260 }
261 }
262
Winsonbe7607a2015-10-01 17:24:51 -0700263 @Override
264 protected void onAttachedToWindow() {
265 EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY + 1);
266 EventBus.getDefault().register(mTouchHandler, RecentsActivity.EVENT_BUS_PRIORITY + 1);
267 super.onAttachedToWindow();
268 }
269
270 @Override
271 protected void onDetachedFromWindow() {
272 super.onDetachedFromWindow();
273 EventBus.getDefault().unregister(this);
274 EventBus.getDefault().unregister(mTouchHandler);
275 }
276
Winson Chungf7bca432014-04-30 17:11:13 -0700277 /**
278 * This is called with the full size of the window since we are handling our own insets.
279 */
Winson Chung303e1ff2014-03-07 15:06:19 -0800280 @Override
281 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Winson53ec42c2015-10-28 15:55:35 -0700282 RecentsConfiguration config = Recents.getConfiguration();
Winson Chung303e1ff2014-03-07 15:06:19 -0800283 int width = MeasureSpec.getSize(widthMeasureSpec);
284 int height = MeasureSpec.getSize(heightMeasureSpec);
Winson Chungbd912972014-03-18 14:36:35 -0700285
Winson Chungf7bca432014-04-30 17:11:13 -0700286 // Get the search bar bounds and measure the search bar layout
Winson Chungaf3bb692015-06-03 17:31:39 -0700287 Rect searchBarSpaceBounds = new Rect();
Winson Chungecd9b302014-04-16 17:07:18 -0700288 if (mSearchBar != null) {
Winson53ec42c2015-10-28 15:55:35 -0700289 config.getSearchBarBounds(new Rect(0, 0, width, height), mSystemInsets.top,
Winson147ecaf2015-09-16 16:49:55 -0700290 searchBarSpaceBounds);
Winson Chungf7bca432014-04-30 17:11:13 -0700291 mSearchBar.measure(
292 MeasureSpec.makeMeasureSpec(searchBarSpaceBounds.width(), MeasureSpec.EXACTLY),
293 MeasureSpec.makeMeasureSpec(searchBarSpaceBounds.height(), MeasureSpec.EXACTLY));
Winson Chungecd9b302014-04-16 17:07:18 -0700294 }
295
Winson Chungf7bca432014-04-30 17:11:13 -0700296 Rect taskStackBounds = new Rect();
Winson53ec42c2015-10-28 15:55:35 -0700297 config.getTaskStackBounds(new Rect(0, 0, width, height), mSystemInsets.top,
Winson35f30502015-09-28 11:24:36 -0700298 mSystemInsets.right, searchBarSpaceBounds, taskStackBounds);
Winson147ecaf2015-09-16 16:49:55 -0700299 if (mTaskStackView != null && mTaskStackView.getVisibility() != GONE) {
Winson88f00ab2015-10-05 17:24:00 -0700300 mTaskStackView.setTaskStackBounds(taskStackBounds, mSystemInsets);
Winson147ecaf2015-09-16 16:49:55 -0700301 mTaskStackView.measure(widthMeasureSpec, heightMeasureSpec);
Winson Chung303e1ff2014-03-07 15:06:19 -0800302 }
303
Winsonbe7607a2015-10-01 17:24:51 -0700304 if (mDragView != null) {
Winsoneca4ab62015-11-04 10:50:28 -0800305 Rect taskRect = mTaskStackView.mLayoutAlgorithm.mTaskRect;
Winsonbe7607a2015-10-01 17:24:51 -0700306 mDragView.measure(
Winsoneca4ab62015-11-04 10:50:28 -0800307 MeasureSpec.makeMeasureSpec(taskRect.width(), MeasureSpec.AT_MOST),
308 MeasureSpec.makeMeasureSpec(taskRect.height(), MeasureSpec.AT_MOST));
Winsonbe7607a2015-10-01 17:24:51 -0700309 }
310
Winson Chung303e1ff2014-03-07 15:06:19 -0800311 setMeasuredDimension(width, height);
312 }
313
Winson Chungf7bca432014-04-30 17:11:13 -0700314 /**
315 * This is called with the full size of the window since we are handling our own insets.
316 */
Winson Chung303e1ff2014-03-07 15:06:19 -0800317 @Override
318 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
Winson53ec42c2015-10-28 15:55:35 -0700319 RecentsConfiguration config = Recents.getConfiguration();
320
Winson Chungf7bca432014-04-30 17:11:13 -0700321 // Get the search bar bounds so that we lay it out
Winson147ecaf2015-09-16 16:49:55 -0700322 Rect measuredRect = new Rect(0, 0, getMeasuredWidth(), getMeasuredHeight());
323 Rect searchBarSpaceBounds = new Rect();
Winson Chungecd9b302014-04-16 17:07:18 -0700324 if (mSearchBar != null) {
Winson53ec42c2015-10-28 15:55:35 -0700325 config.getSearchBarBounds(measuredRect,
Winson35f30502015-09-28 11:24:36 -0700326 mSystemInsets.top, searchBarSpaceBounds);
Winson Chungdcfa7972014-07-22 12:27:13 -0700327 mSearchBar.layout(searchBarSpaceBounds.left, searchBarSpaceBounds.top,
328 searchBarSpaceBounds.right, searchBarSpaceBounds.bottom);
Winson Chungecd9b302014-04-16 17:07:18 -0700329 }
330
Winson147ecaf2015-09-16 16:49:55 -0700331 if (mTaskStackView != null && mTaskStackView.getVisibility() != GONE) {
332 mTaskStackView.layout(left, top, left + getMeasuredWidth(), top + getMeasuredHeight());
Winson Chung303e1ff2014-03-07 15:06:19 -0800333 }
Winsonbe7607a2015-10-01 17:24:51 -0700334
335 if (mDragView != null) {
336 mDragView.layout(left, top, left + mDragView.getMeasuredWidth(),
337 top + mDragView.getMeasuredHeight());
338 }
Winson Chung303e1ff2014-03-07 15:06:19 -0800339 }
340
Winson Chung8eaeb7d2014-06-25 15:10:59 -0700341 @Override
Winson Chung8eaeb7d2014-06-25 15:10:59 -0700342 public WindowInsets onApplyWindowInsets(WindowInsets insets) {
Winson35f30502015-09-28 11:24:36 -0700343 mSystemInsets.set(insets.getSystemWindowInsets());
Winson Chung8eaeb7d2014-06-25 15:10:59 -0700344 requestLayout();
Winson Chungdcfa7972014-07-22 12:27:13 -0700345 return insets.consumeSystemWindowInsets();
Winson Chung8eaeb7d2014-06-25 15:10:59 -0700346 }
347
Winsonbe7607a2015-10-01 17:24:51 -0700348 @Override
349 public boolean onInterceptTouchEvent(MotionEvent ev) {
350 return mTouchHandler.onInterceptTouchEvent(ev);
351 }
352
353 @Override
354 public boolean onTouchEvent(MotionEvent ev) {
355 return mTouchHandler.onTouchEvent(ev);
356 }
357
358 @Override
359 protected void dispatchDraw(Canvas canvas) {
360 super.dispatchDraw(canvas);
Winson882072b2015-10-12 11:26:33 -0700361 for (int i = mVisibleDockStates.length - 1; i >= 0; i--) {
362 Drawable d = mVisibleDockStates[i].viewState.dockAreaOverlay;
363 if (d.getAlpha() > 0) {
364 d.draw(canvas);
365 }
Winsonbe7607a2015-10-01 17:24:51 -0700366 }
367 }
368
Winson4165d3362015-10-10 14:40:35 -0700369 @Override
370 protected boolean verifyDrawable(Drawable who) {
Winson882072b2015-10-12 11:26:33 -0700371 for (int i = mVisibleDockStates.length - 1; i >= 0; i--) {
372 Drawable d = mVisibleDockStates[i].viewState.dockAreaOverlay;
373 if (d == who) {
374 return true;
375 }
376 }
377 return super.verifyDrawable(who);
Winson4165d3362015-10-10 14:40:35 -0700378 }
379
Winson Chung303e1ff2014-03-07 15:06:19 -0800380 /** Unfilters any filtered stacks */
381 public boolean unfilterFilteredStacks() {
Winson Chungdcfa7972014-07-22 12:27:13 -0700382 if (mStacks != null) {
Winson Chung303e1ff2014-03-07 15:06:19 -0800383 // Check if there are any filtered stacks and unfilter them before we back out of Recents
384 boolean stacksUnfiltered = false;
Winson Chungdcfa7972014-07-22 12:27:13 -0700385 int numStacks = mStacks.size();
386 for (int i = 0; i < numStacks; i++) {
387 TaskStack stack = mStacks.get(i);
Winson Chung303e1ff2014-03-07 15:06:19 -0800388 if (stack.hasFilteredTasks()) {
389 stack.unfilterTasks();
390 stacksUnfiltered = true;
391 }
392 }
393 return stacksUnfiltered;
394 }
395 return false;
396 }
397
Jorim Jaggi900fb482015-06-02 15:07:33 -0700398 public void disableLayersForOneFrame() {
Winson147ecaf2015-09-16 16:49:55 -0700399 if (mTaskStackView != null) {
400 mTaskStackView.disableLayersForOneFrame();
Jorim Jaggi900fb482015-06-02 15:07:33 -0700401 }
402 }
403
Winson Chung47c4c692014-03-17 10:17:11 -0700404 /**** TaskStackView.TaskStackCallbacks Implementation ****/
Winson Chung303e1ff2014-03-07 15:06:19 -0800405
406 @Override
Winson Chung7aceb9a2014-07-03 13:38:01 -0700407 public void onTaskViewClicked(final TaskStackView stackView, final TaskView tv,
Filip Gruszczynskif48b5852015-10-13 10:28:22 -0700408 final TaskStack stack, final Task task, final boolean lockToTask,
Winson83c1b072015-11-09 10:48:04 -0800409 final Rect bounds, int destinationStack) {
410 mTransitionHelper.launchTaskFromRecents(stack, task, stackView, tv, lockToTask, bounds,
411 destinationStack);
Winson Chung303e1ff2014-03-07 15:06:19 -0800412 }
Winson Chung9f9679d2014-04-11 16:49:09 -0700413
414 @Override
Winson Chung6ac8bd62015-01-07 16:38:35 -0800415 public void onAllTaskViewsDismissed(ArrayList<Task> removedTasks) {
Winson2536c7e2015-10-01 15:49:31 -0700416 /* TODO: Not currently enabled
Winson Chung6ac8bd62015-01-07 16:38:35 -0800417 if (removedTasks != null) {
418 int taskCount = removedTasks.size();
419 for (int i = 0; i < taskCount; i++) {
420 onTaskViewDismissed(removedTasks.get(i));
421 }
422 }
Winson2536c7e2015-10-01 15:49:31 -0700423 */
Winson Chung6ac8bd62015-01-07 16:38:35 -0800424
Winson Chung7aceb9a2014-07-03 13:38:01 -0700425 mCb.onAllTaskViewsDismissed();
Winson Chung5c9f4b92015-06-25 16:16:46 -0700426
427 // Keep track of all-deletions
428 MetricsLogger.count(getContext(), "overview_task_all_dismissed", 1);
Winson Chungd7b2cb12014-06-26 15:08:50 -0700429 }
430
431 @Override
Winson Chung8e548f72014-06-24 14:40:53 -0700432 public void onTaskStackFilterTriggered() {
433 // Hide the search bar
434 if (mSearchBar != null) {
Winson35f30502015-09-28 11:24:36 -0700435 int filterDuration = getResources().getInteger(
436 R.integer.recents_filter_animate_current_views_duration);
Winson Chung8e548f72014-06-24 14:40:53 -0700437 mSearchBar.animate()
438 .alpha(0f)
439 .setStartDelay(0)
Winson35f30502015-09-28 11:24:36 -0700440 .setInterpolator(mFastOutSlowInInterpolator)
441 .setDuration(filterDuration)
Winson Chung8e548f72014-06-24 14:40:53 -0700442 .withLayer()
443 .start();
444 }
445 }
446
447 @Override
448 public void onTaskStackUnfilterTriggered() {
449 // Show the search bar
450 if (mSearchBar != null) {
Winson35f30502015-09-28 11:24:36 -0700451 int filterDuration = getResources().getInteger(
452 R.integer.recents_filter_animate_new_views_duration);
Winson Chung8e548f72014-06-24 14:40:53 -0700453 mSearchBar.animate()
454 .alpha(1f)
455 .setStartDelay(0)
Winson35f30502015-09-28 11:24:36 -0700456 .setInterpolator(mFastOutSlowInInterpolator)
457 .setDuration(filterDuration)
Winson Chung8e548f72014-06-24 14:40:53 -0700458 .withLayer()
459 .start();
460 }
461 }
Winsonbe7607a2015-10-01 17:24:51 -0700462
463 /**** EventBus Events ****/
464
465 public final void onBusEvent(DragStartEvent event) {
466 // Add the drag view
467 mDragView = event.dragView;
468 addView(mDragView);
Winson4165d3362015-10-10 14:40:35 -0700469
Winson882072b2015-10-12 11:26:33 -0700470 updateVisibleDockRegions(mTouchHandler.getDockStatesForCurrentOrientation(),
471 TaskStack.DockState.NONE.viewState.dockAreaAlpha);
Winsonbe7607a2015-10-01 17:24:51 -0700472 }
473
Winsoneca4ab62015-11-04 10:50:28 -0800474 public final void onBusEvent(DragDropTargetChangedEvent event) {
475 if (event.dropTarget == null || !(event.dropTarget instanceof TaskStack.DockState)) {
Winson882072b2015-10-12 11:26:33 -0700476 updateVisibleDockRegions(mTouchHandler.getDockStatesForCurrentOrientation(),
477 TaskStack.DockState.NONE.viewState.dockAreaAlpha);
478 } else {
Winsoneca4ab62015-11-04 10:50:28 -0800479 final TaskStack.DockState dockState = (TaskStack.DockState) event.dropTarget;
480 updateVisibleDockRegions(new TaskStack.DockState[] {dockState}, -1);
Winson882072b2015-10-12 11:26:33 -0700481 }
Winsonbe7607a2015-10-01 17:24:51 -0700482 }
483
484 public final void onBusEvent(final DragEndEvent event) {
Winsoneca4ab62015-11-04 10:50:28 -0800485 final Runnable cleanUpRunnable = new Runnable() {
Winsonbe7607a2015-10-01 17:24:51 -0700486 @Override
487 public void run() {
488 // Remove the drag view
489 removeView(mDragView);
490 mDragView = null;
Winsonbe7607a2015-10-01 17:24:51 -0700491 }
Winsoneca4ab62015-11-04 10:50:28 -0800492 };
493
494 // Animate the overlay alpha back to 0
495 updateVisibleDockRegions(null, -1);
496
497 if (event.dropTarget == null) {
498 // No drop targets for hit, so just animate the task back to its place
499 event.postAnimationTrigger.increment();
500 event.postAnimationTrigger.addLastDecrementRunnable(new Runnable() {
501 @Override
502 public void run() {
503 cleanUpRunnable.run();
504 }
505 });
506 // Animate the task back to where it was before then clean up afterwards
507 TaskViewTransform taskTransform = new TaskViewTransform();
508 TaskStackLayoutAlgorithm layoutAlgorithm = mTaskStackView.getStackAlgorithm();
509 layoutAlgorithm.getStackTransform(event.task,
510 mTaskStackView.getScroller().getStackScroll(), taskTransform, null);
Winsonbe7607a2015-10-01 17:24:51 -0700511 event.dragView.animate()
Winsoneca4ab62015-11-04 10:50:28 -0800512 .scaleX(taskTransform.scale)
513 .scaleY(taskTransform.scale)
514 .translationX((layoutAlgorithm.mTaskRect.left - event.dragView.getLeft())
515 + taskTransform.translationX)
516 .translationY((layoutAlgorithm.mTaskRect.top - event.dragView.getTop())
517 + taskTransform.translationY)
Winsonbe7607a2015-10-01 17:24:51 -0700518 .setDuration(175)
Winson4165d3362015-10-10 14:40:35 -0700519 .setInterpolator(mFastOutSlowInInterpolator)
Winsonbe7607a2015-10-01 17:24:51 -0700520 .withEndAction(event.postAnimationTrigger.decrementAsRunnable())
Winsonbe7607a2015-10-01 17:24:51 -0700521 .start();
Winson4165d3362015-10-10 14:40:35 -0700522
Winsoneca4ab62015-11-04 10:50:28 -0800523 } else if (event.dropTarget instanceof TaskStack.DockState) {
524 final TaskStack.DockState dockState = (TaskStack.DockState) event.dropTarget;
525
526 // For now, just remove the drag view and the original task
527 // TODO: Animate the task to the drop target rect before launching it above
528 cleanUpRunnable.run();
529
530 // Dock the task and launch it
531 SystemServicesProxy ssp = Recents.getSystemServices();
532 ssp.startTaskInDockedMode(event.task.key.id, dockState.createMode);
533 launchTask(event.task, null, INVALID_STACK_ID);
534
Winsonbe7607a2015-10-01 17:24:51 -0700535 } else {
Winsoneca4ab62015-11-04 10:50:28 -0800536 // We dropped on another drop target, so just add the cleanup to the post animation
537 // trigger
538 event.postAnimationTrigger.addLastDecrementRunnable(new Runnable() {
539 @Override
540 public void run() {
541 cleanUpRunnable.run();
542 }
543 });
Winsonbe7607a2015-10-01 17:24:51 -0700544 }
545 }
Winson4165d3362015-10-10 14:40:35 -0700546
Jorim Jaggidd98d412015-11-18 15:57:38 -0800547 public final void onBusEvent(DraggingInRecentsEvent event) {
548 setStackViewVisibility(View.VISIBLE);
549 setTranslationY(event.distanceFromTop - mTaskStackView.getTaskViews().get(0).getY());
550 }
551
552 public final void onBusEvent(DraggingInRecentsEndedEvent event) {
553 animate().translationY(0f);
554 }
555
Winson4165d3362015-10-10 14:40:35 -0700556 /**
557 * Updates the dock region to match the specified dock state.
558 */
Winson882072b2015-10-12 11:26:33 -0700559 private void updateVisibleDockRegions(TaskStack.DockState[] newDockStates, int overrideAlpha) {
560 ArraySet<TaskStack.DockState> newDockStatesSet = new ArraySet<>();
561 if (newDockStates != null) {
562 for (TaskStack.DockState dockState : newDockStates) {
563 newDockStatesSet.add(dockState);
564 }
Winson4165d3362015-10-10 14:40:35 -0700565 }
Winson882072b2015-10-12 11:26:33 -0700566 for (TaskStack.DockState dockState : mVisibleDockStates) {
567 TaskStack.DockState.ViewState viewState = dockState.viewState;
568 if (newDockStates == null || !newDockStatesSet.contains(dockState)) {
569 // This is no longer visible, so hide it
570 viewState.startAlphaAnimation(0, 150);
571 } else {
572 // This state is now visible, update the bounds and show it
573 int alpha = (overrideAlpha != -1 ? overrideAlpha : viewState.dockAreaAlpha);
574 viewState.dockAreaOverlay.setBounds(
575 dockState.getDockedBounds(getMeasuredWidth(), getMeasuredHeight()));
576 viewState.dockAreaOverlay.setCallback(this);
577 viewState.startAlphaAnimation(alpha, 150);
578 }
Winson4165d3362015-10-10 14:40:35 -0700579 }
Winson4165d3362015-10-10 14:40:35 -0700580 }
Filip Gruszczynski14b4e572015-11-03 15:53:55 -0800581
582 public void setStackViewVisibility(int stackViewVisibility) {
583 mStackViewVisibility = stackViewVisibility;
584 if (mTaskStackView != null) {
585 mTaskStackView.setVisibility(stackViewVisibility);
586 invalidate();
587 }
588 }
Winson Chung303e1ff2014-03-07 15:06:19 -0800589}