blob: 87a68461eff069a7344f6a570e26156d01dbf34c [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
Winson70f0bf72016-02-01 14:05:29 -080019import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
20import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
21import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
22
Winsona78a8f32015-12-03 10:55:01 -080023import android.animation.ObjectAnimator;
Winson Chungbf5dbf12014-09-16 00:58:25 +020024import android.animation.ValueAnimator;
Winson619e40c2016-03-25 16:12:35 -070025import android.annotation.IntDef;
Winson Chung9f49df92014-05-07 18:08:34 -070026import android.content.ComponentName;
Winson Chung303e1ff2014-03-07 15:06:19 -080027import android.content.Context;
Winsonfc48b072016-04-21 11:20:11 -070028import android.content.res.Configuration;
Winsonbb410952015-12-04 14:34:11 -080029import android.content.res.Resources;
Jorim Jaggi900fb482015-06-02 15:07:33 -070030import android.graphics.Canvas;
Winson Chung303e1ff2014-03-07 15:06:19 -080031import android.graphics.Rect;
Winsona78a8f32015-12-03 10:55:01 -080032import android.graphics.drawable.Drawable;
Winsonde0591a2015-12-04 17:24:35 -080033import android.graphics.drawable.GradientDrawable;
Winson Chung83ea6f72015-06-17 13:00:23 -070034import android.os.Bundle;
Winson Chung931c51f2015-12-17 17:08:55 -050035import android.provider.Settings;
Winson55003902016-01-12 12:00:37 -080036import android.util.ArrayMap;
37import android.util.ArraySet;
Winson8aa99592016-01-19 15:07:07 -080038import android.util.MutableBoolean;
Winson Chung37c8d8e2014-03-24 14:53:07 -070039import android.view.LayoutInflater;
Winson Chung303e1ff2014-03-07 15:06:19 -080040import android.view.MotionEvent;
Winson Chung303e1ff2014-03-07 15:06:19 -080041import android.view.View;
Winson231bc9c2016-02-09 12:31:00 -080042import android.view.ViewDebug;
Winson70f0bf72016-02-01 14:05:29 -080043import android.view.ViewGroup;
Winson Chungee445952014-09-09 16:12:59 +020044import android.view.accessibility.AccessibilityEvent;
Winson Chung83ea6f72015-06-17 13:00:23 -070045import android.view.accessibility.AccessibilityNodeInfo;
Winson Chung303e1ff2014-03-07 15:06:19 -080046import android.widget.FrameLayout;
Winsonf0009882016-06-01 12:22:55 -070047import android.widget.ScrollView;
Winsonc0d70582016-01-29 10:24:39 -080048
Winson42329522016-02-05 10:39:46 -080049import com.android.internal.logging.MetricsLogger;
50import com.android.internal.logging.MetricsProto.MetricsEvent;
Winsonc0d70582016-01-29 10:24:39 -080051import com.android.systemui.Interpolators;
Winson Chungc6a16232014-04-01 14:04:48 -070052import com.android.systemui.R;
Winsone7f138c2015-10-22 16:15:21 -070053import com.android.systemui.recents.Recents;
Winsone6c90732015-09-24 16:06:29 -070054import com.android.systemui.recents.RecentsActivity;
Winson2536c7e2015-10-01 15:49:31 -070055import com.android.systemui.recents.RecentsActivityLaunchState;
Winson Chung303e1ff2014-03-07 15:06:19 -080056import com.android.systemui.recents.RecentsConfiguration;
Winson4b9cded2016-01-26 16:26:47 -080057import com.android.systemui.recents.RecentsDebugFlags;
Winsone6c90732015-09-24 16:06:29 -070058import com.android.systemui.recents.events.EventBus;
Winsone5f1faa2015-11-20 12:26:23 -080059import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent;
Winsone693aaf2016-03-01 12:05:59 -080060import com.android.systemui.recents.events.activity.ConfigurationChangedEvent;
Winsonef064132016-01-05 12:11:31 -080061import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
Winson4b9cded2016-01-26 16:26:47 -080062import com.android.systemui.recents.events.activity.EnterRecentsTaskStackAnimationCompletedEvent;
Winsone5f1faa2015-11-20 12:26:23 -080063import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent;
Winsonbc0f8cd2016-03-15 15:44:48 -070064import com.android.systemui.recents.events.activity.HideRecentsEvent;
Winsonc69249f2016-03-28 13:38:39 -070065import com.android.systemui.recents.events.activity.HideStackActionButtonEvent;
Winson8b1871d2015-11-20 09:56:20 -080066import com.android.systemui.recents.events.activity.IterateRecentsEvent;
Winsonb61e6542016-02-04 14:37:18 -080067import com.android.systemui.recents.events.activity.LaunchNextTaskRequestEvent;
Winson Chung48f2cda2015-12-11 13:20:12 -050068import com.android.systemui.recents.events.activity.LaunchTaskEvent;
Winsonef064132016-01-05 12:11:31 -080069import com.android.systemui.recents.events.activity.LaunchTaskStartedEvent;
Winson88737542016-02-17 13:27:33 -080070import com.android.systemui.recents.events.activity.MultiWindowStateChangedEvent;
Winsone6c90732015-09-24 16:06:29 -070071import com.android.systemui.recents.events.activity.PackagesChangedEvent;
Winson8f6ee482016-03-18 17:51:48 -070072import com.android.systemui.recents.events.activity.ShowStackActionButtonEvent;
Winson397ae742015-11-20 11:27:33 -080073import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent;
Winsonef064132016-01-05 12:11:31 -080074import com.android.systemui.recents.events.ui.DeleteTaskDataEvent;
Winson3b6ba1a2016-03-22 15:37:54 -070075import com.android.systemui.recents.events.ui.DismissAllTaskViewsEvent;
Winson0d14d4d2015-10-26 17:05:04 -070076import com.android.systemui.recents.events.ui.DismissTaskViewEvent;
Jorim Jaggidb21bbd2016-04-18 15:32:07 -070077import com.android.systemui.recents.events.ui.RecentsGrowingEvent;
Winsonef064132016-01-05 12:11:31 -080078import com.android.systemui.recents.events.ui.TaskViewDismissedEvent;
Winsonb1e71d02015-11-23 12:40:23 -080079import com.android.systemui.recents.events.ui.UpdateFreeformTaskViewVisibilityEvent;
Winsone7f138c2015-10-22 16:15:21 -070080import com.android.systemui.recents.events.ui.UserInteractionEvent;
Winsoneca4ab62015-11-04 10:50:28 -080081import com.android.systemui.recents.events.ui.dragndrop.DragDropTargetChangedEvent;
82import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
Winson27c28f82016-05-05 16:16:50 -070083import com.android.systemui.recents.events.ui.dragndrop.DragEndCancelledEvent;
Winsoneca4ab62015-11-04 10:50:28 -080084import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
85import com.android.systemui.recents.events.ui.dragndrop.DragStartInitializeDropTargetsEvent;
Winson0d14d4d2015-10-26 17:05:04 -070086import com.android.systemui.recents.events.ui.focus.DismissFocusedTaskViewEvent;
87import com.android.systemui.recents.events.ui.focus.FocusNextTaskViewEvent;
88import com.android.systemui.recents.events.ui.focus.FocusPreviousTaskViewEvent;
Winson Chungffa2ec62014-07-03 15:54:42 -070089import com.android.systemui.recents.misc.DozeTrigger;
Winson Chungee445952014-09-09 16:12:59 +020090import com.android.systemui.recents.misc.SystemServicesProxy;
Winson Chungbf5dbf12014-09-16 00:58:25 +020091import com.android.systemui.recents.misc.Utilities;
Winson Chung303e1ff2014-03-07 15:06:19 -080092import com.android.systemui.recents.model.Task;
93import com.android.systemui.recents.model.TaskStack;
Winson Chung303e1ff2014-03-07 15:06:19 -080094
Manu Cornetbf8e2902016-12-20 08:29:33 -080095import com.android.systemui.recents.views.grid.GridTaskView;
Winsond72c3152016-04-05 15:33:35 -070096import java.io.PrintWriter;
Winson619e40c2016-03-25 16:12:35 -070097import java.lang.annotation.Retention;
98import java.lang.annotation.RetentionPolicy;
Winson Chung303e1ff2014-03-07 15:06:19 -080099import java.util.ArrayList;
Winson Chung6ac8bd62015-01-07 16:38:35 -0800100import java.util.List;
Winson Chung303e1ff2014-03-07 15:06:19 -0800101
Winson Chung303e1ff2014-03-07 15:06:19 -0800102
103/* The visual representation of a task stack view */
Winson Chung04dfe0d2014-03-14 14:06:29 -0700104public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCallbacks,
Winson Chung012ef362014-07-31 18:36:25 -0700105 TaskView.TaskViewCallbacks, TaskStackViewScroller.TaskStackViewScrollerCallbacks,
Winson1c846142016-01-22 11:34:38 -0800106 TaskStackLayoutAlgorithm.TaskStackLayoutAlgorithmCallbacks,
Winsone6c90732015-09-24 16:06:29 -0700107 ViewPool.ViewPoolConsumer<TaskView, Task> {
Winson Chung04dfe0d2014-03-14 14:06:29 -0700108
Winsond72c3152016-04-05 15:33:35 -0700109 private static final String TAG = "TaskStackView";
110
Winson8f6ee482016-03-18 17:51:48 -0700111 // The thresholds at which to show/hide the stack action button.
112 private static final float SHOW_STACK_ACTION_BUTTON_SCROLL_THRESHOLD = 0.3f;
113 private static final float HIDE_STACK_ACTION_BUTTON_SCROLL_THRESHOLD = 0.3f;
Winsonc29ff002015-11-20 16:00:45 -0800114
Winson8aa99592016-01-19 15:07:07 -0800115 public static final int DEFAULT_SYNC_STACK_DURATION = 200;
Winson3f32e7e2016-04-20 17:18:08 -0700116 public static final int SLOW_SYNC_STACK_DURATION = 250;
Winsonf24f2162016-01-05 12:11:55 -0800117 private static final int DRAG_SCALE_DURATION = 175;
Jorim Jaggi0b46f3c2016-03-14 12:21:37 +0100118 static final float DRAG_SCALE_FACTOR = 1.05f;
Winson Chung06266772015-12-11 10:24:21 -0500119
Winsonf8597b22016-03-23 18:44:26 -0700120 private static final int LAUNCH_NEXT_SCROLL_BASE_DURATION = 216;
Winson96e61342016-03-15 16:47:19 -0700121 private static final int LAUNCH_NEXT_SCROLL_INCR_DURATION = 32;
122
Winson619e40c2016-03-25 16:12:35 -0700123 // The actions to perform when resetting to initial state,
124 @Retention(RetentionPolicy.SOURCE)
125 @IntDef({INITIAL_STATE_UPDATE_NONE, INITIAL_STATE_UPDATE_ALL, INITIAL_STATE_UPDATE_LAYOUT_ONLY})
126 public @interface InitialStateAction {}
127 /** Do not update the stack and layout to the initial state. */
128 private static final int INITIAL_STATE_UPDATE_NONE = 0;
129 /** Update both the stack and layout to the initial state. */
130 private static final int INITIAL_STATE_UPDATE_ALL = 1;
131 /** Update only the layout to the initial state. */
132 private static final int INITIAL_STATE_UPDATE_LAYOUT_ONLY = 2;
133
Winsonfc48b072016-04-21 11:20:11 -0700134 private LayoutInflater mInflater;
135 private TaskStack mStack = new TaskStack();
Winson231bc9c2016-02-09 12:31:00 -0800136 @ViewDebug.ExportedProperty(deepExport=true, prefix="layout_")
Winson36a5a2c2015-10-29 18:04:39 -0700137 TaskStackLayoutAlgorithm mLayoutAlgorithm;
Winsonf9357d92016-03-25 15:14:37 -0700138 // The stable layout algorithm is only used to calculate the task rect with the stable bounds
Winsonfc48b072016-04-21 11:20:11 -0700139 private TaskStackLayoutAlgorithm mStableLayoutAlgorithm;
Winson231bc9c2016-02-09 12:31:00 -0800140 @ViewDebug.ExportedProperty(deepExport=true, prefix="scroller_")
Winsonfc48b072016-04-21 11:20:11 -0700141 private TaskStackViewScroller mStackScroller;
Winson231bc9c2016-02-09 12:31:00 -0800142 @ViewDebug.ExportedProperty(deepExport=true, prefix="touch_")
Winsonfc48b072016-04-21 11:20:11 -0700143 private TaskStackViewTouchHandler mTouchHandler;
144 private TaskStackAnimationHelper mAnimationHelper;
145 private GradientDrawable mFreeformWorkspaceBackground;
146 private ObjectAnimator mFreeformWorkspaceBackgroundAnimator;
147 private ViewPool<TaskView, Task> mViewPool;
Winsonf24f2162016-01-05 12:11:55 -0800148
Winsonfc48b072016-04-21 11:20:11 -0700149 private ArrayList<TaskView> mTaskViews = new ArrayList<>();
150 private ArrayList<TaskViewTransform> mCurrentTaskTransforms = new ArrayList<>();
151 private ArraySet<Task.TaskKey> mIgnoreTasks = new ArraySet<>();
152 private AnimationProps mDeferredTaskViewLayoutAnimation = null;
Winsonf24f2162016-01-05 12:11:55 -0800153
Winson231bc9c2016-02-09 12:31:00 -0800154 @ViewDebug.ExportedProperty(deepExport=true, prefix="doze_")
Winsonfc48b072016-04-21 11:20:11 -0700155 private DozeTrigger mUIDozeTrigger;
Winson231bc9c2016-02-09 12:31:00 -0800156 @ViewDebug.ExportedProperty(deepExport=true, prefix="focused_task_")
Winsonfc48b072016-04-21 11:20:11 -0700157 private Task mFocusedTask;
Winsonf24f2162016-01-05 12:11:55 -0800158
Winsonfc48b072016-04-21 11:20:11 -0700159 private int mTaskCornerRadiusPx;
Winson3e874742016-01-07 10:08:17 -0800160 private int mDividerSize;
Winson4b9cded2016-01-26 16:26:47 -0800161 private int mStartTimerIndicatorDuration;
Winsonf24f2162016-01-05 12:11:55 -0800162
Winson231bc9c2016-02-09 12:31:00 -0800163 @ViewDebug.ExportedProperty(category="recents")
Winsonfc48b072016-04-21 11:20:11 -0700164 private boolean mTaskViewsClipDirty = true;
Winson231bc9c2016-02-09 12:31:00 -0800165 @ViewDebug.ExportedProperty(category="recents")
Winsonfc48b072016-04-21 11:20:11 -0700166 private boolean mAwaitingFirstLayout = true;
Winson231bc9c2016-02-09 12:31:00 -0800167 @ViewDebug.ExportedProperty(category="recents")
Winsonbd53a312016-09-21 12:13:32 -0700168 private boolean mLaunchNextAfterFirstMeasure = false;
169 @ViewDebug.ExportedProperty(category="recents")
Winson619e40c2016-03-25 16:12:35 -0700170 @InitialStateAction
Winsonfc48b072016-04-21 11:20:11 -0700171 private int mInitialState = INITIAL_STATE_UPDATE_ALL;
Winson619e40c2016-03-25 16:12:35 -0700172 @ViewDebug.ExportedProperty(category="recents")
Winsonfc48b072016-04-21 11:20:11 -0700173 private boolean mInMeasureLayout = false;
Winson231bc9c2016-02-09 12:31:00 -0800174 @ViewDebug.ExportedProperty(category="recents")
Winsonfc48b072016-04-21 11:20:11 -0700175 private boolean mEnterAnimationComplete = false;
Winson231bc9c2016-02-09 12:31:00 -0800176 @ViewDebug.ExportedProperty(category="recents")
Winsonf0009882016-06-01 12:22:55 -0700177 boolean mTouchExplorationEnabled;
Winson231bc9c2016-02-09 12:31:00 -0800178 @ViewDebug.ExportedProperty(category="recents")
Winsonf24f2162016-01-05 12:11:55 -0800179 boolean mScreenPinningEnabled;
Winson3150e572015-10-23 15:07:24 -0700180
Winson3e874742016-01-07 10:08:17 -0800181 // The stable stack bounds are the full bounds that we were measured with from RecentsView
Winson231bc9c2016-02-09 12:31:00 -0800182 @ViewDebug.ExportedProperty(category="recents")
Winson05e46ca2016-02-05 15:40:29 -0800183 private Rect mStableStackBounds = new Rect();
Winson3e874742016-01-07 10:08:17 -0800184 // The current stack bounds are dynamic and may change as the user drags and drops
Winson231bc9c2016-02-09 12:31:00 -0800185 @ViewDebug.ExportedProperty(category="recents")
Winson05e46ca2016-02-05 15:40:29 -0800186 private Rect mStackBounds = new Rect();
Winson59924fe2016-03-17 14:13:18 -0700187 // The current window bounds at the point we were measured
188 @ViewDebug.ExportedProperty(category="recents")
189 private Rect mStableWindowRect = new Rect();
190 // The current window bounds are dynamic and may change as the user drags and drops
191 @ViewDebug.ExportedProperty(category="recents")
192 private Rect mWindowRect = new Rect();
Winsonfc48b072016-04-21 11:20:11 -0700193 // The current display bounds
194 @ViewDebug.ExportedProperty(category="recents")
195 private Rect mDisplayRect = new Rect();
196 // The current display orientation
197 @ViewDebug.ExportedProperty(category="recents")
198 private int mDisplayOrientation = Configuration.ORIENTATION_UNDEFINED;
Winsond9529612016-01-28 13:29:49 -0800199
Winson05e46ca2016-02-05 15:40:29 -0800200 private Rect mTmpRect = new Rect();
201 private ArrayMap<Task.TaskKey, TaskView> mTmpTaskViewMap = new ArrayMap<>();
202 private List<TaskView> mTmpTaskViews = new ArrayList<>();
203 private TaskViewTransform mTmpTransform = new TaskViewTransform();
Winsonc4387022016-02-24 12:05:26 -0800204 private int[] mTmpIntPair = new int[2];
Jorim Jaggidb21bbd2016-04-18 15:32:07 -0700205 private boolean mResetToInitialStateWhenResized;
206 private int mLastWidth;
207 private int mLastHeight;
Winson Chung931c51f2015-12-17 17:08:55 -0500208
Winson Chungbf5dbf12014-09-16 00:58:25 +0200209 // A convenience update listener to request updating clipping of tasks
Winsoneca4ab62015-11-04 10:50:28 -0800210 private ValueAnimator.AnimatorUpdateListener mRequestUpdateClippingListener =
Winson Chungbf5dbf12014-09-16 00:58:25 +0200211 new ValueAnimator.AnimatorUpdateListener() {
Winson5b7dd532015-12-01 16:02:12 -0800212 @Override
213 public void onAnimationUpdate(ValueAnimator animation) {
Winson55003902016-01-12 12:00:37 -0800214 if (!mTaskViewsClipDirty) {
215 mTaskViewsClipDirty = true;
216 invalidate();
217 }
Winson5b7dd532015-12-01 16:02:12 -0800218 }
219 };
Winson Chungbf5dbf12014-09-16 00:58:25 +0200220
Winsoneca4ab62015-11-04 10:50:28 -0800221 // The drop targets for a task drag
222 private DropTarget mFreeformWorkspaceDropTarget = new DropTarget() {
223 @Override
Winson08deff02016-08-05 13:58:31 -0700224 public boolean acceptsDrop(int x, int y, int width, int height, Rect insets,
225 boolean isCurrentTarget) {
Winson3e874742016-01-07 10:08:17 -0800226 // This drop target has a fixed bounds and should be checked last, so just fall through
227 // if it is the current target
228 if (!isCurrentTarget) {
229 return mLayoutAlgorithm.mFreeformRect.contains(x, y);
230 }
231 return false;
Winsoneca4ab62015-11-04 10:50:28 -0800232 }
233 };
234
235 private DropTarget mStackDropTarget = new DropTarget() {
236 @Override
Winson08deff02016-08-05 13:58:31 -0700237 public boolean acceptsDrop(int x, int y, int width, int height, Rect insets,
238 boolean isCurrentTarget) {
Winson3e874742016-01-07 10:08:17 -0800239 // This drop target has a fixed bounds and should be checked last, so just fall through
240 // if it is the current target
241 if (!isCurrentTarget) {
242 return mLayoutAlgorithm.mStackRect.contains(x, y);
243 }
244 return false;
Winsoneca4ab62015-11-04 10:50:28 -0800245 }
246 };
247
Winson88737542016-02-17 13:27:33 -0800248 public TaskStackView(Context context) {
Winson Chung303e1ff2014-03-07 15:06:19 -0800249 super(context);
Winsonde0591a2015-12-04 17:24:35 -0800250 SystemServicesProxy ssp = Recents.getSystemServices();
Winsonbb410952015-12-04 14:34:11 -0800251 Resources res = context.getResources();
252
Winson Chungb0a28ea2014-10-28 15:21:35 -0700253 // Set the stack first
Winson88737542016-02-17 13:27:33 -0800254 mStack.setCallbacks(this);
Winson35f30502015-09-28 11:24:36 -0700255 mViewPool = new ViewPool<>(context, this);
Winson Chung37c8d8e2014-03-24 14:53:07 -0700256 mInflater = LayoutInflater.from(context);
Winson1c846142016-01-22 11:34:38 -0800257 mLayoutAlgorithm = new TaskStackLayoutAlgorithm(context, this);
Winsonf9357d92016-03-25 15:14:37 -0700258 mStableLayoutAlgorithm = new TaskStackLayoutAlgorithm(context, null);
Winson1c846142016-01-22 11:34:38 -0800259 mStackScroller = new TaskStackViewScroller(context, this, mLayoutAlgorithm);
Winson35f30502015-09-28 11:24:36 -0700260 mTouchHandler = new TaskStackViewTouchHandler(context, this, mStackScroller);
Winsonf24f2162016-01-05 12:11:55 -0800261 mAnimationHelper = new TaskStackAnimationHelper(context, this);
Winsonbb410952015-12-04 14:34:11 -0800262 mTaskCornerRadiusPx = res.getDimensionPixelSize(
263 R.dimen.recents_task_view_rounded_corners_radius);
Winson3e874742016-01-07 10:08:17 -0800264 mDividerSize = ssp.getDockedDividerSize(context);
Winsonfc48b072016-04-21 11:20:11 -0700265 mDisplayOrientation = Utilities.getAppConfiguration(mContext).orientation;
266 mDisplayRect = ssp.getDisplayRect();
Winson35f30502015-09-28 11:24:36 -0700267
268 int taskBarDismissDozeDelaySeconds = getResources().getInteger(
269 R.integer.recents_task_bar_dismiss_delay_seconds);
270 mUIDozeTrigger = new DozeTrigger(taskBarDismissDozeDelaySeconds, new Runnable() {
Winson Chunga26fb782014-06-12 17:52:39 -0700271 @Override
272 public void run() {
273 // Show the task bar dismiss buttons
Winson Chung6ac8bd62015-01-07 16:38:35 -0800274 List<TaskView> taskViews = getTaskViews();
275 int taskViewCount = taskViews.size();
276 for (int i = 0; i < taskViewCount; i++) {
277 TaskView tv = taskViews.get(i);
Winson Chung969f5862014-06-16 17:08:24 -0700278 tv.startNoUserInteractionAnimation();
Winson Chunga26fb782014-06-12 17:52:39 -0700279 }
280 }
281 });
Winson Chung83ea6f72015-06-17 13:00:23 -0700282 setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
Manu Cornetbf8e2902016-12-20 08:29:33 -0800283 if (ssp.hasFreeformWorkspaceSupport()) {
284 setWillNotDraw(false);
285 }
Winson36a5a2c2015-10-29 18:04:39 -0700286
Winsonde0591a2015-12-04 17:24:35 -0800287 mFreeformWorkspaceBackground = (GradientDrawable) getContext().getDrawable(
288 R.drawable.recents_freeform_workspace_bg);
Winsona78a8f32015-12-03 10:55:01 -0800289 mFreeformWorkspaceBackground.setCallback(this);
Winsonde0591a2015-12-04 17:24:35 -0800290 if (ssp.hasFreeformWorkspaceSupport()) {
Winson Chungaa4f8002015-12-17 10:27:55 -0500291 mFreeformWorkspaceBackground.setColor(
292 getContext().getColor(R.color.recents_freeform_workspace_bg_color));
Winsonde0591a2015-12-04 17:24:35 -0800293 }
Winson Chung303e1ff2014-03-07 15:06:19 -0800294 }
295
Winsona1ededd2016-03-25 12:23:12 -0700296 @Override
297 protected void onAttachedToWindow() {
298 EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY + 1);
299 super.onAttachedToWindow();
300 readSystemFlags();
301 }
302
303 @Override
304 protected void onDetachedFromWindow() {
305 super.onDetachedFromWindow();
306 EventBus.getDefault().unregister(this);
307 }
308
Winson88737542016-02-17 13:27:33 -0800309 /**
Winsona1ededd2016-03-25 12:23:12 -0700310 * Called from RecentsActivity when it is relaunched.
Winson88737542016-02-17 13:27:33 -0800311 */
Winsona1ededd2016-03-25 12:23:12 -0700312 void onReload(boolean isResumingFromVisible) {
Winson88737542016-02-17 13:27:33 -0800313 if (!isResumingFromVisible) {
314 // Reset the focused task
315 resetFocusedTask(getFocusedTask());
316 }
317
318 // Reset the state of each of the task views
319 List<TaskView> taskViews = new ArrayList<>();
320 taskViews.addAll(getTaskViews());
321 taskViews.addAll(mViewPool.getViews());
322 for (int i = taskViews.size() - 1; i >= 0; i--) {
Winsona1ededd2016-03-25 12:23:12 -0700323 taskViews.get(i).onReload(isResumingFromVisible);
Winson88737542016-02-17 13:27:33 -0800324 }
325
326 // Reset the stack state
327 readSystemFlags();
328 mTaskViewsClipDirty = true;
329 mEnterAnimationComplete = false;
330 mUIDozeTrigger.stopDozing();
331 if (isResumingFromVisible) {
332 // Animate in the freeform workspace
333 int ffBgAlpha = mLayoutAlgorithm.getStackState().freeformBackgroundAlpha;
334 animateFreeformWorkspaceBackgroundAlpha(ffBgAlpha, new AnimationProps(150,
335 Interpolators.FAST_OUT_SLOW_IN));
336 } else {
337 mStackScroller.reset();
Winsonf9357d92016-03-25 15:14:37 -0700338 mStableLayoutAlgorithm.reset();
Winson88737542016-02-17 13:27:33 -0800339 mLayoutAlgorithm.reset();
Winson88737542016-02-17 13:27:33 -0800340 }
Winson88737542016-02-17 13:27:33 -0800341
Winsona1ededd2016-03-25 12:23:12 -0700342 // Since we always animate to the same place in (the initial state), always reset the stack
343 // to the initial state when resuming
344 mAwaitingFirstLayout = true;
Winsonbd53a312016-09-21 12:13:32 -0700345 mLaunchNextAfterFirstMeasure = false;
Winson619e40c2016-03-25 16:12:35 -0700346 mInitialState = INITIAL_STATE_UPDATE_ALL;
Winsona1ededd2016-03-25 12:23:12 -0700347 requestLayout();
Winsone6c90732015-09-24 16:06:29 -0700348 }
349
Winson88737542016-02-17 13:27:33 -0800350 /**
351 * Sets the stack tasks of this TaskStackView from the given TaskStack.
352 */
Winsona1ededd2016-03-25 12:23:12 -0700353 public void setTasks(TaskStack stack, boolean allowNotifyStackChanges) {
Winson88737542016-02-17 13:27:33 -0800354 boolean isInitialized = mLayoutAlgorithm.isInitialized();
Winsond2a03062016-04-15 11:19:07 -0700355
Winsona1ededd2016-03-25 12:23:12 -0700356 // Only notify if we are already initialized, otherwise, everything will pick up all the
357 // new and old tasks when we next layout
Winson88737542016-02-17 13:27:33 -0800358 mStack.setTasks(getContext(), stack.computeAllTasksList(),
Winsona1ededd2016-03-25 12:23:12 -0700359 allowNotifyStackChanges && isInitialized);
Winson Chungb0a28ea2014-10-28 15:21:35 -0700360 }
361
Winson Chungd16c5652015-01-26 16:11:07 -0800362 /** Returns the task stack. */
Winsone693aaf2016-03-01 12:05:59 -0800363 public TaskStack getStack() {
Winson Chungd16c5652015-01-26 16:11:07 -0800364 return mStack;
365 }
366
Winsone693aaf2016-03-01 12:05:59 -0800367 /**
368 * Updates this TaskStackView to the initial state.
369 */
Winson67c79572016-04-13 14:02:18 -0700370 public void updateToInitialState() {
371 mStackScroller.setStackScrollToInitialState();
Winsond2a03062016-04-15 11:19:07 -0700372 mLayoutAlgorithm.setTaskOverridesForInitialState(mStack, false /* ignoreScrollToFront */);
Winsone693aaf2016-03-01 12:05:59 -0800373 }
374
Winson Chung6ac8bd62015-01-07 16:38:35 -0800375 /** Updates the list of task views */
376 void updateTaskViewsList() {
377 mTaskViews.clear();
378 int childCount = getChildCount();
379 for (int i = 0; i < childCount; i++) {
380 View v = getChildAt(i);
381 if (v instanceof TaskView) {
382 mTaskViews.add((TaskView) v);
383 }
384 }
Winson Chung6ac8bd62015-01-07 16:38:35 -0800385 }
386
387 /** Gets the list of task views */
388 List<TaskView> getTaskViews() {
Winsonf24f2162016-01-05 12:11:55 -0800389 return mTaskViews;
Winson Chung6ac8bd62015-01-07 16:38:35 -0800390 }
391
Winson1b585612015-11-06 09:16:26 -0800392 /**
393 * Returns the front most task view.
394 *
395 * @param stackTasksOnly if set, will return the front most task view in the stack (by default
396 * the front most task view will be freeform since they are placed above
397 * stack tasks)
398 */
399 private TaskView getFrontMostTaskView(boolean stackTasksOnly) {
400 List<TaskView> taskViews = getTaskViews();
401 int taskViewCount = taskViews.size();
402 for (int i = taskViewCount - 1; i >= 0; i--) {
403 TaskView tv = taskViews.get(i);
404 Task task = tv.getTask();
405 if (stackTasksOnly && task.isFreeformTask()) {
406 continue;
407 }
408 return tv;
409 }
410 return null;
411 }
412
413 /**
414 * Finds the child view given a specific {@param task}.
415 */
416 public TaskView getChildViewForTask(Task t) {
417 List<TaskView> taskViews = getTaskViews();
418 int taskViewCount = taskViews.size();
419 for (int i = 0; i < taskViewCount; i++) {
420 TaskView tv = taskViews.get(i);
421 if (tv.getTask() == t) {
422 return tv;
423 }
424 }
425 return null;
426 }
427
Winson Chungd7b2cb12014-06-26 15:08:50 -0700428 /** Returns the stack algorithm for this task stack. */
Winson36a5a2c2015-10-29 18:04:39 -0700429 public TaskStackLayoutAlgorithm getStackAlgorithm() {
Winson Chung012ef362014-07-31 18:36:25 -0700430 return mLayoutAlgorithm;
Winson Chung303e1ff2014-03-07 15:06:19 -0800431 }
432
Winson Chungc6a16232014-04-01 14:04:48 -0700433 /**
Winsonaa0dea72016-04-28 10:59:30 -0700434 * Returns the touch handler for this task stack.
435 */
436 public TaskStackViewTouchHandler getTouchHandler() {
437 return mTouchHandler;
438 }
439
440 /**
Winson8aa99592016-01-19 15:07:07 -0800441 * Adds a task to the ignored set.
Winson Chungc6a16232014-04-01 14:04:48 -0700442 */
Winson8aa99592016-01-19 15:07:07 -0800443 void addIgnoreTask(Task task) {
444 mIgnoreTasks.add(task.key);
445 }
446
447 /**
448 * Removes a task from the ignored set.
449 */
450 void removeIgnoreTask(Task task) {
451 mIgnoreTasks.remove(task.key);
452 }
453
454 /**
455 * Returns whether the specified {@param task} is ignored.
456 */
457 boolean isIgnoredTask(Task task) {
458 return mIgnoreTasks.contains(task.key);
459 }
460
461 /**
462 * Computes the task transforms at the current stack scroll for all visible tasks. If a valid
463 * target stack scroll is provided (ie. is different than {@param curStackScroll}), then the
464 * visible range includes all tasks at the target stack scroll. This is useful for ensure that
465 * all views necessary for a transition or animation will be visible at the start.
466 *
467 * This call ignores freeform tasks.
468 *
469 * @param taskTransforms The set of task view transforms to reuse, this list will be sized to
470 * match the size of {@param tasks}
471 * @param tasks The set of tasks for which to generate transforms
472 * @param curStackScroll The current stack scroll
473 * @param targetStackScroll The stack scroll that we anticipate we are going to be scrolling to.
474 * The range of the union of the visible views at the current and
475 * target stack scrolls will be returned.
476 * @param ignoreTasksSet The set of tasks to skip for purposes of calculaing the visible range.
477 * Transforms will still be calculated for the ignore tasks.
Winsonc4387022016-02-24 12:05:26 -0800478 * @return the front and back most visible task indices (there may be non visible tasks in
479 * between this range)
Winson8aa99592016-01-19 15:07:07 -0800480 */
Winsonc4387022016-02-24 12:05:26 -0800481 int[] computeVisibleTaskTransforms(ArrayList<TaskViewTransform> taskTransforms,
Winson8aa99592016-01-19 15:07:07 -0800482 ArrayList<Task> tasks, float curStackScroll, float targetStackScroll,
Winsone693aaf2016-03-01 12:05:59 -0800483 ArraySet<Task.TaskKey> ignoreTasksSet, boolean ignoreTaskOverrides) {
Winson Chungc6a16232014-04-01 14:04:48 -0700484 int taskCount = tasks.size();
Winsonc4387022016-02-24 12:05:26 -0800485 int[] visibleTaskRange = mTmpIntPair;
486 visibleTaskRange[0] = -1;
487 visibleTaskRange[1] = -1;
Winson8aa99592016-01-19 15:07:07 -0800488 boolean useTargetStackScroll = Float.compare(curStackScroll, targetStackScroll) != 0;
Winson Chungc9567c02014-06-16 20:25:51 -0700489
490 // We can reuse the task transforms where possible to reduce object allocation
Winsonc5fd3502016-01-18 15:18:37 -0800491 Utilities.matchTaskListSize(tasks, taskTransforms);
Winson Chungc9567c02014-06-16 20:25:51 -0700492
493 // Update the stack transforms
Winson4993c2f2015-11-19 10:06:06 -0800494 TaskViewTransform frontTransform = null;
Winson8aa99592016-01-19 15:07:07 -0800495 TaskViewTransform frontTransformAtTarget = null;
496 TaskViewTransform transform = null;
497 TaskViewTransform transformAtTarget = null;
Winson Chung7aceb9a2014-07-03 13:38:01 -0700498 for (int i = taskCount - 1; i >= 0; i--) {
Winsona5e6b362015-11-02 17:17:20 -0800499 Task task = tasks.get(i);
Winson8aa99592016-01-19 15:07:07 -0800500
501 // Calculate the current and (if necessary) the target transform for the task
502 transform = mLayoutAlgorithm.getStackTransform(task, curStackScroll,
Jiaquan He26f637b2016-12-27 14:44:14 -0800503 taskTransforms.get(i), frontTransform, ignoreTaskOverrides);
Winson8aa99592016-01-19 15:07:07 -0800504 if (useTargetStackScroll && !transform.visible) {
505 // If we have a target stack scroll and the task is not currently visible, then we
506 // just update the transform at the new scroll
507 // TODO: Optimize this
Manu Cornetbf8e2902016-12-20 08:29:33 -0800508 transformAtTarget = mLayoutAlgorithm.getStackTransform(task, targetStackScroll,
Jiaquan He26f637b2016-12-27 14:44:14 -0800509 new TaskViewTransform(), frontTransformAtTarget);
Winson8aa99592016-01-19 15:07:07 -0800510 if (transformAtTarget.visible) {
511 transform.copyFrom(transformAtTarget);
512 }
Winson3e874742016-01-07 10:08:17 -0800513 }
514
Winson8aa99592016-01-19 15:07:07 -0800515 // For ignore tasks, only calculate the stack transform and skip the calculation of the
516 // visible stack indices
517 if (ignoreTasksSet.contains(task.key)) {
518 continue;
519 }
Winsonf24f2162016-01-05 12:11:55 -0800520
521 // For freeform tasks, only calculate the stack transform and skip the calculation of
522 // the visible stack indices
Winsona5e6b362015-11-02 17:17:20 -0800523 if (task.isFreeformTask()) {
524 continue;
525 }
526
Winson4993c2f2015-11-19 10:06:06 -0800527 frontTransform = transform;
Winson8aa99592016-01-19 15:07:07 -0800528 frontTransformAtTarget = transformAtTarget;
Winsonc4387022016-02-24 12:05:26 -0800529 if (transform.visible) {
530 if (visibleTaskRange[0] < 0) {
531 visibleTaskRange[0] = i;
532 }
533 visibleTaskRange[1] = i;
534 }
Winson Chungc6a16232014-04-01 14:04:48 -0700535 }
Winsonc4387022016-02-24 12:05:26 -0800536 return visibleTaskRange;
Winson Chungd42a6cf2014-06-03 16:24:04 -0700537 }
538
Winsonf24f2162016-01-05 12:11:55 -0800539 /**
Winson8aa99592016-01-19 15:07:07 -0800540 * Binds the visible {@link TaskView}s at the given target scroll.
Winsonf24f2162016-01-05 12:11:55 -0800541 */
Winson8aa99592016-01-19 15:07:07 -0800542 void bindVisibleTaskViews(float targetStackScroll) {
Winsond2a03062016-04-15 11:19:07 -0700543 bindVisibleTaskViews(targetStackScroll, false /* ignoreTaskOverrides */);
Winson8aa99592016-01-19 15:07:07 -0800544 }
545
546 /**
547 * Synchronizes the set of children {@link TaskView}s to match the visible set of tasks in the
548 * current {@link TaskStack}. This call does not continue on to update their position to the
549 * computed {@link TaskViewTransform}s of the visible range, but only ensures that they will
550 * be added/removed from the view hierarchy and placed in the correct Z order and initial
551 * position (if not currently on screen).
552 *
553 * @param targetStackScroll If provided, will ensure that the set of visible {@link TaskView}s
554 * includes those visible at the current stack scroll, and all at the
555 * target stack scroll.
Winsone693aaf2016-03-01 12:05:59 -0800556 * @param ignoreTaskOverrides If set, the visible task computation will get the transforms for
557 * tasks at their non-overridden task progress
Winson8aa99592016-01-19 15:07:07 -0800558 */
Winsond2a03062016-04-15 11:19:07 -0700559 void bindVisibleTaskViews(float targetStackScroll, boolean ignoreTaskOverrides) {
Winsonf24f2162016-01-05 12:11:55 -0800560 // Get all the task transforms
Winsonc4387022016-02-24 12:05:26 -0800561 ArrayList<Task> tasks = mStack.getStackTasks();
562 int[] visibleTaskRange = computeVisibleTaskTransforms(mCurrentTaskTransforms, tasks,
Winsond2a03062016-04-15 11:19:07 -0700563 mStackScroller.getStackScroll(), targetStackScroll, mIgnoreTasks,
Winsone693aaf2016-03-01 12:05:59 -0800564 ignoreTaskOverrides);
Winsonf24f2162016-01-05 12:11:55 -0800565
566 // Return all the invisible children to the pool
Winson55003902016-01-12 12:00:37 -0800567 mTmpTaskViewMap.clear();
Winson8aa99592016-01-19 15:07:07 -0800568 List<TaskView> taskViews = getTaskViews();
569 int lastFocusedTaskIndex = -1;
570 int taskViewCount = taskViews.size();
Winsonf24f2162016-01-05 12:11:55 -0800571 for (int i = taskViewCount - 1; i >= 0; i--) {
Winson8aa99592016-01-19 15:07:07 -0800572 TaskView tv = taskViews.get(i);
573 Task task = tv.getTask();
Winsonf24f2162016-01-05 12:11:55 -0800574
Winson3e874742016-01-07 10:08:17 -0800575 // Skip ignored tasks
Winsond2a03062016-04-15 11:19:07 -0700576 if (mIgnoreTasks.contains(task.key)) {
Winson3e874742016-01-07 10:08:17 -0800577 continue;
578 }
579
Winson1d5ff7e2016-03-04 11:21:09 -0800580 // It is possible for the set of lingering TaskViews to differ from the stack if the
581 // stack was updated before the relayout. If the task view is no longer in the stack,
582 // then just return it back to the view pool.
583 int taskIndex = mStack.indexOfStackTask(task);
584 TaskViewTransform transform = null;
585 if (taskIndex != -1) {
586 transform = mCurrentTaskTransforms.get(taskIndex);
587 }
588
589 if (task.isFreeformTask() || (transform != null && transform.visible)) {
Winson55003902016-01-12 12:00:37 -0800590 mTmpTaskViewMap.put(task.key, tv);
Winsonf24f2162016-01-05 12:11:55 -0800591 } else {
Winsonf0009882016-06-01 12:22:55 -0700592 if (mTouchExplorationEnabled && Utilities.isDescendentAccessibilityFocused(tv)) {
Winsonf24f2162016-01-05 12:11:55 -0800593 lastFocusedTaskIndex = taskIndex;
594 resetFocusedTask(task);
Winson Chung303e1ff2014-03-07 15:06:19 -0800595 }
Winsonf24f2162016-01-05 12:11:55 -0800596 mViewPool.returnViewToPool(tv);
Winson Chung303e1ff2014-03-07 15:06:19 -0800597 }
Winson Chung303e1ff2014-03-07 15:06:19 -0800598 }
Winsonf24f2162016-01-05 12:11:55 -0800599
600 // Pick up all the newly visible children
Winsonc4387022016-02-24 12:05:26 -0800601 for (int i = tasks.size() - 1; i >= 0; i--) {
Winson8aa99592016-01-19 15:07:07 -0800602 Task task = tasks.get(i);
603 TaskViewTransform transform = mCurrentTaskTransforms.get(i);
Winsonf24f2162016-01-05 12:11:55 -0800604
Winson3e874742016-01-07 10:08:17 -0800605 // Skip ignored tasks
Winsond2a03062016-04-15 11:19:07 -0700606 if (mIgnoreTasks.contains(task.key)) {
Winson3e874742016-01-07 10:08:17 -0800607 continue;
608 }
609
Winsonf24f2162016-01-05 12:11:55 -0800610 // Skip the invisible non-freeform stack tasks
Winson05e46ca2016-02-05 15:40:29 -0800611 if (!task.isFreeformTask() && !transform.visible) {
Winsonf24f2162016-01-05 12:11:55 -0800612 continue;
613 }
614
Winson55003902016-01-12 12:00:37 -0800615 TaskView tv = mTmpTaskViewMap.get(task.key);
Winsonf24f2162016-01-05 12:11:55 -0800616 if (tv == null) {
617 tv = mViewPool.pickUpViewFromPool(task, task);
618 if (task.isFreeformTask()) {
Winsonc69249f2016-03-28 13:38:39 -0700619 updateTaskViewToTransform(tv, transform, AnimationProps.IMMEDIATE);
Winsonf24f2162016-01-05 12:11:55 -0800620 } else {
Winson68088812016-02-12 16:06:04 -0800621 if (transform.rect.top <= mLayoutAlgorithm.mStackRect.top) {
Winsonc69249f2016-03-28 13:38:39 -0700622 updateTaskViewToTransform(tv, mLayoutAlgorithm.getBackOfStackTransform(),
623 AnimationProps.IMMEDIATE);
Winsonf24f2162016-01-05 12:11:55 -0800624 } else {
Winsonc69249f2016-03-28 13:38:39 -0700625 updateTaskViewToTransform(tv, mLayoutAlgorithm.getFrontOfStackTransform(),
626 AnimationProps.IMMEDIATE);
Winsonf24f2162016-01-05 12:11:55 -0800627 }
628 }
629 } else {
630 // Reattach it in the right z order
631 final int taskIndex = mStack.indexOfStackTask(task);
632 final int insertIndex = findTaskViewInsertIndex(task, taskIndex);
633 if (insertIndex != getTaskViews().indexOf(tv)){
634 detachViewFromParent(tv);
635 attachViewToParent(tv, insertIndex, tv.getLayoutParams());
636 updateTaskViewsList();
637 }
638 }
639 }
640
641 // Update the focus if the previous focused task was returned to the view pool
642 if (lastFocusedTaskIndex != -1) {
Winsonf0009882016-06-01 12:22:55 -0700643 int newFocusedTaskIndex = (lastFocusedTaskIndex < visibleTaskRange[1])
644 ? visibleTaskRange[1]
645 : visibleTaskRange[0];
646 setFocusedTask(newFocusedTaskIndex, false /* scrollToTask */,
647 true /* requestViewFocus */);
648 TaskView focusedTaskView = getChildViewForTask(mFocusedTask);
649 if (focusedTaskView != null) {
650 focusedTaskView.requestAccessibilityFocus();
Winsonf24f2162016-01-05 12:11:55 -0800651 }
652 }
653 }
654
655 /**
Winson27c28f82016-05-05 16:16:50 -0700656 * @see #relayoutTaskViews(AnimationProps, ArrayMap<Task, AnimationProps>, boolean)
Winsonf24f2162016-01-05 12:11:55 -0800657 */
Winson67c79572016-04-13 14:02:18 -0700658 public void relayoutTaskViews(AnimationProps animation) {
Winson27c28f82016-05-05 16:16:50 -0700659 relayoutTaskViews(animation, null /* animationOverrides */,
660 false /* ignoreTaskOverrides */);
Winson59924fe2016-03-17 14:13:18 -0700661 }
662
663 /**
Winson8aa99592016-01-19 15:07:07 -0800664 * Relayout the the visible {@link TaskView}s to their current transforms as specified by the
665 * {@link TaskStackLayoutAlgorithm} with the given {@param animation}. This call cancels any
666 * animations that are current running on those task views, and will ensure that the children
Winson27c28f82016-05-05 16:16:50 -0700667 * {@link TaskView}s will match the set of visible tasks in the stack. If a {@link Task} has
668 * an animation provided in {@param animationOverrides}, that will be used instead.
Winson8aa99592016-01-19 15:07:07 -0800669 */
Winson27c28f82016-05-05 16:16:50 -0700670 private void relayoutTaskViews(AnimationProps animation,
671 ArrayMap<Task, AnimationProps> animationOverrides,
672 boolean ignoreTaskOverrides) {
Winsonf24f2162016-01-05 12:11:55 -0800673 // If we had a deferred animation, cancel that
Winsoneca47ef2016-04-21 16:48:50 -0700674 cancelDeferredTaskViewLayoutAnimation();
Winsonf24f2162016-01-05 12:11:55 -0800675
Winson8aa99592016-01-19 15:07:07 -0800676 // Synchronize the current set of TaskViews
Winsond2a03062016-04-15 11:19:07 -0700677 bindVisibleTaskViews(mStackScroller.getStackScroll(),
Winson59924fe2016-03-17 14:13:18 -0700678 ignoreTaskOverrides /* ignoreTaskOverrides */);
Winsonf24f2162016-01-05 12:11:55 -0800679
680 // Animate them to their final transforms with the given animation
681 List<TaskView> taskViews = getTaskViews();
682 int taskViewCount = taskViews.size();
683 for (int i = 0; i < taskViewCount; i++) {
Winson43336942016-03-07 14:52:59 -0800684 TaskView tv = taskViews.get(i);
Winson27c28f82016-05-05 16:16:50 -0700685 Task task = tv.getTask();
Winsonf24f2162016-01-05 12:11:55 -0800686
Winson27c28f82016-05-05 16:16:50 -0700687 if (mIgnoreTasks.contains(task.key)) {
Winson3e874742016-01-07 10:08:17 -0800688 continue;
689 }
690
Winson448c0ad2016-10-19 09:53:59 -0700691 int taskIndex = mStack.indexOfStackTask(task);
692 TaskViewTransform transform = mCurrentTaskTransforms.get(taskIndex);
Winson27c28f82016-05-05 16:16:50 -0700693 if (animationOverrides != null && animationOverrides.containsKey(task)) {
694 animation = animationOverrides.get(task);
695 }
696
Winsonf24f2162016-01-05 12:11:55 -0800697 updateTaskViewToTransform(tv, transform, animation);
698 }
699 }
700
701 /**
702 * Posts an update to synchronize the {@link TaskView}s with the stack on the next frame.
703 */
Winsonbe8e6962016-02-01 14:27:52 -0800704 void relayoutTaskViewsOnNextFrame(AnimationProps animation) {
Winson8aa99592016-01-19 15:07:07 -0800705 mDeferredTaskViewLayoutAnimation = animation;
Winson1c846142016-01-22 11:34:38 -0800706 invalidate();
Winsonf24f2162016-01-05 12:11:55 -0800707 }
708
709 /**
710 * Called to update a specific {@link TaskView} to a given {@link TaskViewTransform} with a
Winsonbe8e6962016-02-01 14:27:52 -0800711 * given set of {@link AnimationProps} properties.
Winsonf24f2162016-01-05 12:11:55 -0800712 */
713 public void updateTaskViewToTransform(TaskView taskView, TaskViewTransform transform,
Winsonbe8e6962016-02-01 14:27:52 -0800714 AnimationProps animation) {
Jorim Jaggi899327f2016-02-25 20:44:18 -0500715 if (taskView.isAnimatingTo(transform)) {
716 return;
717 }
718 taskView.cancelTransformAnimation();
Winsonf24f2162016-01-05 12:11:55 -0800719 taskView.updateViewPropertiesToTaskTransform(transform, animation,
720 mRequestUpdateClippingListener);
721 }
722
723 /**
Winson8aa99592016-01-19 15:07:07 -0800724 * Returns the current task transforms of all tasks, falling back to the stack layout if there
725 * is no {@link TaskView} for the task.
Winsonf24f2162016-01-05 12:11:55 -0800726 */
Winson8aa99592016-01-19 15:07:07 -0800727 public void getCurrentTaskTransforms(ArrayList<Task> tasks,
728 ArrayList<TaskViewTransform> transformsOut) {
729 Utilities.matchTaskListSize(tasks, transformsOut);
Winson66474132016-02-23 18:45:47 -0800730 int focusState = mLayoutAlgorithm.getFocusState();
Winson8aa99592016-01-19 15:07:07 -0800731 for (int i = tasks.size() - 1; i >= 0; i--) {
732 Task task = tasks.get(i);
733 TaskViewTransform transform = transformsOut.get(i);
734 TaskView tv = getChildViewForTask(task);
735 if (tv != null) {
736 transform.fillIn(tv);
737 } else {
738 mLayoutAlgorithm.getStackTransform(task, mStackScroller.getStackScroll(),
Winsone693aaf2016-03-01 12:05:59 -0800739 focusState, transform, null, true /* forceUpdate */,
Jiaquan He26f637b2016-12-27 14:44:14 -0800740 false /* ignoreTaskOverrides */);
Winson8aa99592016-01-19 15:07:07 -0800741 }
742 transform.visible = true;
743 }
744 }
745
746 /**
747 * Returns the task transforms for all the tasks in the stack if the stack was at the given
Winson14991502016-02-15 15:40:08 -0800748 * {@param stackScroll} and {@param focusState}.
Winson8aa99592016-01-19 15:07:07 -0800749 */
Winson66474132016-02-23 18:45:47 -0800750 public void getLayoutTaskTransforms(float stackScroll, int focusState, ArrayList<Task> tasks,
Winsond2a03062016-04-15 11:19:07 -0700751 boolean ignoreTaskOverrides, ArrayList<TaskViewTransform> transformsOut) {
Winson8aa99592016-01-19 15:07:07 -0800752 Utilities.matchTaskListSize(tasks, transformsOut);
753 for (int i = tasks.size() - 1; i >= 0; i--) {
754 Task task = tasks.get(i);
755 TaskViewTransform transform = transformsOut.get(i);
Winson14991502016-02-15 15:40:08 -0800756 mLayoutAlgorithm.getStackTransform(task, stackScroll, focusState, transform, null,
Jiaquan He26f637b2016-12-27 14:44:14 -0800757 true /* forceUpdate */, ignoreTaskOverrides);
Winson8aa99592016-01-19 15:07:07 -0800758 transform.visible = true;
759 }
760 }
761
762 /**
Winson05e46ca2016-02-05 15:40:29 -0800763 * Cancels the next deferred task view layout.
764 */
765 void cancelDeferredTaskViewLayoutAnimation() {
766 mDeferredTaskViewLayoutAnimation = null;
767 }
768
769 /**
Winson8aa99592016-01-19 15:07:07 -0800770 * Cancels all {@link TaskView} animations.
Winson8aa99592016-01-19 15:07:07 -0800771 */
772 void cancelAllTaskViewAnimations() {
Winsonf24f2162016-01-05 12:11:55 -0800773 List<TaskView> taskViews = getTaskViews();
Winson3e874742016-01-07 10:08:17 -0800774 for (int i = taskViews.size() - 1; i >= 0; i--) {
Winsonf24f2162016-01-05 12:11:55 -0800775 final TaskView tv = taskViews.get(i);
Winsoneca47ef2016-04-21 16:48:50 -0700776 if (!mIgnoreTasks.contains(tv.getTask().key)) {
Winson8aa99592016-01-19 15:07:07 -0800777 tv.cancelTransformAnimation();
778 }
Winsonf24f2162016-01-05 12:11:55 -0800779 }
Winson Chung303e1ff2014-03-07 15:06:19 -0800780 }
781
Winson3150e572015-10-23 15:07:24 -0700782 /**
783 * Updates the clip for each of the task views from back to front.
784 */
Winsonf24f2162016-01-05 12:11:55 -0800785 private void clipTaskViews() {
Manu Cornetbf8e2902016-12-20 08:29:33 -0800786 // We never clip task views in grid layout
787 if (Recents.getConfiguration().isGridEnabled) {
788 return;
789 }
790
Winson Chung93748a12014-07-13 17:43:31 -0700791 // Update the clip on each task child
Winson Chung6ac8bd62015-01-07 16:38:35 -0800792 List<TaskView> taskViews = getTaskViews();
Winson3150e572015-10-23 15:07:24 -0700793 TaskView tmpTv = null;
Winson8aa99592016-01-19 15:07:07 -0800794 TaskView prevVisibleTv = null;
Winson Chung6ac8bd62015-01-07 16:38:35 -0800795 int taskViewCount = taskViews.size();
Winson3150e572015-10-23 15:07:24 -0700796 for (int i = 0; i < taskViewCount; i++) {
Winson Chung6ac8bd62015-01-07 16:38:35 -0800797 TaskView tv = taskViews.get(i);
Winson3150e572015-10-23 15:07:24 -0700798 TaskView frontTv = null;
Winson Chung6ac8bd62015-01-07 16:38:35 -0800799 int clipBottom = 0;
Winson8aa99592016-01-19 15:07:07 -0800800
Winson05e46ca2016-02-05 15:40:29 -0800801 if (isIgnoredTask(tv.getTask())) {
Winson8aa99592016-01-19 15:07:07 -0800802 // For each of the ignore tasks, update the translationZ of its TaskView to be
803 // between the translationZ of the tasks immediately underneath it
804 if (prevVisibleTv != null) {
805 tv.setTranslationZ(Math.max(tv.getTranslationZ(),
806 prevVisibleTv.getTranslationZ() + 0.1f));
807 }
808 }
809
Winson3150e572015-10-23 15:07:24 -0700810 if (i < (taskViewCount - 1) && tv.shouldClipViewInStack()) {
Winson Chung6ac8bd62015-01-07 16:38:35 -0800811 // Find the next view to clip against
Winson3150e572015-10-23 15:07:24 -0700812 for (int j = i + 1; j < taskViewCount; j++) {
813 tmpTv = taskViews.get(j);
Winsonef064132016-01-05 12:11:31 -0800814
Winson3150e572015-10-23 15:07:24 -0700815 if (tmpTv.shouldClipViewInStack()) {
816 frontTv = tmpTv;
Winson Chung6ac8bd62015-01-07 16:38:35 -0800817 break;
Winson Chung93748a12014-07-13 17:43:31 -0700818 }
819 }
Winson Chung6ac8bd62015-01-07 16:38:35 -0800820
821 // Clip against the next view, this is just an approximation since we are
822 // stacked and we can make assumptions about the visibility of the this
823 // task relative to the ones in front of it.
Winson3150e572015-10-23 15:07:24 -0700824 if (frontTv != null) {
Winsonbb410952015-12-04 14:34:11 -0800825 float taskBottom = tv.getBottom();
826 float frontTaskTop = frontTv.getTop();
Winson3150e572015-10-23 15:07:24 -0700827 if (frontTaskTop < taskBottom) {
828 // Map the stack view space coordinate (the rects) to view space
Winsonbb410952015-12-04 14:34:11 -0800829 clipBottom = (int) (taskBottom - frontTaskTop) - mTaskCornerRadiusPx;
Winson3150e572015-10-23 15:07:24 -0700830 }
Winson Chung6ac8bd62015-01-07 16:38:35 -0800831 }
Winson Chung93748a12014-07-13 17:43:31 -0700832 }
Winsonf24f2162016-01-05 12:11:55 -0800833 tv.getViewBounds().setClipBottom(clipBottom);
Winsone693aaf2016-03-01 12:05:59 -0800834 tv.mThumbnailView.updateThumbnailVisibility(clipBottom - tv.getPaddingBottom());
Winson8aa99592016-01-19 15:07:07 -0800835 prevVisibleTv = tv;
Winson Chung6ac8bd62015-01-07 16:38:35 -0800836 }
Winsonf24f2162016-01-05 12:11:55 -0800837 mTaskViewsClipDirty = false;
Winson Chung93748a12014-07-13 17:43:31 -0700838 }
839
Winson3e874742016-01-07 10:08:17 -0800840 /**
Winson8aa99592016-01-19 15:07:07 -0800841 * Updates the layout algorithm min and max virtual scroll bounds.
Winson8aa99592016-01-19 15:07:07 -0800842 */
Winson003eda62016-03-11 14:56:00 -0800843 public void updateLayoutAlgorithm(boolean boundScrollToNewMinMax) {
Winson Chung303e1ff2014-03-07 15:06:19 -0800844 // Compute the min and max scroll values
Winsond2a03062016-04-15 11:19:07 -0700845 mLayoutAlgorithm.update(mStack, mIgnoreTasks);
Winson Chung303e1ff2014-03-07 15:06:19 -0800846
Winson8aa99592016-01-19 15:07:07 -0800847 // Update the freeform workspace background
Winsona5e6b362015-11-02 17:17:20 -0800848 SystemServicesProxy ssp = Recents.getSystemServices();
849 if (ssp.hasFreeformWorkspaceSupport()) {
850 mTmpRect.set(mLayoutAlgorithm.mFreeformRect);
Winsona5e6b362015-11-02 17:17:20 -0800851 mFreeformWorkspaceBackground.setBounds(mTmpRect);
852 }
853
Winson Chung303e1ff2014-03-07 15:06:19 -0800854 if (boundScrollToNewMinMax) {
Winson Chung012ef362014-07-31 18:36:25 -0700855 mStackScroller.boundScroll();
Winson Chung303e1ff2014-03-07 15:06:19 -0800856 }
857 }
858
Winson27c28f82016-05-05 16:16:50 -0700859 /**
860 * Updates the stack layout to its stable places.
861 */
862 private void updateLayoutToStableBounds() {
863 mWindowRect.set(mStableWindowRect);
864 mStackBounds.set(mStableStackBounds);
865 mLayoutAlgorithm.setSystemInsets(mStableLayoutAlgorithm.mSystemInsets);
866 mLayoutAlgorithm.initialize(mDisplayRect, mWindowRect, mStackBounds,
867 TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack));
868 updateLayoutAlgorithm(true /* boundScroll */);
869 }
870
Winson Chung012ef362014-07-31 18:36:25 -0700871 /** Returns the scroller. */
872 public TaskStackViewScroller getScroller() {
873 return mStackScroller;
874 }
875
Winson0d14d4d2015-10-26 17:05:04 -0700876 /**
877 * Sets the focused task to the provided (bounded taskIndex).
Winsone5f1faa2015-11-20 12:26:23 -0800878 *
879 * @return whether or not the stack will scroll as a part of this focus change
Winson0d14d4d2015-10-26 17:05:04 -0700880 */
Winsonf24f2162016-01-05 12:11:55 -0800881 private boolean setFocusedTask(int taskIndex, boolean scrollToTask,
Winsonaaf33bc2015-12-03 12:02:38 -0800882 final boolean requestViewFocus) {
Winson4b9cded2016-01-26 16:26:47 -0800883 return setFocusedTask(taskIndex, scrollToTask, requestViewFocus, 0);
Peter Schillerb124d562015-12-11 21:31:17 -0800884 }
885
886 /**
Winson05e46ca2016-02-05 15:40:29 -0800887 * Sets the focused task to the provided (bounded focusTaskIndex).
Peter Schillerb124d562015-12-11 21:31:17 -0800888 *
889 * @return whether or not the stack will scroll as a part of this focus change
890 */
Winson05e46ca2016-02-05 15:40:29 -0800891 private boolean setFocusedTask(int focusTaskIndex, boolean scrollToTask,
892 boolean requestViewFocus, int timerIndicatorDuration) {
Winson0d14d4d2015-10-26 17:05:04 -0700893 // Find the next task to focus
Winson4b057c62016-01-12 15:01:52 -0800894 int newFocusedTaskIndex = mStack.getTaskCount() > 0 ?
Winson68088812016-02-12 16:06:04 -0800895 Utilities.clamp(focusTaskIndex, 0, mStack.getTaskCount() - 1) : -1;
Winson0d14d4d2015-10-26 17:05:04 -0700896 final Task newFocusedTask = (newFocusedTaskIndex != -1) ?
Winson250608a2015-11-24 15:00:31 -0800897 mStack.getStackTasks().get(newFocusedTaskIndex) : null;
Winson Chung1e8d71b2014-05-16 17:05:22 -0700898
Winson0d14d4d2015-10-26 17:05:04 -0700899 // Reset the last focused task state if changed
Winsonaaf33bc2015-12-03 12:02:38 -0800900 if (mFocusedTask != null) {
Peter Schillerb124d562015-12-11 21:31:17 -0800901 // Cancel the timer indicator, if applicable
Winson4b9cded2016-01-26 16:26:47 -0800902 if (timerIndicatorDuration > 0) {
Peter Schillerb124d562015-12-11 21:31:17 -0800903 final TaskView tv = getChildViewForTask(mFocusedTask);
904 if (tv != null) {
905 tv.getHeaderView().cancelFocusTimerIndicator();
906 }
907 }
Winsonb433c5b2016-01-20 17:11:29 -0800908
909 resetFocusedTask(mFocusedTask);
Winson0d14d4d2015-10-26 17:05:04 -0700910 }
911
Winsone5f1faa2015-11-20 12:26:23 -0800912 boolean willScroll = false;
Winsonaaf33bc2015-12-03 12:02:38 -0800913 mFocusedTask = newFocusedTask;
Peter Schillerb124d562015-12-11 21:31:17 -0800914
Winsonaaf33bc2015-12-03 12:02:38 -0800915 if (newFocusedTask != null) {
Peter Schillerb124d562015-12-11 21:31:17 -0800916 // Start the timer indicator, if applicable
Winson4b9cded2016-01-26 16:26:47 -0800917 if (timerIndicatorDuration > 0) {
Peter Schillerb124d562015-12-11 21:31:17 -0800918 final TaskView tv = getChildViewForTask(mFocusedTask);
919 if (tv != null) {
Winson4b9cded2016-01-26 16:26:47 -0800920 tv.getHeaderView().startFocusTimerIndicator(timerIndicatorDuration);
Peter Schillerb124d562015-12-11 21:31:17 -0800921 } else {
922 // The view is null; set a flag for later
Winson4b9cded2016-01-26 16:26:47 -0800923 mStartTimerIndicatorDuration = timerIndicatorDuration;
Peter Schillerb124d562015-12-11 21:31:17 -0800924 }
925 }
926
Winson0d14d4d2015-10-26 17:05:04 -0700927 if (scrollToTask) {
Winson1c846142016-01-22 11:34:38 -0800928 // Cancel any running enter animations at this point when we scroll or change focus
929 if (!mEnterAnimationComplete) {
930 cancelAllTaskViewAnimations();
931 }
932
Winsone693aaf2016-03-01 12:05:59 -0800933 mLayoutAlgorithm.clearUnfocusedTaskOverrides();
Winson05e46ca2016-02-05 15:40:29 -0800934 willScroll = mAnimationHelper.startScrollToFocusedTaskAnimation(newFocusedTask,
935 requestViewFocus);
Winson Chung1e8d71b2014-05-16 17:05:22 -0700936 } else {
Winson05e46ca2016-02-05 15:40:29 -0800937 // Focus the task view
938 TaskView newFocusedTaskView = getChildViewForTask(newFocusedTask);
939 if (newFocusedTaskView != null) {
940 newFocusedTaskView.setFocusedState(true, requestViewFocus);
941 }
Winson Chung1e8d71b2014-05-16 17:05:22 -0700942 }
943 }
Winsone5f1faa2015-11-20 12:26:23 -0800944 return willScroll;
Winson Chung1e8d71b2014-05-16 17:05:22 -0700945 }
946
Winson Chungd213a1e2014-10-02 11:18:30 -0700947 /**
Winson0d14d4d2015-10-26 17:05:04 -0700948 * Sets the focused task relative to the currently focused task.
949 *
Winsone5f1faa2015-11-20 12:26:23 -0800950 * @param forward whether to go to the next task in the stack (along the curve) or the previous
Winson1b585612015-11-06 09:16:26 -0800951 * @param stackTasksOnly if set, will ensure that the traversal only goes along stack tasks, and
952 * if the currently focused task is not a stack task, will set the focus
953 * to the first visible stack task
Winson0d14d4d2015-10-26 17:05:04 -0700954 * @param animated determines whether to actually draw the highlight along with the change in
955 * focus.
Winson Chungd213a1e2014-10-02 11:18:30 -0700956 */
Winson1b585612015-11-06 09:16:26 -0800957 public void setRelativeFocusedTask(boolean forward, boolean stackTasksOnly, boolean animated) {
Winsonf0009882016-06-01 12:22:55 -0700958 setRelativeFocusedTask(forward, stackTasksOnly, animated, false, 0);
Peter Schillerb124d562015-12-11 21:31:17 -0800959 }
960
961 /**
962 * Sets the focused task relative to the currently focused task.
963 *
964 * @param forward whether to go to the next task in the stack (along the curve) or the previous
965 * @param stackTasksOnly if set, will ensure that the traversal only goes along stack tasks, and
966 * if the currently focused task is not a stack task, will set the focus
967 * to the first visible stack task
968 * @param animated determines whether to actually draw the highlight along with the change in
969 * focus.
970 * @param cancelWindowAnimations if set, will attempt to cancel window animations if a scroll
971 * happens.
Winson4b9cded2016-01-26 16:26:47 -0800972 * @param timerIndicatorDuration the duration to initialize the auto-advance timer indicator
Peter Schillerb124d562015-12-11 21:31:17 -0800973 */
974 public void setRelativeFocusedTask(boolean forward, boolean stackTasksOnly, boolean animated,
Winsonf0009882016-06-01 12:22:55 -0700975 boolean cancelWindowAnimations, int timerIndicatorDuration) {
976 Task focusedTask = getFocusedTask();
977 int newIndex = mStack.indexOfStackTask(focusedTask);
978 if (focusedTask != null) {
Winson1b585612015-11-06 09:16:26 -0800979 if (stackTasksOnly) {
Winson250608a2015-11-24 15:00:31 -0800980 List<Task> tasks = mStack.getStackTasks();
Winsonf0009882016-06-01 12:22:55 -0700981 if (focusedTask.isFreeformTask()) {
Winson1b585612015-11-06 09:16:26 -0800982 // Try and focus the front most stack task
983 TaskView tv = getFrontMostTaskView(stackTasksOnly);
984 if (tv != null) {
Winson250608a2015-11-24 15:00:31 -0800985 newIndex = mStack.indexOfStackTask(tv.getTask());
Winson1b585612015-11-06 09:16:26 -0800986 }
987 } else {
988 // Try the next task if it is a stack task
Winsonaaf33bc2015-12-03 12:02:38 -0800989 int tmpNewIndex = newIndex + (forward ? -1 : 1);
Winson1b585612015-11-06 09:16:26 -0800990 if (0 <= tmpNewIndex && tmpNewIndex < tasks.size()) {
991 Task t = tasks.get(tmpNewIndex);
992 if (!t.isFreeformTask()) {
993 newIndex = tmpNewIndex;
994 }
995 }
996 }
997 } else {
Winson8b1871d2015-11-20 09:56:20 -0800998 // No restrictions, lets just move to the new task (looping forward/backwards if
999 // necessary)
Winson4b057c62016-01-12 15:01:52 -08001000 int taskCount = mStack.getTaskCount();
Winsonaaf33bc2015-12-03 12:02:38 -08001001 newIndex = (newIndex + (forward ? -1 : 1) + taskCount) % taskCount;
Winson1b585612015-11-06 09:16:26 -08001002 }
1003 } else {
Winson23b0d3f2016-02-15 17:43:01 -08001004 // We don't have a focused task
1005 float stackScroll = mStackScroller.getStackScroll();
1006 ArrayList<Task> tasks = mStack.getStackTasks();
1007 int taskCount = tasks.size();
1008 if (forward) {
1009 // Walk backwards and focus the next task smaller than the current stack scroll
1010 for (newIndex = taskCount - 1; newIndex >= 0; newIndex--) {
1011 float taskP = mLayoutAlgorithm.getStackScrollForTask(tasks.get(newIndex));
1012 if (Float.compare(taskP, stackScroll) <= 0) {
1013 break;
1014 }
1015 }
1016 } else {
1017 // Walk forwards and focus the next task larger than the current stack scroll
1018 for (newIndex = 0; newIndex < taskCount; newIndex++) {
1019 float taskP = mLayoutAlgorithm.getStackScrollForTask(tasks.get(newIndex));
1020 if (Float.compare(taskP, stackScroll) >= 0) {
1021 break;
1022 }
1023 }
Winson1b585612015-11-06 09:16:26 -08001024 }
1025 }
1026 if (newIndex != -1) {
Winsonf24f2162016-01-05 12:11:55 -08001027 boolean willScroll = setFocusedTask(newIndex, true /* scrollToTask */,
Winson4b9cded2016-01-26 16:26:47 -08001028 true /* requestViewFocus */, timerIndicatorDuration);
Winsone5f1faa2015-11-20 12:26:23 -08001029 if (willScroll && cancelWindowAnimations) {
1030 // As we iterate to the next/previous task, cancel any current/lagging window
1031 // transition animations
1032 EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(null));
1033 }
Winson1b585612015-11-06 09:16:26 -08001034 }
Winson Chunga0e88b52014-08-11 19:25:42 -07001035 }
1036
Winson0d14d4d2015-10-26 17:05:04 -07001037 /**
1038 * Resets the focused task.
1039 */
Winsona0731a12015-12-02 15:10:14 -08001040 void resetFocusedTask(Task task) {
1041 if (task != null) {
1042 TaskView tv = getChildViewForTask(task);
Winson Chungfc33cdf2014-12-03 13:16:48 -08001043 if (tv != null) {
Winsonf24f2162016-01-05 12:11:55 -08001044 tv.setFocusedState(false, false /* requestViewFocus */);
Winson Chungfc33cdf2014-12-03 13:16:48 -08001045 }
Winson Chungb0a28ea2014-10-28 15:21:35 -07001046 }
Winsonaaf33bc2015-12-03 12:02:38 -08001047 mFocusedTask = null;
Winson Chungb0a28ea2014-10-28 15:21:35 -07001048 }
1049
Winson142af422015-11-09 10:39:57 -08001050 /**
1051 * Returns the focused task.
1052 */
1053 Task getFocusedTask() {
Winsonaaf33bc2015-12-03 12:02:38 -08001054 return mFocusedTask;
Winson142af422015-11-09 10:39:57 -08001055 }
1056
Winsonf0009882016-06-01 12:22:55 -07001057 /**
1058 * Returns the accessibility focused task.
1059 */
1060 Task getAccessibilityFocusedTask() {
1061 List<TaskView> taskViews = getTaskViews();
1062 int taskViewCount = taskViews.size();
1063 for (int i = 0; i < taskViewCount; i++) {
1064 TaskView tv = taskViews.get(i);
1065 if (Utilities.isDescendentAccessibilityFocused(tv)) {
1066 return tv.getTask();
1067 }
1068 }
1069 TaskView frontTv = getFrontMostTaskView(true /* stackTasksOnly */);
1070 if (frontTv != null) {
1071 return frontTv.getTask();
1072 }
1073 return null;
1074 }
1075
Winson Chung303e1ff2014-03-07 15:06:19 -08001076 @Override
Winson Chungee445952014-09-09 16:12:59 +02001077 public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
1078 super.onInitializeAccessibilityEvent(event);
Winson Chung6ac8bd62015-01-07 16:38:35 -08001079 List<TaskView> taskViews = getTaskViews();
1080 int taskViewCount = taskViews.size();
1081 if (taskViewCount > 0) {
1082 TaskView backMostTask = taskViews.get(0);
1083 TaskView frontMostTask = taskViews.get(taskViewCount - 1);
Winson250608a2015-11-24 15:00:31 -08001084 event.setFromIndex(mStack.indexOfStackTask(backMostTask.getTask()));
1085 event.setToIndex(mStack.indexOfStackTask(frontMostTask.getTask()));
Winson Chung296278a2015-12-17 12:09:02 -05001086 event.setContentDescription(frontMostTask.getTask().title);
Winson Chungee445952014-09-09 16:12:59 +02001087 }
Winson4b057c62016-01-12 15:01:52 -08001088 event.setItemCount(mStack.getTaskCount());
Winson59924fe2016-03-17 14:13:18 -07001089
1090 int stackHeight = mLayoutAlgorithm.mStackRect.height();
1091 event.setScrollY((int) (mStackScroller.getStackScroll() * stackHeight));
1092 event.setMaxScrollY((int) (mLayoutAlgorithm.mMaxScrollP * stackHeight));
Winson Chungee445952014-09-09 16:12:59 +02001093 }
1094
1095 @Override
Winson Chung83ea6f72015-06-17 13:00:23 -07001096 public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
1097 super.onInitializeAccessibilityNodeInfo(info);
1098 List<TaskView> taskViews = getTaskViews();
1099 int taskViewCount = taskViews.size();
Winsonf0009882016-06-01 12:22:55 -07001100 if (taskViewCount > 1) {
1101 // Find the accessibility focused task
1102 Task focusedTask = getAccessibilityFocusedTask();
Winson Chung83ea6f72015-06-17 13:00:23 -07001103 info.setScrollable(true);
Winsonf0009882016-06-01 12:22:55 -07001104 int focusedTaskIndex = mStack.indexOfStackTask(focusedTask);
Winsonaaf33bc2015-12-03 12:02:38 -08001105 if (focusedTaskIndex > 0) {
Winson Chung83ea6f72015-06-17 13:00:23 -07001106 info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
1107 }
Winsonf0009882016-06-01 12:22:55 -07001108 if (0 <= focusedTaskIndex && focusedTaskIndex < mStack.getTaskCount() - 1) {
1109 info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
1110 }
Winson Chung83ea6f72015-06-17 13:00:23 -07001111 }
1112 }
1113
1114 @Override
1115 public CharSequence getAccessibilityClassName() {
Winsonf0009882016-06-01 12:22:55 -07001116 return ScrollView.class.getName();
Winson Chung83ea6f72015-06-17 13:00:23 -07001117 }
1118
1119 @Override
1120 public boolean performAccessibilityAction(int action, Bundle arguments) {
1121 if (super.performAccessibilityAction(action, arguments)) {
1122 return true;
1123 }
Winsonf0009882016-06-01 12:22:55 -07001124 Task focusedTask = getAccessibilityFocusedTask();
1125 int taskIndex = mStack.indexOfStackTask(focusedTask);
1126 if (0 <= taskIndex && taskIndex < mStack.getTaskCount()) {
1127 switch (action) {
1128 case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: {
1129 setFocusedTask(taskIndex + 1, true /* scrollToTask */, true /* requestViewFocus */,
1130 0);
1131 return true;
1132 }
1133 case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: {
1134 setFocusedTask(taskIndex - 1, true /* scrollToTask */, true /* requestViewFocus */,
1135 0);
1136 return true;
1137 }
Winson Chung83ea6f72015-06-17 13:00:23 -07001138 }
1139 }
1140 return false;
1141 }
1142
1143 @Override
Winson Chung303e1ff2014-03-07 15:06:19 -08001144 public boolean onInterceptTouchEvent(MotionEvent ev) {
1145 return mTouchHandler.onInterceptTouchEvent(ev);
1146 }
1147
1148 @Override
1149 public boolean onTouchEvent(MotionEvent ev) {
1150 return mTouchHandler.onTouchEvent(ev);
1151 }
1152
1153 @Override
Winson Chungd213a1e2014-10-02 11:18:30 -07001154 public boolean onGenericMotionEvent(MotionEvent ev) {
1155 return mTouchHandler.onGenericMotionEvent(ev);
1156 }
1157
1158 @Override
Winson Chungd7b2cb12014-06-26 15:08:50 -07001159 public void computeScroll() {
Winsonf24f2162016-01-05 12:11:55 -08001160 if (mStackScroller.computeScroll()) {
1161 // Notify accessibility
1162 sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SCROLLED);
1163 }
Winson8aa99592016-01-19 15:07:07 -08001164 if (mDeferredTaskViewLayoutAnimation != null) {
1165 relayoutTaskViews(mDeferredTaskViewLayoutAnimation);
Winsonf24f2162016-01-05 12:11:55 -08001166 mTaskViewsClipDirty = true;
Winson8aa99592016-01-19 15:07:07 -08001167 mDeferredTaskViewLayoutAnimation = null;
Winsonf24f2162016-01-05 12:11:55 -08001168 }
1169 if (mTaskViewsClipDirty) {
1170 clipTaskViews();
1171 }
Winson Chung303e1ff2014-03-07 15:06:19 -08001172 }
1173
Winson3e874742016-01-07 10:08:17 -08001174 /**
Winson8aa99592016-01-19 15:07:07 -08001175 * Computes the maximum number of visible tasks and thumbnails. Requires that
Winsoneca4ab62015-11-04 10:50:28 -08001176 * updateLayoutForStack() is called first.
Winson Chunga91c2932014-11-07 15:02:38 -08001177 */
Winson36a5a2c2015-10-29 18:04:39 -07001178 public TaskStackLayoutAlgorithm.VisibilityReport computeStackVisibilityReport() {
Winson250608a2015-11-24 15:00:31 -08001179 return mLayoutAlgorithm.computeStackVisibilityReport(mStack.getStackTasks());
Winson Chunga91c2932014-11-07 15:02:38 -08001180 }
1181
Winson3e874742016-01-07 10:08:17 -08001182 /**
Winson59924fe2016-03-17 14:13:18 -07001183 * Updates the system insets.
Winson3e874742016-01-07 10:08:17 -08001184 */
Winson59924fe2016-03-17 14:13:18 -07001185 public void setSystemInsets(Rect systemInsets) {
Winson67c79572016-04-13 14:02:18 -07001186 boolean changed = false;
1187 changed |= mStableLayoutAlgorithm.setSystemInsets(systemInsets);
1188 changed |= mLayoutAlgorithm.setSystemInsets(systemInsets);
1189 if (changed) {
Winson49df4202016-01-25 17:33:34 -08001190 requestLayout();
1191 }
Winson147ecaf2015-09-16 16:49:55 -07001192 }
1193
Winson Chunga91c2932014-11-07 15:02:38 -08001194 /**
Winson Chunga4ccb862014-08-22 15:26:27 -07001195 * This is called with the full window width and height to allow stack view children to
Winson Chungdcfa7972014-07-22 12:27:13 -07001196 * perform the full screen transition down.
Winson Chungf7bca432014-04-30 17:11:13 -07001197 */
Winson Chung303e1ff2014-03-07 15:06:19 -08001198 @Override
1199 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Winson70f0bf72016-02-01 14:05:29 -08001200 mInMeasureLayout = true;
Winson Chung303e1ff2014-03-07 15:06:19 -08001201 int width = MeasureSpec.getSize(widthMeasureSpec);
1202 int height = MeasureSpec.getSize(heightMeasureSpec);
Winson Chung303e1ff2014-03-07 15:06:19 -08001203
Winson59924fe2016-03-17 14:13:18 -07001204 // Update the stable stack bounds, but only update the current stack bounds if the stable
1205 // bounds have changed. This is because we may get spurious measures while dragging where
1206 // our current stack bounds reflect the target drop region.
Winsonfc48b072016-04-21 11:20:11 -07001207 mLayoutAlgorithm.getTaskStackBounds(mDisplayRect, new Rect(0, 0, width, height),
Winsoncbb625b2016-07-06 15:24:15 -07001208 mLayoutAlgorithm.mSystemInsets.top, mLayoutAlgorithm.mSystemInsets.left,
1209 mLayoutAlgorithm.mSystemInsets.right, mTmpRect);
Winson59924fe2016-03-17 14:13:18 -07001210 if (!mTmpRect.equals(mStableStackBounds)) {
1211 mStableStackBounds.set(mTmpRect);
1212 mStackBounds.set(mTmpRect);
1213 mStableWindowRect.set(0, 0, width, height);
1214 mWindowRect.set(0, 0, width, height);
1215 }
1216
Winson8aa99592016-01-19 15:07:07 -08001217 // Compute the rects in the stack algorithm
Winsonfc48b072016-04-21 11:20:11 -07001218 mStableLayoutAlgorithm.initialize(mDisplayRect, mStableWindowRect, mStableStackBounds,
Winsonf9357d92016-03-25 15:14:37 -07001219 TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack));
Winsonfc48b072016-04-21 11:20:11 -07001220 mLayoutAlgorithm.initialize(mDisplayRect, mWindowRect, mStackBounds,
Winson8aa99592016-01-19 15:07:07 -08001221 TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack));
Winson67c79572016-04-13 14:02:18 -07001222 updateLayoutAlgorithm(false /* boundScroll */);
Winson Chung303e1ff2014-03-07 15:06:19 -08001223
Winsonf24f2162016-01-05 12:11:55 -08001224 // If this is the first layout, then scroll to the front of the stack, then update the
1225 // TaskViews with the stack so that we can lay them out
Jorim Jaggidb21bbd2016-04-18 15:32:07 -07001226 boolean resetToInitialState = (width != mLastWidth || height != mLastHeight)
1227 && mResetToInitialStateWhenResized;
1228 if (mAwaitingFirstLayout || mInitialState != INITIAL_STATE_UPDATE_NONE
1229 || resetToInitialState) {
1230 if (mInitialState != INITIAL_STATE_UPDATE_LAYOUT_ONLY || resetToInitialState) {
Winson67c79572016-04-13 14:02:18 -07001231 updateToInitialState();
Jorim Jaggidb21bbd2016-04-18 15:32:07 -07001232 mResetToInitialStateWhenResized = false;
Winson67c79572016-04-13 14:02:18 -07001233 }
Winson670ea712016-04-12 17:02:26 -07001234 if (!mAwaitingFirstLayout) {
1235 mInitialState = INITIAL_STATE_UPDATE_NONE;
1236 }
Winson Chung303e1ff2014-03-07 15:06:19 -08001237 }
Winsonbd53a312016-09-21 12:13:32 -07001238 // If we got the launch-next event before the first layout pass, then re-send it after the
1239 // initial state has been updated
1240 if (mLaunchNextAfterFirstMeasure) {
1241 mLaunchNextAfterFirstMeasure = false;
1242 EventBus.getDefault().post(new LaunchNextTaskRequestEvent());
1243 }
Winsone693aaf2016-03-01 12:05:59 -08001244
Winson8aa99592016-01-19 15:07:07 -08001245 // Rebind all the views, including the ignore ones
Winsond2a03062016-04-15 11:19:07 -07001246 bindVisibleTaskViews(mStackScroller.getStackScroll(), false /* ignoreTaskOverrides */);
Winson Chung303e1ff2014-03-07 15:06:19 -08001247
Winson Chungdcfa7972014-07-22 12:27:13 -07001248 // Measure each of the TaskViews
Winsona2236f12015-11-13 16:10:01 -08001249 mTmpTaskViews.clear();
1250 mTmpTaskViews.addAll(getTaskViews());
1251 mTmpTaskViews.addAll(mViewPool.getViews());
1252 int taskViewCount = mTmpTaskViews.size();
Winson Chung6ac8bd62015-01-07 16:38:35 -08001253 for (int i = 0; i < taskViewCount; i++) {
Winson70f0bf72016-02-01 14:05:29 -08001254 measureTaskView(mTmpTaskViews.get(i));
Winson Chung303e1ff2014-03-07 15:06:19 -08001255 }
1256
1257 setMeasuredDimension(width, height);
Jorim Jaggidb21bbd2016-04-18 15:32:07 -07001258 mLastWidth = width;
1259 mLastHeight = height;
Winson70f0bf72016-02-01 14:05:29 -08001260 mInMeasureLayout = false;
1261 }
1262
1263 /**
1264 * Measures a TaskView.
1265 */
1266 private void measureTaskView(TaskView tv) {
Winson67c79572016-04-13 14:02:18 -07001267 Rect padding = new Rect();
Winson70f0bf72016-02-01 14:05:29 -08001268 if (tv.getBackground() != null) {
Winson67c79572016-04-13 14:02:18 -07001269 tv.getBackground().getPadding(padding);
Winson70f0bf72016-02-01 14:05:29 -08001270 }
Jiaquan He8f34df42016-12-27 15:38:44 -08001271 mTmpRect.set(mStableLayoutAlgorithm.getTaskRect());
1272 mTmpRect.union(mLayoutAlgorithm.getTaskRect());
Winson70f0bf72016-02-01 14:05:29 -08001273 tv.measure(
Winson67c79572016-04-13 14:02:18 -07001274 MeasureSpec.makeMeasureSpec(mTmpRect.width() + padding.left + padding.right,
Winson70f0bf72016-02-01 14:05:29 -08001275 MeasureSpec.EXACTLY),
Winson67c79572016-04-13 14:02:18 -07001276 MeasureSpec.makeMeasureSpec(mTmpRect.height() + padding.top + padding.bottom,
Winson70f0bf72016-02-01 14:05:29 -08001277 MeasureSpec.EXACTLY));
Winson Chung303e1ff2014-03-07 15:06:19 -08001278 }
1279
1280 @Override
1281 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
Winson36a5a2c2015-10-29 18:04:39 -07001282 // Layout each of the TaskViews
Winsona2236f12015-11-13 16:10:01 -08001283 mTmpTaskViews.clear();
1284 mTmpTaskViews.addAll(getTaskViews());
1285 mTmpTaskViews.addAll(mViewPool.getViews());
1286 int taskViewCount = mTmpTaskViews.size();
Winson Chung6ac8bd62015-01-07 16:38:35 -08001287 for (int i = 0; i < taskViewCount; i++) {
Winsonc69249f2016-03-28 13:38:39 -07001288 layoutTaskView(changed, mTmpTaskViews.get(i));
Winson Chung303e1ff2014-03-07 15:06:19 -08001289 }
1290
Jorim Jaggi7af8ea82015-11-09 15:28:34 +01001291 if (changed) {
Winsona2236f12015-11-13 16:10:01 -08001292 if (mStackScroller.isScrollOutOfBounds()) {
1293 mStackScroller.boundScroll();
1294 }
Winsonf24f2162016-01-05 12:11:55 -08001295 }
Winsonc69249f2016-03-28 13:38:39 -07001296
Winson8aa99592016-01-19 15:07:07 -08001297 // Relayout all of the task views including the ignored ones
Winson67c79572016-04-13 14:02:18 -07001298 relayoutTaskViews(AnimationProps.IMMEDIATE);
Winsonf24f2162016-01-05 12:11:55 -08001299 clipTaskViews();
1300
1301 if (mAwaitingFirstLayout || !mEnterAnimationComplete) {
1302 mAwaitingFirstLayout = false;
Winson670ea712016-04-12 17:02:26 -07001303 mInitialState = INITIAL_STATE_UPDATE_NONE;
Winsonf24f2162016-01-05 12:11:55 -08001304 onFirstLayout();
Jorim Jaggi7af8ea82015-11-09 15:28:34 +01001305 }
Winson Chungdcfa7972014-07-22 12:27:13 -07001306 }
Winson Chung24cf1522014-05-29 12:03:33 -07001307
Winson70f0bf72016-02-01 14:05:29 -08001308 /**
1309 * Lays out a TaskView.
1310 */
Winsonc69249f2016-03-28 13:38:39 -07001311 private void layoutTaskView(boolean changed, TaskView tv) {
1312 if (changed) {
Winson67c79572016-04-13 14:02:18 -07001313 Rect padding = new Rect();
Winsonc69249f2016-03-28 13:38:39 -07001314 if (tv.getBackground() != null) {
Winson67c79572016-04-13 14:02:18 -07001315 tv.getBackground().getPadding(padding);
Winsonc69249f2016-03-28 13:38:39 -07001316 }
Jiaquan He8f34df42016-12-27 15:38:44 -08001317 mTmpRect.set(mStableLayoutAlgorithm.getTaskRect());
1318 mTmpRect.union(mLayoutAlgorithm.getTaskRect());
Winsonc69249f2016-03-28 13:38:39 -07001319 tv.cancelTransformAnimation();
Winson67c79572016-04-13 14:02:18 -07001320 tv.layout(mTmpRect.left - padding.left, mTmpRect.top - padding.top,
1321 mTmpRect.right + padding.right, mTmpRect.bottom + padding.bottom);
Winson70f0bf72016-02-01 14:05:29 -08001322 } else {
Winsonc69249f2016-03-28 13:38:39 -07001323 // If the layout has not changed, then just lay it out again in-place
1324 tv.layout(tv.getLeft(), tv.getTop(), tv.getRight(), tv.getBottom());
Winson70f0bf72016-02-01 14:05:29 -08001325 }
Winson70f0bf72016-02-01 14:05:29 -08001326 }
1327
Winson Chungdcfa7972014-07-22 12:27:13 -07001328 /** Handler for the first layout. */
1329 void onFirstLayout() {
Winsonf24f2162016-01-05 12:11:55 -08001330 // Setup the view for the enter animation
1331 mAnimationHelper.prepareForEnterAnimation();
Winson Chung083baf92014-07-11 10:32:42 -07001332
Winsona78a8f32015-12-03 10:55:01 -08001333 // Animate in the freeform workspace
Winsonbe8e6962016-02-01 14:27:52 -08001334 int ffBgAlpha = mLayoutAlgorithm.getStackState().freeformBackgroundAlpha;
1335 animateFreeformWorkspaceBackgroundAlpha(ffBgAlpha, new AnimationProps(150,
1336 Interpolators.FAST_OUT_SLOW_IN));
Winsona78a8f32015-12-03 10:55:01 -08001337
Winson0d14d4d2015-10-26 17:05:04 -07001338 // Set the task focused state without requesting view focus, and leave the focus animations
1339 // until after the enter-animation
Winson5da43472015-11-04 17:39:55 -08001340 RecentsConfiguration config = Recents.getConfiguration();
1341 RecentsActivityLaunchState launchState = config.getLaunchState();
Winson4b9cded2016-01-26 16:26:47 -08001342 int focusedTaskIndex = launchState.getInitialFocusTaskIndex(mStack.getTaskCount());
Winson5da43472015-11-04 17:39:55 -08001343 if (focusedTaskIndex != -1) {
Winsonf24f2162016-01-05 12:11:55 -08001344 setFocusedTask(focusedTaskIndex, false /* scrollToTask */,
Winson5da43472015-11-04 17:39:55 -08001345 false /* requestViewFocus */);
Winson0983e022015-10-13 17:21:42 -07001346 }
Manu Cornetbf8e2902016-12-20 08:29:33 -08001347 updateStackActionButtonVisibility();
Winson Chung24cf1522014-05-29 12:03:33 -07001348 }
1349
Winson671e8f92016-01-12 13:16:56 -08001350 public boolean isTouchPointInView(float x, float y, TaskView tv) {
Winson8aa99592016-01-19 15:07:07 -08001351 mTmpRect.set(tv.getLeft(), tv.getTop(), tv.getRight(), tv.getBottom());
1352 mTmpRect.offset((int) tv.getTranslationX(), (int) tv.getTranslationY());
1353 return mTmpRect.contains((int) x, (int) y);
1354 }
1355
1356 /**
1357 * Returns a non-ignored task in the {@param tasks} list that can be used as an achor when
1358 * calculating the scroll position before and after a layout change.
1359 */
1360 public Task findAnchorTask(List<Task> tasks, MutableBoolean isFrontMostTask) {
1361 for (int i = tasks.size() - 1; i >= 0; i--) {
1362 Task task = tasks.get(i);
1363
1364 // Ignore deleting tasks
Winson05e46ca2016-02-05 15:40:29 -08001365 if (isIgnoredTask(task)) {
Winson8aa99592016-01-19 15:07:07 -08001366 if (i == tasks.size() - 1) {
1367 isFrontMostTask.value = true;
1368 }
1369 continue;
1370 }
1371 return task;
1372 }
1373 return null;
Winson Chung303e1ff2014-03-07 15:06:19 -08001374 }
1375
Jorim Jaggi900fb482015-06-02 15:07:33 -07001376 @Override
Winsonbe8e6962016-02-01 14:27:52 -08001377 protected void onDraw(Canvas canvas) {
1378 super.onDraw(canvas);
1379
Winson36a5a2c2015-10-29 18:04:39 -07001380 // Draw the freeform workspace background
Winson805578d2015-11-23 14:47:37 -08001381 SystemServicesProxy ssp = Recents.getSystemServices();
1382 if (ssp.hasFreeformWorkspaceSupport()) {
1383 if (mFreeformWorkspaceBackground.getAlpha() > 0) {
1384 mFreeformWorkspaceBackground.draw(canvas);
1385 }
Winson36a5a2c2015-10-29 18:04:39 -07001386 }
Jorim Jaggi900fb482015-06-02 15:07:33 -07001387 }
1388
Winsona78a8f32015-12-03 10:55:01 -08001389 @Override
1390 protected boolean verifyDrawable(Drawable who) {
1391 if (who == mFreeformWorkspaceBackground) {
1392 return true;
1393 }
1394 return super.verifyDrawable(who);
1395 }
1396
Winsona5e6b362015-11-02 17:17:20 -08001397 /**
1398 * Launches the freeform tasks.
1399 */
1400 public boolean launchFreeformTasks() {
Winsonf24f2162016-01-05 12:11:55 -08001401 ArrayList<Task> tasks = mStack.getFreeformTasks();
1402 if (!tasks.isEmpty()) {
1403 Task frontTask = tasks.get(tasks.size() - 1);
1404 if (frontTask != null && frontTask.isFreeformTask()) {
1405 EventBus.getDefault().send(new LaunchTaskEvent(getChildViewForTask(frontTask),
1406 frontTask, null, INVALID_STACK_ID, false));
1407 return true;
1408 }
Winsona5e6b362015-11-02 17:17:20 -08001409 }
1410 return false;
1411 }
1412
Winson Chung303e1ff2014-03-07 15:06:19 -08001413 /**** TaskStackCallbacks Implementation ****/
1414
1415 @Override
Winson Chung06266772015-12-11 10:24:21 -05001416 public void onStackTaskAdded(TaskStack stack, Task newTask) {
1417 // Update the min/max scroll and animate other task views into their new positions
Winson8aa99592016-01-19 15:07:07 -08001418 updateLayoutAlgorithm(true /* boundScroll */);
Winson Chung06266772015-12-11 10:24:21 -05001419
1420 // Animate all the tasks into place
Winson409d99a2016-05-10 15:03:46 -07001421 relayoutTaskViews(mAwaitingFirstLayout
1422 ? AnimationProps.IMMEDIATE
1423 : new AnimationProps(DEFAULT_SYNC_STACK_DURATION, Interpolators.FAST_OUT_SLOW_IN));
Winson Chung06266772015-12-11 10:24:21 -05001424 }
1425
Winson8aa99592016-01-19 15:07:07 -08001426 /**
1427 * We expect that the {@link TaskView} associated with the removed task is already hidden.
1428 */
Winson Chung06266772015-12-11 10:24:21 -05001429 @Override
Winson6c8217a2016-05-25 10:53:53 -07001430 public void onStackTaskRemoved(TaskStack stack, Task removedTask, Task newFrontMostTask,
1431 AnimationProps animation, boolean fromDockGesture) {
Winsonaaf33bc2015-12-03 12:02:38 -08001432 if (mFocusedTask == removedTask) {
Winsona0731a12015-12-02 15:10:14 -08001433 resetFocusedTask(removedTask);
1434 }
1435
Winson8aa99592016-01-19 15:07:07 -08001436 // Remove the view associated with this task, we can't rely on updateTransforms
1437 // to work here because the task is no longer in the list
1438 TaskView tv = getChildViewForTask(removedTask);
1439 if (tv != null) {
1440 mViewPool.returnViewToPool(tv);
Winson Chung303e1ff2014-03-07 15:06:19 -08001441 }
1442
Winson8aa99592016-01-19 15:07:07 -08001443 // Remove the task from the ignored set
1444 removeIgnoreTask(removedTask);
1445
1446 // If requested, relayout with the given animation
1447 if (animation != null) {
1448 updateLayoutAlgorithm(true /* boundScroll */);
1449 relayoutTaskViews(animation);
1450 }
Winsonf24f2162016-01-05 12:11:55 -08001451
Winson Chung931c51f2015-12-17 17:08:55 -05001452 // Update the new front most task's action button
1453 if (mScreenPinningEnabled && newFrontMostTask != null) {
Winson Chung1f24c7e2014-07-11 17:06:48 -07001454 TaskView frontTv = getChildViewForTask(newFrontMostTask);
1455 if (frontTv != null) {
Winson Chung931c51f2015-12-17 17:08:55 -05001456 frontTv.showActionButton(true /* fadeIn */, DEFAULT_SYNC_STACK_DURATION);
Winson Chung1f24c7e2014-07-11 17:06:48 -07001457 }
1458 }
1459
Winson397ae742015-11-20 11:27:33 -08001460 // If there are no remaining tasks, then just close recents
Winson4b057c62016-01-12 15:01:52 -08001461 if (mStack.getTaskCount() == 0) {
Winson20684082016-03-16 17:13:34 -07001462 EventBus.getDefault().send(new AllTaskViewsDismissedEvent(fromDockGesture
1463 ? R.string.recents_empty_message
1464 : R.string.recents_empty_message_dismissed_all));
Winson Chung9f49df92014-05-07 18:08:34 -07001465 }
Winson Chung303e1ff2014-03-07 15:06:19 -08001466 }
1467
Winsona1ededd2016-03-25 12:23:12 -07001468 @Override
Winson3b6ba1a2016-03-22 15:37:54 -07001469 public void onStackTasksRemoved(TaskStack stack) {
1470 // Reset the focused task
1471 resetFocusedTask(getFocusedTask());
1472
1473 // Return all the views to the pool
1474 List<TaskView> taskViews = new ArrayList<>();
1475 taskViews.addAll(getTaskViews());
1476 for (int i = taskViews.size() - 1; i >= 0; i--) {
1477 mViewPool.returnViewToPool(taskViews.get(i));
1478 }
1479
1480 // Remove all the ignore tasks
1481 mIgnoreTasks.clear();
1482
1483 // If there are no remaining tasks, then just close recents
1484 EventBus.getDefault().send(new AllTaskViewsDismissedEvent(
1485 R.string.recents_empty_message_dismissed_all));
1486 }
1487
1488 @Override
Winsona1ededd2016-03-25 12:23:12 -07001489 public void onStackTasksUpdated(TaskStack stack) {
1490 // Update the layout and immediately layout
1491 updateLayoutAlgorithm(false /* boundScroll */);
1492 relayoutTaskViews(AnimationProps.IMMEDIATE);
1493
1494 // Rebind all the task views. This will not trigger new resources to be loaded
1495 // unless they have actually changed
1496 List<TaskView> taskViews = getTaskViews();
1497 int taskViewCount = taskViews.size();
1498 for (int i = 0; i < taskViewCount; i++) {
1499 TaskView tv = taskViews.get(i);
1500 bindTaskView(tv, tv.getTask());
1501 }
1502 }
1503
Winson Chung303e1ff2014-03-07 15:06:19 -08001504 /**** ViewPoolConsumer Implementation ****/
1505
1506 @Override
1507 public TaskView createView(Context context) {
Manu Cornetbf8e2902016-12-20 08:29:33 -08001508 if (Recents.getConfiguration().isGridEnabled) {
1509 return (GridTaskView) mInflater.inflate(R.layout.recents_grid_task_view, this, false);
1510 } else {
1511 return (TaskView) mInflater.inflate(R.layout.recents_task_view, this, false);
1512 }
Winson Chung303e1ff2014-03-07 15:06:19 -08001513 }
1514
1515 @Override
Winson05e46ca2016-02-05 15:40:29 -08001516 public void onReturnViewToPool(TaskView tv) {
Winson Chung931c51f2015-12-17 17:08:55 -05001517 final Task task = tv.getTask();
Winson Chung303e1ff2014-03-07 15:06:19 -08001518
Winson43336942016-03-07 14:52:59 -08001519 // Unbind the task from the task view
1520 unbindTaskView(tv, task);
Winson Chung303e1ff2014-03-07 15:06:19 -08001521
Winson Chung931c51f2015-12-17 17:08:55 -05001522 // Reset the view properties and view state
Winsonf0009882016-06-01 12:22:55 -07001523 tv.clearAccessibilityFocus();
Winson Chung8eaeb7d2014-06-25 15:10:59 -07001524 tv.resetViewProperties();
Winsonf24f2162016-01-05 12:11:55 -08001525 tv.setFocusedState(false, false /* requestViewFocus */);
Winson Chungb0a28ea2014-10-28 15:21:35 -07001526 tv.setClipViewInStack(false);
Winson Chung931c51f2015-12-17 17:08:55 -05001527 if (mScreenPinningEnabled) {
Winsonf24f2162016-01-05 12:11:55 -08001528 tv.hideActionButton(false /* fadeOut */, 0 /* duration */, false /* scaleDown */, null);
Winson Chung931c51f2015-12-17 17:08:55 -05001529 }
Winson3c107162016-01-22 15:53:00 -08001530
1531 // Detach the view from the hierarchy
1532 detachViewFromParent(tv);
1533 // Update the task views list after removing the task view
1534 updateTaskViewsList();
Winson Chung303e1ff2014-03-07 15:06:19 -08001535 }
1536
1537 @Override
Winson05e46ca2016-02-05 15:40:29 -08001538 public void onPickUpViewFromPool(TaskView tv, Task task, boolean isNewView) {
Winson Chung8eaeb7d2014-06-25 15:10:59 -07001539 // Find the index where this task should be placed in the stack
Winson250608a2015-11-24 15:00:31 -08001540 int taskIndex = mStack.indexOfStackTask(task);
Winsona78a8f32015-12-03 10:55:01 -08001541 int insertIndex = findTaskViewInsertIndex(task, taskIndex);
Winson Chung8eaeb7d2014-06-25 15:10:59 -07001542
Winson Chung303e1ff2014-03-07 15:06:19 -08001543 // Add/attach the view to the hierarchy
Winson Chung303e1ff2014-03-07 15:06:19 -08001544 if (isNewView) {
Winson70f0bf72016-02-01 14:05:29 -08001545 if (mInMeasureLayout) {
1546 // If we are measuring the layout, then just add the view normally as it will be
1547 // laid out during the layout pass
1548 addView(tv, insertIndex);
1549 } else {
1550 // Otherwise, this is from a bindVisibleTaskViews() call outside the measure/layout
1551 // pass, and we should layout the new child ourselves
1552 ViewGroup.LayoutParams params = tv.getLayoutParams();
1553 if (params == null) {
1554 params = generateDefaultLayoutParams();
1555 }
1556 addViewInLayout(tv, insertIndex, params, true /* preventRequestLayout */);
1557 measureTaskView(tv);
Winsonc69249f2016-03-28 13:38:39 -07001558 layoutTaskView(true /* changed */, tv);
Winson70f0bf72016-02-01 14:05:29 -08001559 }
Winson Chung303e1ff2014-03-07 15:06:19 -08001560 } else {
1561 attachViewToParent(tv, insertIndex, tv.getLayoutParams());
1562 }
Winson Chung6ac8bd62015-01-07 16:38:35 -08001563 // Update the task views list after adding the new task view
1564 updateTaskViewsList();
Winson Chungb0a28ea2014-10-28 15:21:35 -07001565
Winson43336942016-03-07 14:52:59 -08001566 // Bind the task view to the new task
1567 bindTaskView(tv, task);
Winson3c107162016-01-22 15:53:00 -08001568
Winson Chungb0a28ea2014-10-28 15:21:35 -07001569 // Set the new state for this view, including the callbacks and view clipping
1570 tv.setCallbacks(this);
1571 tv.setTouchEnabled(true);
1572 tv.setClipViewInStack(true);
Winsonaaf33bc2015-12-03 12:02:38 -08001573 if (mFocusedTask == task) {
Winsonf24f2162016-01-05 12:11:55 -08001574 tv.setFocusedState(true, false /* requestViewFocus */);
Winson4b9cded2016-01-26 16:26:47 -08001575 if (mStartTimerIndicatorDuration > 0) {
Peter Schillerb124d562015-12-11 21:31:17 -08001576 // The timer indicator couldn't be started before, so start it now
Winson4b9cded2016-01-26 16:26:47 -08001577 tv.getHeaderView().startFocusTimerIndicator(mStartTimerIndicatorDuration);
1578 mStartTimerIndicatorDuration = 0;
Peter Schillerb124d562015-12-11 21:31:17 -08001579 }
Winsona0731a12015-12-02 15:10:14 -08001580 }
Winson Chung931c51f2015-12-17 17:08:55 -05001581
1582 // Restore the action button visibility if it is the front most task view
Winson35a8b042016-01-22 09:41:09 -08001583 if (mScreenPinningEnabled && tv.getTask() ==
1584 mStack.getStackFrontMostTask(false /* includeFreeform */)) {
Winson Chung931c51f2015-12-17 17:08:55 -05001585 tv.showActionButton(false /* fadeIn */, 0 /* fadeInDuration */);
1586 }
Winson Chung303e1ff2014-03-07 15:06:19 -08001587 }
1588
1589 @Override
1590 public boolean hasPreferredData(TaskView tv, Task preferredData) {
1591 return (tv.getTask() == preferredData);
1592 }
1593
Winson43336942016-03-07 14:52:59 -08001594 private void bindTaskView(TaskView tv, Task task) {
1595 // Rebind the task and request that this task's data be filled into the TaskView
Winsonfc48b072016-04-21 11:20:11 -07001596 tv.onTaskBound(task, mTouchExplorationEnabled, mDisplayOrientation, mDisplayRect);
Winson43336942016-03-07 14:52:59 -08001597
Manu Cornetbf8e2902016-12-20 08:29:33 -08001598 // If the doze trigger has already fired, then update the state for this task view
1599 if (mUIDozeTrigger.isAsleep() ||
Manu Cornet8ff78542016-12-20 17:17:51 -08001600 Recents.getSystemServices().hasFreeformWorkspaceSupport() ||
1601 useGridLayout()) {
Manu Cornetbf8e2902016-12-20 08:29:33 -08001602 tv.setNoUserInteractionState();
1603 }
1604
Winson43336942016-03-07 14:52:59 -08001605 // Load the task data
Winsond2a03062016-04-15 11:19:07 -07001606 Recents.getTaskLoader().loadTaskData(task);
Winson43336942016-03-07 14:52:59 -08001607 }
1608
1609 private void unbindTaskView(TaskView tv, Task task) {
1610 // Report that this task's data is no longer being used
1611 Recents.getTaskLoader().unloadTaskData(task);
1612 }
1613
Winson Chung303e1ff2014-03-07 15:06:19 -08001614 /**** TaskViewCallbacks Implementation ****/
1615
1616 @Override
Winson Chung93748a12014-07-13 17:43:31 -07001617 public void onTaskViewClipStateChanged(TaskView tv) {
Winson8aa99592016-01-19 15:07:07 -08001618 if (!mTaskViewsClipDirty) {
1619 mTaskViewsClipDirty = true;
1620 invalidate();
1621 }
Winson Chung93748a12014-07-13 17:43:31 -07001622 }
1623
Winson1c846142016-01-22 11:34:38 -08001624 /**** TaskStackLayoutAlgorithm.TaskStackLayoutAlgorithmCallbacks ****/
1625
1626 @Override
Winson66474132016-02-23 18:45:47 -08001627 public void onFocusStateChanged(int prevFocusState, int curFocusState) {
Winson1c846142016-01-22 11:34:38 -08001628 if (mDeferredTaskViewLayoutAnimation == null) {
1629 mUIDozeTrigger.poke();
Winsonbe8e6962016-02-01 14:27:52 -08001630 relayoutTaskViewsOnNextFrame(AnimationProps.IMMEDIATE);
Winson1c846142016-01-22 11:34:38 -08001631 }
1632 }
1633
Winson Chung012ef362014-07-31 18:36:25 -07001634 /**** TaskStackViewScroller.TaskStackViewScrollerCallbacks ****/
1635
1636 @Override
Winson14991502016-02-15 15:40:08 -08001637 public void onStackScrollChanged(float prevScroll, float curScroll, AnimationProps animation) {
Winson Chung012ef362014-07-31 18:36:25 -07001638 mUIDozeTrigger.poke();
Winson8aa99592016-01-19 15:07:07 -08001639 if (animation != null) {
1640 relayoutTaskViewsOnNextFrame(animation);
1641 }
Winsonc29ff002015-11-20 16:00:45 -08001642
Manu Cornetbf8e2902016-12-20 08:29:33 -08001643 // In grid layout, the stack action button always remains visible.
1644 if (mEnterAnimationComplete && !useGridLayout()) {
Winson8f6ee482016-03-18 17:51:48 -07001645 if (prevScroll > SHOW_STACK_ACTION_BUTTON_SCROLL_THRESHOLD &&
Winson3b6ba1a2016-03-22 15:37:54 -07001646 curScroll <= SHOW_STACK_ACTION_BUTTON_SCROLL_THRESHOLD &&
1647 mStack.getTaskCount() > 0) {
Winson8f6ee482016-03-18 17:51:48 -07001648 EventBus.getDefault().send(new ShowStackActionButtonEvent(true /* translate */));
1649 } else if (prevScroll < HIDE_STACK_ACTION_BUTTON_SCROLL_THRESHOLD &&
1650 curScroll >= HIDE_STACK_ACTION_BUTTON_SCROLL_THRESHOLD) {
1651 EventBus.getDefault().send(new HideStackActionButtonEvent());
Winson49df4202016-01-25 17:33:34 -08001652 }
Winsonc29ff002015-11-20 16:00:45 -08001653 }
Winson Chung012ef362014-07-31 18:36:25 -07001654 }
1655
Winsone6c90732015-09-24 16:06:29 -07001656 /**** EventBus Events ****/
Winson Chung9f49df92014-05-07 18:08:34 -07001657
Winsone6c90732015-09-24 16:06:29 -07001658 public final void onBusEvent(PackagesChangedEvent event) {
Winson Chung04400672014-10-17 14:53:30 -07001659 // Compute which components need to be removed
Winson55003902016-01-12 12:00:37 -08001660 ArraySet<ComponentName> removedComponents = mStack.computeComponentsRemoved(
Winsone7f138c2015-10-22 16:15:21 -07001661 event.packageName, event.userId);
Winson Chung04400672014-10-17 14:53:30 -07001662
Winson Chung9f49df92014-05-07 18:08:34 -07001663 // For other tasks, just remove them directly if they no longer exist
Winson250608a2015-11-24 15:00:31 -08001664 ArrayList<Task> tasks = mStack.getStackTasks();
Winson Chung9f49df92014-05-07 18:08:34 -07001665 for (int i = tasks.size() - 1; i >= 0; i--) {
1666 final Task t = tasks.get(i);
Winsone7f138c2015-10-22 16:15:21 -07001667 if (removedComponents.contains(t.key.getComponent())) {
Winson0d14d4d2015-10-26 17:05:04 -07001668 final TaskView tv = getChildViewForTask(t);
Winson Chung9f49df92014-05-07 18:08:34 -07001669 if (tv != null) {
1670 // For visible children, defer removing the task until after the animation
Winsonf24f2162016-01-05 12:11:55 -08001671 tv.dismissTask();
Winson Chung9f49df92014-05-07 18:08:34 -07001672 } else {
1673 // Otherwise, remove the task from the stack immediately
Winson20684082016-03-16 17:13:34 -07001674 mStack.removeTask(t, AnimationProps.IMMEDIATE, false /* fromDockGesture */);
Winson Chung9f49df92014-05-07 18:08:34 -07001675 }
1676 }
1677 }
1678 }
Winson2536c7e2015-10-01 15:49:31 -07001679
Winson Chung48f2cda2015-12-11 13:20:12 -05001680 public final void onBusEvent(LaunchTaskEvent event) {
1681 // Cancel any doze triggers once a task is launched
1682 mUIDozeTrigger.stopDozing();
1683 }
1684
Winsonb61e6542016-02-04 14:37:18 -08001685 public final void onBusEvent(LaunchNextTaskRequestEvent event) {
Winsonbd53a312016-09-21 12:13:32 -07001686 if (mAwaitingFirstLayout) {
1687 mLaunchNextAfterFirstMeasure = true;
1688 return;
1689 }
1690
Manu Cornetbf8e2902016-12-20 08:29:33 -08001691 final Task launchTask = mStack.getNextLaunchTarget();
1692 if (launchTask != null) {
Winsonb61e6542016-02-04 14:37:18 -08001693 // Stop all animations
Winsonb61e6542016-02-04 14:37:18 -08001694 cancelAllTaskViewAnimations();
1695
Winsonf8597b22016-03-23 18:44:26 -07001696 float curScroll = mStackScroller.getStackScroll();
1697 float targetScroll = mLayoutAlgorithm.getStackScrollForTaskAtInitialOffset(launchTask);
1698 float absScrollDiff = Math.abs(targetScroll - curScroll);
1699 if (getChildViewForTask(launchTask) == null || absScrollDiff > 0.35f) {
1700 int duration = (int) (LAUNCH_NEXT_SCROLL_BASE_DURATION +
1701 absScrollDiff * LAUNCH_NEXT_SCROLL_INCR_DURATION);
1702 mStackScroller.animateScroll(targetScroll,
Winson96e61342016-03-15 16:47:19 -07001703 duration, new Runnable() {
1704 @Override
1705 public void run() {
1706 EventBus.getDefault().send(new LaunchTaskEvent(
1707 getChildViewForTask(launchTask), launchTask, null,
1708 INVALID_STACK_ID, false /* screenPinningRequested */));
1709 }
1710 });
1711 } else {
1712 EventBus.getDefault().send(new LaunchTaskEvent(getChildViewForTask(launchTask),
1713 launchTask, null, INVALID_STACK_ID, false /* screenPinningRequested */));
1714 }
Winsond9342902016-02-25 10:18:33 -08001715
1716 MetricsLogger.action(getContext(), MetricsEvent.OVERVIEW_LAUNCH_PREVIOUS_TASK,
1717 launchTask.key.getComponent().toString());
Winsonbc0f8cd2016-03-15 15:44:48 -07001718 } else if (mStack.getTaskCount() == 0) {
1719 // If there are no tasks, then just hide recents back to home.
1720 EventBus.getDefault().send(new HideRecentsEvent(false, true));
Winsonb61e6542016-02-04 14:37:18 -08001721 }
1722 }
1723
Winsonef064132016-01-05 12:11:31 -08001724 public final void onBusEvent(LaunchTaskStartedEvent event) {
Winsonf24f2162016-01-05 12:11:55 -08001725 mAnimationHelper.startLaunchTaskAnimation(event.taskView, event.screenPinningRequested,
1726 event.getAnimationTrigger());
Winson0d14d4d2015-10-26 17:05:04 -07001727 }
Winson2536c7e2015-10-01 15:49:31 -07001728
Winsonef064132016-01-05 12:11:31 -08001729 public final void onBusEvent(DismissRecentsToHomeAnimationStarted event) {
1730 // Stop any scrolling
Winson61560f02016-05-02 16:36:20 -07001731 mTouchHandler.cancelNonDismissTaskAnimations();
Winsonef064132016-01-05 12:11:31 -08001732 mStackScroller.stopScroller();
1733 mStackScroller.stopBoundScrollAnimation();
Winson60df2462016-04-23 16:06:50 -07001734 cancelDeferredTaskViewLayoutAnimation();
Winson2536c7e2015-10-01 15:49:31 -07001735
Winsonef064132016-01-05 12:11:31 -08001736 // Start the task animations
Winsonf24f2162016-01-05 12:11:55 -08001737 mAnimationHelper.startExitToHomeAnimation(event.animated, event.getAnimationTrigger());
Winsonef064132016-01-05 12:11:31 -08001738
1739 // Dismiss the freeform workspace background
Winson50448632016-02-01 18:04:59 -08001740 int taskViewExitToHomeDuration = TaskStackAnimationHelper.EXIT_TO_HOME_TRANSLATION_DURATION;
Winsonbe8e6962016-02-01 14:27:52 -08001741 animateFreeformWorkspaceBackgroundAlpha(0, new AnimationProps(taskViewExitToHomeDuration,
1742 Interpolators.FAST_OUT_SLOW_IN));
Winson0d14d4d2015-10-26 17:05:04 -07001743 }
Winson42be4312015-10-10 11:51:08 -07001744
Winson0d14d4d2015-10-26 17:05:04 -07001745 public final void onBusEvent(DismissFocusedTaskViewEvent event) {
Winsonaaf33bc2015-12-03 12:02:38 -08001746 if (mFocusedTask != null) {
1747 TaskView tv = getChildViewForTask(mFocusedTask);
1748 if (tv != null) {
1749 tv.dismissTask();
1750 }
1751 resetFocusedTask(mFocusedTask);
Winson2536c7e2015-10-01 15:49:31 -07001752 }
1753 }
Winsone7f138c2015-10-22 16:15:21 -07001754
Winson3b6ba1a2016-03-22 15:37:54 -07001755 public final void onBusEvent(DismissTaskViewEvent event) {
Winsonef064132016-01-05 12:11:31 -08001756 // For visible children, defer removing the task until after the animation
Manu Cornet5df76672017-01-11 15:14:14 -08001757 mAnimationHelper.startDeleteTaskAnimation(
1758 event.taskView, useGridLayout(), event.getAnimationTrigger());
Winson3b6ba1a2016-03-22 15:37:54 -07001759 }
1760
1761 public final void onBusEvent(final DismissAllTaskViewsEvent event) {
1762 // Keep track of the tasks which will have their data removed
1763 ArrayList<Task> tasks = new ArrayList<>(mStack.getStackTasks());
Manu Cornet5df76672017-01-11 15:14:14 -08001764 mAnimationHelper.startDeleteAllTasksAnimation(
1765 getTaskViews(), useGridLayout(), event.getAnimationTrigger());
Winson3b6ba1a2016-03-22 15:37:54 -07001766 event.addPostAnimationCallback(new Runnable() {
1767 @Override
1768 public void run() {
1769 // Announce for accessibility
1770 announceForAccessibility(getContext().getString(
1771 R.string.accessibility_recents_all_items_dismissed));
1772
1773 // Remove all tasks and delete the task data for all tasks
1774 mStack.removeAllTasks();
1775 for (int i = tasks.size() - 1; i >= 0; i--) {
1776 EventBus.getDefault().send(new DeleteTaskDataEvent(tasks.get(i)));
1777 }
1778
1779 MetricsLogger.action(getContext(), MetricsEvent.OVERVIEW_DISMISS_ALL);
1780 }
1781 });
1782
Winsonef064132016-01-05 12:11:31 -08001783 }
1784
1785 public final void onBusEvent(TaskViewDismissedEvent event) {
Winson3b6ba1a2016-03-22 15:37:54 -07001786 // Announce for accessibility
1787 announceForAccessibility(getContext().getString(
1788 R.string.accessibility_recents_item_dismissed, event.task.title));
1789
1790 // Remove the task from the stack
Winson61560f02016-05-02 16:36:20 -07001791 mStack.removeTask(event.task, event.animation, false /* fromDockGesture */);
Winsonef064132016-01-05 12:11:31 -08001792 EventBus.getDefault().send(new DeleteTaskDataEvent(event.task));
Winson42329522016-02-05 10:39:46 -08001793
1794 MetricsLogger.action(getContext(), MetricsEvent.OVERVIEW_DISMISS,
1795 event.task.key.getComponent().toString());
Winsonef064132016-01-05 12:11:31 -08001796 }
1797
1798 public final void onBusEvent(FocusNextTaskViewEvent event) {
Winson66474132016-02-23 18:45:47 -08001799 // Stop any scrolling
1800 mStackScroller.stopScroller();
1801 mStackScroller.stopBoundScrollAnimation();
1802
Peter Schillerb124d562015-12-11 21:31:17 -08001803 setRelativeFocusedTask(true, false /* stackTasksOnly */, true /* animated */, false,
Winson4b9cded2016-01-26 16:26:47 -08001804 event.timerIndicatorDuration);
Winsonef064132016-01-05 12:11:31 -08001805 }
1806
1807 public final void onBusEvent(FocusPreviousTaskViewEvent event) {
Winson66474132016-02-23 18:45:47 -08001808 // Stop any scrolling
1809 mStackScroller.stopScroller();
1810 mStackScroller.stopBoundScrollAnimation();
1811
Winsonef064132016-01-05 12:11:31 -08001812 setRelativeFocusedTask(false, false /* stackTasksOnly */, true /* animated */);
1813 }
1814
Winsone7f138c2015-10-22 16:15:21 -07001815 public final void onBusEvent(UserInteractionEvent event) {
1816 // Poke the doze trigger on user interaction
1817 mUIDozeTrigger.poke();
Winson4b9cded2016-01-26 16:26:47 -08001818
1819 RecentsDebugFlags debugFlags = Recents.getDebugFlags();
1820 if (debugFlags.isFastToggleRecentsEnabled() && mFocusedTask != null) {
Winsonc5ef63f2016-01-21 14:39:23 -08001821 TaskView tv = getChildViewForTask(mFocusedTask);
1822 if (tv != null) {
1823 tv.getHeaderView().cancelFocusTimerIndicator();
1824 }
Peter Schillerb124d562015-12-11 21:31:17 -08001825 }
Winsone7f138c2015-10-22 16:15:21 -07001826 }
1827
Winsoneca4ab62015-11-04 10:50:28 -08001828 public final void onBusEvent(DragStartEvent event) {
Winson70f0bf72016-02-01 14:05:29 -08001829 // Ensure that the drag task is not animated
1830 addIgnoreTask(event.task);
1831
Winsoneca4ab62015-11-04 10:50:28 -08001832 if (event.task.isFreeformTask()) {
1833 // Animate to the front of the stack
Winsond9529612016-01-28 13:29:49 -08001834 mStackScroller.animateScroll(mLayoutAlgorithm.mInitialScrollP, null);
Winsoneca4ab62015-11-04 10:50:28 -08001835 }
Winsonf24f2162016-01-05 12:11:55 -08001836
1837 // Enlarge the dragged view slightly
1838 float finalScale = event.taskView.getScaleX() * DRAG_SCALE_FACTOR;
1839 mLayoutAlgorithm.getStackTransform(event.task, getScroller().getStackScroll(),
Jiaquan He26f637b2016-12-27 14:44:14 -08001840 mTmpTransform, null);
Winsonf24f2162016-01-05 12:11:55 -08001841 mTmpTransform.scale = finalScale;
Winson3e874742016-01-07 10:08:17 -08001842 mTmpTransform.translationZ = mLayoutAlgorithm.mMaxTranslationZ + 1;
Winson0a461f02016-04-19 10:51:12 -07001843 mTmpTransform.dimAlpha = 0f;
Winsonf24f2162016-01-05 12:11:55 -08001844 updateTaskViewToTransform(event.taskView, mTmpTransform,
Winsonbe8e6962016-02-01 14:27:52 -08001845 new AnimationProps(DRAG_SCALE_DURATION, Interpolators.FAST_OUT_SLOW_IN));
Winsoneca4ab62015-11-04 10:50:28 -08001846 }
1847
1848 public final void onBusEvent(DragStartInitializeDropTargetsEvent event) {
1849 SystemServicesProxy ssp = Recents.getSystemServices();
1850 if (ssp.hasFreeformWorkspaceSupport()) {
1851 event.handler.registerDropTargetForCurrentDrag(mStackDropTarget);
1852 event.handler.registerDropTargetForCurrentDrag(mFreeformWorkspaceDropTarget);
1853 }
1854 }
1855
1856 public final void onBusEvent(DragDropTargetChangedEvent event) {
Winson3f32e7e2016-04-20 17:18:08 -07001857 AnimationProps animation = new AnimationProps(SLOW_SYNC_STACK_DURATION,
1858 Interpolators.FAST_OUT_SLOW_IN);
Winson59924fe2016-03-17 14:13:18 -07001859 boolean ignoreTaskOverrides = false;
Winson3e874742016-01-07 10:08:17 -08001860 if (event.dropTarget instanceof TaskStack.DockState) {
1861 // Calculate the new task stack bounds that matches the window size that Recents will
1862 // have after the drop
1863 final TaskStack.DockState dockState = (TaskStack.DockState) event.dropTarget;
Winson670ea712016-04-12 17:02:26 -07001864 Rect systemInsets = new Rect(mStableLayoutAlgorithm.mSystemInsets);
1865 // When docked, the nav bar insets are consumed and the activity is measured without
1866 // insets. However, the window bounds include the insets, so we need to subtract them
1867 // here to make them identical.
1868 int height = getMeasuredHeight();
1869 height -= systemInsets.bottom;
1870 systemInsets.bottom = 0;
Winsonfc48b072016-04-21 11:20:11 -07001871 mStackBounds.set(dockState.getDockedTaskStackBounds(mDisplayRect, getMeasuredWidth(),
Winson67c79572016-04-13 14:02:18 -07001872 height, mDividerSize, systemInsets,
Winson59924fe2016-03-17 14:13:18 -07001873 mLayoutAlgorithm, getResources(), mWindowRect));
Winson670ea712016-04-12 17:02:26 -07001874 mLayoutAlgorithm.setSystemInsets(systemInsets);
Winsonfc48b072016-04-21 11:20:11 -07001875 mLayoutAlgorithm.initialize(mDisplayRect, mWindowRect, mStackBounds,
Winson8aa99592016-01-19 15:07:07 -08001876 TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack));
1877 updateLayoutAlgorithm(true /* boundScroll */);
Winson59924fe2016-03-17 14:13:18 -07001878 ignoreTaskOverrides = true;
Winson3e874742016-01-07 10:08:17 -08001879 } else {
Winson8aa99592016-01-19 15:07:07 -08001880 // Restore the pre-drag task stack bounds, but ensure that we don't layout the dragging
1881 // task view, so add it back to the ignore set after updating the layout
Winson8aa99592016-01-19 15:07:07 -08001882 removeIgnoreTask(event.task);
Winson27c28f82016-05-05 16:16:50 -07001883 updateLayoutToStableBounds();
Winson8aa99592016-01-19 15:07:07 -08001884 addIgnoreTask(event.task);
Winson3e874742016-01-07 10:08:17 -08001885 }
Winson27c28f82016-05-05 16:16:50 -07001886 relayoutTaskViews(animation, null /* animationOverrides */, ignoreTaskOverrides);
Winsoneca4ab62015-11-04 10:50:28 -08001887 }
1888
1889 public final void onBusEvent(final DragEndEvent event) {
Winson479f7442015-11-25 15:16:27 -08001890 // We don't handle drops on the dock regions
1891 if (event.dropTarget instanceof TaskStack.DockState) {
Winson59924fe2016-03-17 14:13:18 -07001892 // However, we do need to reset the overrides, since the last state of this task stack
1893 // view layout was ignoring task overrides (see DragDropTargetChangedEvent handler)
1894 mLayoutAlgorithm.clearUnfocusedTaskOverrides();
Winsoneca4ab62015-11-04 10:50:28 -08001895 return;
1896 }
1897
Winson479f7442015-11-25 15:16:27 -08001898 boolean isFreeformTask = event.task.isFreeformTask();
1899 boolean hasChangedStacks =
1900 (!isFreeformTask && event.dropTarget == mFreeformWorkspaceDropTarget) ||
1901 (isFreeformTask && event.dropTarget == mStackDropTarget);
Winson479f7442015-11-25 15:16:27 -08001902
Winson5b7dd532015-12-01 16:02:12 -08001903 if (hasChangedStacks) {
Winson479f7442015-11-25 15:16:27 -08001904 // Move the task to the right position in the stack (ie. the front of the stack if
Winson8aa99592016-01-19 15:07:07 -08001905 // freeform or the front of the stack if fullscreen). Note, we MUST move the tasks
Winson479f7442015-11-25 15:16:27 -08001906 // before we update their stack ids, otherwise, the keys will have changed.
1907 if (event.dropTarget == mFreeformWorkspaceDropTarget) {
1908 mStack.moveTaskToStack(event.task, FREEFORM_WORKSPACE_STACK_ID);
Winson479f7442015-11-25 15:16:27 -08001909 } else if (event.dropTarget == mStackDropTarget) {
1910 mStack.moveTaskToStack(event.task, FULLSCREEN_WORKSPACE_STACK_ID);
Winson479f7442015-11-25 15:16:27 -08001911 }
Winson8aa99592016-01-19 15:07:07 -08001912 updateLayoutAlgorithm(true /* boundScroll */);
Winson479f7442015-11-25 15:16:27 -08001913
1914 // Move the task to the new stack in the system after the animation completes
Winson Chungaaeaac12015-12-16 16:49:36 -05001915 event.addPostAnimationCallback(new Runnable() {
Winson479f7442015-11-25 15:16:27 -08001916 @Override
1917 public void run() {
1918 SystemServicesProxy ssp = Recents.getSystemServices();
1919 ssp.moveTaskToStack(event.task.key.id, event.task.key.stackId);
1920 }
1921 });
Winsoneca4ab62015-11-04 10:50:28 -08001922 }
Winsoneca4ab62015-11-04 10:50:28 -08001923
Winson27c28f82016-05-05 16:16:50 -07001924 // Restore the task, so that relayout will apply to it below
Winson8aa99592016-01-19 15:07:07 -08001925 removeIgnoreTask(event.task);
Winson27c28f82016-05-05 16:16:50 -07001926
1927 // Convert the dragging task view back to its final layout-space rect
1928 Utilities.setViewFrameFromTranslation(event.taskView);
1929
1930 // Animate all the tasks into place
1931 ArrayMap<Task, AnimationProps> animationOverrides = new ArrayMap<>();
1932 animationOverrides.put(event.task, new AnimationProps(SLOW_SYNC_STACK_DURATION,
1933 Interpolators.FAST_OUT_SLOW_IN,
1934 event.getAnimationTrigger().decrementOnAnimationEnd()));
1935 relayoutTaskViews(new AnimationProps(SLOW_SYNC_STACK_DURATION,
1936 Interpolators.FAST_OUT_SLOW_IN));
1937 event.getAnimationTrigger().increment();
1938 }
1939
1940 public final void onBusEvent(final DragEndCancelledEvent event) {
1941 // Restore the pre-drag task stack bounds, including the dragging task view
1942 removeIgnoreTask(event.task);
1943 updateLayoutToStableBounds();
1944
1945 // Convert the dragging task view back to its final layout-space rect
1946 Utilities.setViewFrameFromTranslation(event.taskView);
1947
1948 // Animate all the tasks into place
1949 ArrayMap<Task, AnimationProps> animationOverrides = new ArrayMap<>();
1950 animationOverrides.put(event.task, new AnimationProps(SLOW_SYNC_STACK_DURATION,
1951 Interpolators.FAST_OUT_SLOW_IN,
1952 event.getAnimationTrigger().decrementOnAnimationEnd()));
1953 relayoutTaskViews(new AnimationProps(SLOW_SYNC_STACK_DURATION,
1954 Interpolators.FAST_OUT_SLOW_IN));
1955 event.getAnimationTrigger().increment();
Winsoneca4ab62015-11-04 10:50:28 -08001956 }
1957
Winson8b1871d2015-11-20 09:56:20 -08001958 public final void onBusEvent(IterateRecentsEvent event) {
Winson Chungd6b78a32015-12-15 10:22:45 -05001959 if (!mEnterAnimationComplete) {
1960 // Cancel the previous task's window transition before animating the focused state
1961 EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(null));
1962 }
Winson8b1871d2015-11-20 09:56:20 -08001963 }
1964
Winsone5f1faa2015-11-20 12:26:23 -08001965 public final void onBusEvent(EnterRecentsWindowAnimationCompletedEvent event) {
1966 mEnterAnimationComplete = true;
Winsonef064132016-01-05 12:11:31 -08001967
Winson4b057c62016-01-12 15:01:52 -08001968 if (mStack.getTaskCount() > 0) {
Winsonef064132016-01-05 12:11:31 -08001969 // Start the task enter animations
Winsonf24f2162016-01-05 12:11:55 -08001970 mAnimationHelper.startEnterAnimation(event.getAnimationTrigger());
Winsonef064132016-01-05 12:11:31 -08001971
1972 // Add a runnable to the post animation ref counter to clear all the views
1973 event.addPostAnimationCallback(new Runnable() {
1974 @Override
1975 public void run() {
1976 // Start the dozer to trigger to trigger any UI that shows after a timeout
Manu Cornetbf8e2902016-12-20 08:29:33 -08001977 if (!Recents.getSystemServices().hasFreeformWorkspaceSupport()) {
1978 mUIDozeTrigger.startDozing();
1979 }
Winsonef064132016-01-05 12:11:31 -08001980
1981 // Update the focused state here -- since we only set the focused task without
1982 // requesting view focus in onFirstLayout(), actually request view focus and
1983 // animate the focused state if we are alt-tabbing now, after the window enter
1984 // animation is completed
1985 if (mFocusedTask != null) {
1986 RecentsConfiguration config = Recents.getConfiguration();
1987 RecentsActivityLaunchState launchState = config.getLaunchState();
1988 setFocusedTask(mStack.indexOfStackTask(mFocusedTask),
1989 false /* scrollToTask */, launchState.launchedWithAltTab);
Winsonf0009882016-06-01 12:22:55 -07001990 TaskView focusedTaskView = getChildViewForTask(mFocusedTask);
1991 if (mTouchExplorationEnabled && focusedTaskView != null) {
1992 focusedTaskView.requestAccessibilityFocus();
1993 }
Winsonef064132016-01-05 12:11:31 -08001994 }
Winson4b9cded2016-01-26 16:26:47 -08001995
1996 EventBus.getDefault().send(new EnterRecentsTaskStackAnimationCompletedEvent());
Winsonef064132016-01-05 12:11:31 -08001997 }
1998 });
1999 }
Winsone5f1faa2015-11-20 12:26:23 -08002000 }
2001
Winsonb1e71d02015-11-23 12:40:23 -08002002 public final void onBusEvent(UpdateFreeformTaskViewVisibilityEvent event) {
2003 List<TaskView> taskViews = getTaskViews();
2004 int taskViewCount = taskViews.size();
2005 for (int i = 0; i < taskViewCount; i++) {
2006 TaskView tv = taskViews.get(i);
2007 Task task = tv.getTask();
Winson Chung296278a2015-12-17 12:09:02 -05002008 if (task.isFreeformTask()) {
Winsonb1e71d02015-11-23 12:40:23 -08002009 tv.setVisibility(event.visible ? View.VISIBLE : View.INVISIBLE);
2010 }
2011 }
2012 }
2013
Winsond2a03062016-04-15 11:19:07 -07002014 public final void onBusEvent(final MultiWindowStateChangedEvent event) {
Winson95ee8732016-04-26 14:46:58 -07002015 if (event.inMultiWindow || !event.showDeferredAnimation) {
Winsond2a03062016-04-15 11:19:07 -07002016 setTasks(event.stack, true /* allowNotifyStackChanges */);
2017 } else {
2018 // Reset the launch state before handling the multiwindow change
2019 RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
2020 launchState.reset();
2021
Winson67c79572016-04-13 14:02:18 -07002022 // Defer until the next frame to ensure that we have received all the system insets, and
2023 // initial layout updates
Winsond2a03062016-04-15 11:19:07 -07002024 event.getAnimationTrigger().increment();
Winson67c79572016-04-13 14:02:18 -07002025 post(new Runnable() {
Winson931845f2016-02-24 19:38:41 -08002026 @Override
2027 public void run() {
Winson67c79572016-04-13 14:02:18 -07002028 // Scroll the stack to the front to see the undocked task
Winsond2a03062016-04-15 11:19:07 -07002029 mAnimationHelper.startNewStackScrollAnimation(event.stack,
2030 event.getAnimationTrigger());
2031 event.getAnimationTrigger().decrement();
Winson931845f2016-02-24 19:38:41 -08002032 }
2033 });
2034 }
Winsond9529612016-01-28 13:29:49 -08002035 }
2036
Winsone693aaf2016-03-01 12:05:59 -08002037 public final void onBusEvent(ConfigurationChangedEvent event) {
Winsonfc48b072016-04-21 11:20:11 -07002038 if (event.fromDeviceOrientationChange) {
2039 mDisplayOrientation = Utilities.getAppConfiguration(mContext).orientation;
2040 mDisplayRect = Recents.getSystemServices().getDisplayRect();
Winson399d21e2016-05-18 13:26:29 -07002041
2042 // Always stop the scroller, otherwise, we may continue setting the stack scroll to the
2043 // wrong bounds in the new layout
2044 mStackScroller.stopScroller();
Winsonfc48b072016-04-21 11:20:11 -07002045 }
Winson670ea712016-04-12 17:02:26 -07002046 reloadOnConfigurationChange();
Winson619e40c2016-03-25 16:12:35 -07002047
2048 // Notify the task views of the configuration change so they can reload their resources
2049 if (!event.fromMultiWindow) {
2050 mTmpTaskViews.clear();
2051 mTmpTaskViews.addAll(getTaskViews());
2052 mTmpTaskViews.addAll(mViewPool.getViews());
2053 int taskViewCount = mTmpTaskViews.size();
2054 for (int i = 0; i < taskViewCount; i++) {
2055 mTmpTaskViews.get(i).onConfigurationChanged();
2056 }
2057 }
2058
Manu Cornetbf8e2902016-12-20 08:29:33 -08002059 // Update the Clear All button in case we're switching in or out of grid layout.
2060 updateStackActionButtonVisibility();
2061
Winson44849b82016-03-29 10:45:45 -07002062 // Trigger a new layout and update to the initial state if necessary
Winson67c79572016-04-13 14:02:18 -07002063 if (event.fromMultiWindow) {
Winson44849b82016-03-29 10:45:45 -07002064 mInitialState = INITIAL_STATE_UPDATE_LAYOUT_ONLY;
Winson670ea712016-04-12 17:02:26 -07002065 requestLayout();
Winson67c79572016-04-13 14:02:18 -07002066 } else if (event.fromDeviceOrientationChange) {
2067 mInitialState = INITIAL_STATE_UPDATE_ALL;
2068 requestLayout();
Winson44849b82016-03-29 10:45:45 -07002069 }
Winson670ea712016-04-12 17:02:26 -07002070 }
2071
Jorim Jaggidb21bbd2016-04-18 15:32:07 -07002072 public final void onBusEvent(RecentsGrowingEvent event) {
2073 mResetToInitialStateWhenResized = true;
2074 }
2075
Winson670ea712016-04-12 17:02:26 -07002076 public void reloadOnConfigurationChange() {
2077 mStableLayoutAlgorithm.reloadOnConfigurationChange(getContext());
2078 mLayoutAlgorithm.reloadOnConfigurationChange(getContext());
Jiaquan He26f637b2016-12-27 14:44:14 -08002079
2080 boolean hasDockedTask = Recents.getSystemServices().hasDockedTask();
Winsone693aaf2016-03-01 12:05:59 -08002081 }
2082
Winson0d14d4d2015-10-26 17:05:04 -07002083 /**
Winsona78a8f32015-12-03 10:55:01 -08002084 * Starts an alpha animation on the freeform workspace background.
2085 */
Winsonbe8e6962016-02-01 14:27:52 -08002086 private void animateFreeformWorkspaceBackgroundAlpha(int targetAlpha,
2087 AnimationProps animation) {
Winsona78a8f32015-12-03 10:55:01 -08002088 if (mFreeformWorkspaceBackground.getAlpha() == targetAlpha) {
2089 return;
2090 }
2091
2092 Utilities.cancelAnimationWithoutCallbacks(mFreeformWorkspaceBackgroundAnimator);
2093 mFreeformWorkspaceBackgroundAnimator = ObjectAnimator.ofInt(mFreeformWorkspaceBackground,
Winson3e874742016-01-07 10:08:17 -08002094 Utilities.DRAWABLE_ALPHA, mFreeformWorkspaceBackground.getAlpha(), targetAlpha);
Winsonbe8e6962016-02-01 14:27:52 -08002095 mFreeformWorkspaceBackgroundAnimator.setStartDelay(
2096 animation.getDuration(AnimationProps.ALPHA));
2097 mFreeformWorkspaceBackgroundAnimator.setDuration(
2098 animation.getDuration(AnimationProps.ALPHA));
2099 mFreeformWorkspaceBackgroundAnimator.setInterpolator(
2100 animation.getInterpolator(AnimationProps.ALPHA));
Winsona78a8f32015-12-03 10:55:01 -08002101 mFreeformWorkspaceBackgroundAnimator.start();
2102 }
2103
2104 /**
Winson8aa99592016-01-19 15:07:07 -08002105 * Returns the insert index for the task in the current set of task views. If the given task
Winsona78a8f32015-12-03 10:55:01 -08002106 * is already in the task view list, then this method returns the insert index assuming it
2107 * is first removed at the previous index.
2108 *
2109 * @param task the task we are finding the index for
2110 * @param taskIndex the index of the task in the stack
2111 */
2112 private int findTaskViewInsertIndex(Task task, int taskIndex) {
2113 if (taskIndex != -1) {
2114 List<TaskView> taskViews = getTaskViews();
2115 boolean foundTaskView = false;
2116 int taskViewCount = taskViews.size();
2117 for (int i = 0; i < taskViewCount; i++) {
2118 Task tvTask = taskViews.get(i).getTask();
2119 if (tvTask == task) {
2120 foundTaskView = true;
2121 } else if (taskIndex < mStack.indexOfStackTask(tvTask)) {
2122 if (foundTaskView) {
2123 return i - 1;
2124 } else {
2125 return i;
2126 }
2127 }
2128 }
2129 }
2130 return -1;
2131 }
Winson Chungde750de2015-12-11 10:26:06 -05002132
2133 /**
Manu Cornetbf8e2902016-12-20 08:29:33 -08002134 * Check whether we should use the grid layout.
Manu Cornetbf8e2902016-12-20 08:29:33 -08002135 */
2136 public boolean useGridLayout() {
Manu Cornetc0432c62017-01-13 09:21:26 -08002137 return mLayoutAlgorithm.useGridLayout();
Manu Cornetbf8e2902016-12-20 08:29:33 -08002138 }
2139
2140 /**
Winson6ea25882016-01-13 10:59:04 -08002141 * Reads current system flags related to accessibility and screen pinning.
2142 */
2143 private void readSystemFlags() {
2144 SystemServicesProxy ssp = Recents.getSystemServices();
2145 mTouchExplorationEnabled = ssp.isTouchExplorationEnabled();
2146 mScreenPinningEnabled = ssp.getSystemSetting(getContext(),
2147 Settings.System.LOCK_TO_APP_ENABLED) != 0;
2148 }
Winsond72c3152016-04-05 15:33:35 -07002149
Manu Cornetbf8e2902016-12-20 08:29:33 -08002150 private void updateStackActionButtonVisibility() {
2151 // Always show the button in grid layout.
2152 if (useGridLayout() ||
2153 (mStackScroller.getStackScroll() < SHOW_STACK_ACTION_BUTTON_SCROLL_THRESHOLD &&
2154 mStack.getTaskCount() > 0)) {
2155 EventBus.getDefault().send(new ShowStackActionButtonEvent(false /* translate */));
2156 } else {
2157 EventBus.getDefault().send(new HideStackActionButtonEvent());
2158 }
2159 }
2160
Winsond72c3152016-04-05 15:33:35 -07002161 public void dump(String prefix, PrintWriter writer) {
2162 String innerPrefix = prefix + " ";
2163 String id = Integer.toHexString(System.identityHashCode(this));
2164
2165 writer.print(prefix); writer.print(TAG);
2166 writer.print(" hasDefRelayout=");
2167 writer.print(mDeferredTaskViewLayoutAnimation != null ? "Y" : "N");
2168 writer.print(" clipDirty="); writer.print(mTaskViewsClipDirty ? "Y" : "N");
2169 writer.print(" awaitingFirstLayout="); writer.print(mAwaitingFirstLayout ? "Y" : "N");
2170 writer.print(" initialState="); writer.print(mInitialState);
2171 writer.print(" inMeasureLayout="); writer.print(mInMeasureLayout ? "Y" : "N");
2172 writer.print(" enterAnimCompleted="); writer.print(mEnterAnimationComplete ? "Y" : "N");
2173 writer.print(" touchExplorationOn="); writer.print(mTouchExplorationEnabled ? "Y" : "N");
2174 writer.print(" screenPinningOn="); writer.print(mScreenPinningEnabled ? "Y" : "N");
2175 writer.print(" numIgnoreTasks="); writer.print(mIgnoreTasks.size());
2176 writer.print(" numViewPool="); writer.print(mViewPool.getViews().size());
2177 writer.print(" stableStackBounds="); writer.print(Utilities.dumpRect(mStableStackBounds));
2178 writer.print(" stackBounds="); writer.print(Utilities.dumpRect(mStackBounds));
2179 writer.print(" stableWindow="); writer.print(Utilities.dumpRect(mStableWindowRect));
2180 writer.print(" window="); writer.print(Utilities.dumpRect(mWindowRect));
Winsonfc48b072016-04-21 11:20:11 -07002181 writer.print(" display="); writer.print(Utilities.dumpRect(mDisplayRect));
2182 writer.print(" orientation="); writer.print(mDisplayOrientation);
Winsond72c3152016-04-05 15:33:35 -07002183 writer.print(" [0x"); writer.print(id); writer.print("]");
2184 writer.println();
2185
2186 if (mFocusedTask != null) {
2187 writer.print(innerPrefix);
2188 writer.print("Focused task: ");
Winson67c79572016-04-13 14:02:18 -07002189 mFocusedTask.dump("", writer);
Winsond72c3152016-04-05 15:33:35 -07002190 }
2191
Winson Chungeb2206c2017-01-03 12:37:08 -08002192 int numTaskViews = mTaskViews.size();
2193 for (int i = 0; i < numTaskViews; i++) {
2194 mTaskViews.get(i).dump(innerPrefix, writer);
2195 }
2196
Winsond72c3152016-04-05 15:33:35 -07002197 mLayoutAlgorithm.dump(innerPrefix, writer);
2198 mStackScroller.dump(innerPrefix, writer);
2199 }
Winson Chunga4cc9662014-07-25 12:10:38 -07002200}