1f24f21695f5609d06402cf61e3500d408b99bdcbWinson/* 2f24f21695f5609d06402cf61e3500d408b99bdcbWinson * Copyright (C) 2015 The Android Open Source Project 3f24f21695f5609d06402cf61e3500d408b99bdcbWinson * 4f24f21695f5609d06402cf61e3500d408b99bdcbWinson * Licensed under the Apache License, Version 2.0 (the "License"); 5f24f21695f5609d06402cf61e3500d408b99bdcbWinson * you may not use this file except in compliance with the License. 6f24f21695f5609d06402cf61e3500d408b99bdcbWinson * You may obtain a copy of the License at 7f24f21695f5609d06402cf61e3500d408b99bdcbWinson * 8f24f21695f5609d06402cf61e3500d408b99bdcbWinson * http://www.apache.org/licenses/LICENSE-2.0 9f24f21695f5609d06402cf61e3500d408b99bdcbWinson * 10f24f21695f5609d06402cf61e3500d408b99bdcbWinson * Unless required by applicable law or agreed to in writing, software 11f24f21695f5609d06402cf61e3500d408b99bdcbWinson * distributed under the License is distributed on an "AS IS" BASIS, 12f24f21695f5609d06402cf61e3500d408b99bdcbWinson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f24f21695f5609d06402cf61e3500d408b99bdcbWinson * See the License for the specific language governing permissions and 14f24f21695f5609d06402cf61e3500d408b99bdcbWinson * limitations under the License. 15f24f21695f5609d06402cf61e3500d408b99bdcbWinson */ 16f24f21695f5609d06402cf61e3500d408b99bdcbWinson 17f24f21695f5609d06402cf61e3500d408b99bdcbWinsonpackage com.android.systemui.recents.views; 18f24f21695f5609d06402cf61e3500d408b99bdcbWinson 19f24f21695f5609d06402cf61e3500d408b99bdcbWinsonimport android.animation.Animator; 20f24f21695f5609d06402cf61e3500d408b99bdcbWinsonimport android.animation.AnimatorListenerAdapter; 213f32e7eba7aec02edbf542cc11eee13264a5abf2Winsonimport android.animation.TimeInterpolator; 22aa0dea7a4a5b0861bc040e3f5db633a272146fb7Winsonimport android.animation.ValueAnimator; 23f24f21695f5609d06402cf61e3500d408b99bdcbWinsonimport android.content.Context; 24545c5c20d3b1f424b2f1917a262a5e8130dab6d0Jorim Jaggiimport android.content.res.Configuration; 25f24f21695f5609d06402cf61e3500d408b99bdcbWinsonimport android.content.res.Resources; 263f3d744d5c51d3ecc06af22ac7d69f4437671915Winsonimport android.util.Log; 27f24f21695f5609d06402cf61e3500d408b99bdcbWinsonimport android.view.View; 2805e46ca8f3d24cf333e745c8cebb420b2996e9eaWinsonimport android.view.animation.Interpolator; 2950448630a49a9602eb53561d1c022890d07449d0Winsonimport android.view.animation.PathInterpolator; 30c0d7058b14c24cd07912f5629c26b39b7b4673d5Winson 31c0d7058b14c24cd07912f5629c26b39b7b4673d5Winsonimport com.android.systemui.Interpolators; 32f24f21695f5609d06402cf61e3500d408b99bdcbWinsonimport com.android.systemui.R; 33f24f21695f5609d06402cf61e3500d408b99bdcbWinsonimport com.android.systemui.recents.Recents; 34f24f21695f5609d06402cf61e3500d408b99bdcbWinsonimport com.android.systemui.recents.RecentsActivityLaunchState; 35f24f21695f5609d06402cf61e3500d408b99bdcbWinsonimport com.android.systemui.recents.RecentsConfiguration; 36f24f21695f5609d06402cf61e3500d408b99bdcbWinsonimport com.android.systemui.recents.misc.ReferenceCountedTrigger; 37f24f21695f5609d06402cf61e3500d408b99bdcbWinsonimport com.android.systemui.recents.model.Task; 38f24f21695f5609d06402cf61e3500d408b99bdcbWinsonimport com.android.systemui.recents.model.TaskStack; 39f24f21695f5609d06402cf61e3500d408b99bdcbWinson 4005e46ca8f3d24cf333e745c8cebb420b2996e9eaWinsonimport java.util.ArrayList; 41f24f21695f5609d06402cf61e3500d408b99bdcbWinsonimport java.util.List; 42f24f21695f5609d06402cf61e3500d408b99bdcbWinson 43f24f21695f5609d06402cf61e3500d408b99bdcbWinson/** 44f24f21695f5609d06402cf61e3500d408b99bdcbWinson * A helper class to create task view animations for {@link TaskView}s in a {@link TaskStackView}, 45f24f21695f5609d06402cf61e3500d408b99bdcbWinson * but not the contents of the {@link TaskView}s. 46f24f21695f5609d06402cf61e3500d408b99bdcbWinson */ 47f24f21695f5609d06402cf61e3500d408b99bdcbWinsonpublic class TaskStackAnimationHelper { 48f24f21695f5609d06402cf61e3500d408b99bdcbWinson 49f24f21695f5609d06402cf61e3500d408b99bdcbWinson /** 50f24f21695f5609d06402cf61e3500d408b99bdcbWinson * Callbacks from the helper to coordinate view-content animations with view animations. 51f24f21695f5609d06402cf61e3500d408b99bdcbWinson */ 52f24f21695f5609d06402cf61e3500d408b99bdcbWinson public interface Callbacks { 53f24f21695f5609d06402cf61e3500d408b99bdcbWinson /** 54f24f21695f5609d06402cf61e3500d408b99bdcbWinson * Callback to prepare for the start animation for the launch target {@link TaskView}. 55f24f21695f5609d06402cf61e3500d408b99bdcbWinson */ 56f24f21695f5609d06402cf61e3500d408b99bdcbWinson void onPrepareLaunchTargetForEnterAnimation(); 57f24f21695f5609d06402cf61e3500d408b99bdcbWinson 58f24f21695f5609d06402cf61e3500d408b99bdcbWinson /** 59f24f21695f5609d06402cf61e3500d408b99bdcbWinson * Callback to start the animation for the launch target {@link TaskView}. 60f24f21695f5609d06402cf61e3500d408b99bdcbWinson */ 61e693aafe0511c2a7ffc571b22abeefba44046225Winson void onStartLaunchTargetEnterAnimation(TaskViewTransform transform, int duration, 62e693aafe0511c2a7ffc571b22abeefba44046225Winson boolean screenPinningEnabled, ReferenceCountedTrigger postAnimationTrigger); 63f24f21695f5609d06402cf61e3500d408b99bdcbWinson 64f24f21695f5609d06402cf61e3500d408b99bdcbWinson /** 65f24f21695f5609d06402cf61e3500d408b99bdcbWinson * Callback to start the animation for the launch target {@link TaskView} when it is 66f24f21695f5609d06402cf61e3500d408b99bdcbWinson * launched from Recents. 67f24f21695f5609d06402cf61e3500d408b99bdcbWinson */ 68f24f21695f5609d06402cf61e3500d408b99bdcbWinson void onStartLaunchTargetLaunchAnimation(int duration, boolean screenPinningRequested, 69f24f21695f5609d06402cf61e3500d408b99bdcbWinson ReferenceCountedTrigger postAnimationTrigger); 7059924fe0d9136cf349759bea1e06b661603f95feWinson 7159924fe0d9136cf349759bea1e06b661603f95feWinson /** 7259924fe0d9136cf349759bea1e06b661603f95feWinson * Callback to start the animation for the front {@link TaskView} if there is no launch 7359924fe0d9136cf349759bea1e06b661603f95feWinson * target. 7459924fe0d9136cf349759bea1e06b661603f95feWinson */ 7559924fe0d9136cf349759bea1e06b661603f95feWinson void onStartFrontTaskEnterAnimation(boolean screenPinningEnabled); 76f24f21695f5609d06402cf61e3500d408b99bdcbWinson } 77f24f21695f5609d06402cf61e3500d408b99bdcbWinson 783f32e7eba7aec02edbf542cc11eee13264a5abf2Winson private static final int DOUBLE_FRAME_OFFSET_MS = 33; 7950448630a49a9602eb53561d1c022890d07449d0Winson private static final int FRAME_OFFSET_MS = 16; 8050448630a49a9602eb53561d1c022890d07449d0Winson 813f32e7eba7aec02edbf542cc11eee13264a5abf2Winson private static final int ENTER_EXIT_NUM_ANIMATING_TASKS = 5; 82899327f5cbbfb0eae5562b262ccea860c98f6bc4Jorim Jaggi 833f32e7eba7aec02edbf542cc11eee13264a5abf2Winson private static final int ENTER_FROM_HOME_ALPHA_DURATION = 100; 843f32e7eba7aec02edbf542cc11eee13264a5abf2Winson public static final int ENTER_FROM_HOME_TRANSLATION_DURATION = 300; 853f32e7eba7aec02edbf542cc11eee13264a5abf2Winson private static final Interpolator ENTER_FROM_HOME_TRANSLATION_INTERPOLATOR = 863f32e7eba7aec02edbf542cc11eee13264a5abf2Winson Interpolators.LINEAR_OUT_SLOW_IN; 873f32e7eba7aec02edbf542cc11eee13264a5abf2Winson private static final Interpolator ENTER_FROM_HOME_ALPHA_INTERPOLATOR = Interpolators.LINEAR; 883f32e7eba7aec02edbf542cc11eee13264a5abf2Winson 893f32e7eba7aec02edbf542cc11eee13264a5abf2Winson public static final int EXIT_TO_HOME_TRANSLATION_DURATION = 200; 903f32e7eba7aec02edbf542cc11eee13264a5abf2Winson private static final Interpolator EXIT_TO_HOME_TRANSLATION_INTERPOLATOR = 913f32e7eba7aec02edbf542cc11eee13264a5abf2Winson new PathInterpolator(0.4f, 0, 0.6f, 1f); 923f32e7eba7aec02edbf542cc11eee13264a5abf2Winson 933f32e7eba7aec02edbf542cc11eee13264a5abf2Winson private static final int DISMISS_TASK_DURATION = 175; 943f32e7eba7aec02edbf542cc11eee13264a5abf2Winson private static final int DISMISS_ALL_TASKS_DURATION = 200; 953f32e7eba7aec02edbf542cc11eee13264a5abf2Winson private static final Interpolator DISMISS_ALL_TRANSLATION_INTERPOLATOR = 9650448630a49a9602eb53561d1c022890d07449d0Winson new PathInterpolator(0.4f, 0, 1f, 1f); 9750448630a49a9602eb53561d1c022890d07449d0Winson 983f32e7eba7aec02edbf542cc11eee13264a5abf2Winson private static final Interpolator FOCUS_NEXT_TASK_INTERPOLATOR = 9905e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson new PathInterpolator(0.4f, 0, 0, 1f); 1003f32e7eba7aec02edbf542cc11eee13264a5abf2Winson private static final Interpolator FOCUS_IN_FRONT_NEXT_TASK_INTERPOLATOR = 10105e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson new PathInterpolator(0, 0, 0, 1f); 1023f32e7eba7aec02edbf542cc11eee13264a5abf2Winson private static final Interpolator FOCUS_BEHIND_NEXT_TASK_INTERPOLATOR = 1033f32e7eba7aec02edbf542cc11eee13264a5abf2Winson Interpolators.LINEAR_OUT_SLOW_IN; 10405e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson 1053f32e7eba7aec02edbf542cc11eee13264a5abf2Winson private static final Interpolator ENTER_WHILE_DOCKING_INTERPOLATOR = 1063f32e7eba7aec02edbf542cc11eee13264a5abf2Winson Interpolators.LINEAR_OUT_SLOW_IN; 107899327f5cbbfb0eae5562b262ccea860c98f6bc4Jorim Jaggi 10845c8048f4f8996f085c78621efaf710c907ce213Manu Cornet private final int mEnterAndExitFromHomeTranslationOffset; 109f24f21695f5609d06402cf61e3500d408b99bdcbWinson private TaskStackView mStackView; 110f24f21695f5609d06402cf61e3500d408b99bdcbWinson 111f24f21695f5609d06402cf61e3500d408b99bdcbWinson private TaskViewTransform mTmpTransform = new TaskViewTransform(); 11205e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson private ArrayList<TaskViewTransform> mTmpCurrentTaskTransforms = new ArrayList<>(); 11305e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson private ArrayList<TaskViewTransform> mTmpFinalTaskTransforms = new ArrayList<>(); 114f24f21695f5609d06402cf61e3500d408b99bdcbWinson 115f24f21695f5609d06402cf61e3500d408b99bdcbWinson public TaskStackAnimationHelper(Context context, TaskStackView stackView) { 116f24f21695f5609d06402cf61e3500d408b99bdcbWinson mStackView = stackView; 11745c8048f4f8996f085c78621efaf710c907ce213Manu Cornet mEnterAndExitFromHomeTranslationOffset = Recents.getConfiguration().isGridEnabled 11845c8048f4f8996f085c78621efaf710c907ce213Manu Cornet ? 0 : DOUBLE_FRAME_OFFSET_MS; 119f24f21695f5609d06402cf61e3500d408b99bdcbWinson } 120f24f21695f5609d06402cf61e3500d408b99bdcbWinson 121f24f21695f5609d06402cf61e3500d408b99bdcbWinson /** 122f24f21695f5609d06402cf61e3500d408b99bdcbWinson * Prepares the stack views and puts them in their initial animation state while visible, before 123f24f21695f5609d06402cf61e3500d408b99bdcbWinson * the in-app enter animations start (after the window-transition completes). 124f24f21695f5609d06402cf61e3500d408b99bdcbWinson */ 125f24f21695f5609d06402cf61e3500d408b99bdcbWinson public void prepareForEnterAnimation() { 126f24f21695f5609d06402cf61e3500d408b99bdcbWinson RecentsConfiguration config = Recents.getConfiguration(); 127f24f21695f5609d06402cf61e3500d408b99bdcbWinson RecentsActivityLaunchState launchState = config.getLaunchState(); 128f24f21695f5609d06402cf61e3500d408b99bdcbWinson Resources res = mStackView.getResources(); 129e370e15056d45eba83d6ad96d9be46a17eddff29Jorim Jaggi Resources appResources = mStackView.getContext().getApplicationContext().getResources(); 130f24f21695f5609d06402cf61e3500d408b99bdcbWinson 131f24f21695f5609d06402cf61e3500d408b99bdcbWinson TaskStackLayoutAlgorithm stackLayout = mStackView.getStackAlgorithm(); 132f24f21695f5609d06402cf61e3500d408b99bdcbWinson TaskStackViewScroller stackScroller = mStackView.getScroller(); 133f24f21695f5609d06402cf61e3500d408b99bdcbWinson TaskStack stack = mStackView.getStack(); 134f24f21695f5609d06402cf61e3500d408b99bdcbWinson Task launchTargetTask = stack.getLaunchTarget(); 135f24f21695f5609d06402cf61e3500d408b99bdcbWinson 136f24f21695f5609d06402cf61e3500d408b99bdcbWinson // Break early if there are no tasks 1374b057c6787624b75613769a857ccdf51114bb7f2Winson if (stack.getTaskCount() == 0) { 138f24f21695f5609d06402cf61e3500d408b99bdcbWinson return; 139f24f21695f5609d06402cf61e3500d408b99bdcbWinson } 140f24f21695f5609d06402cf61e3500d408b99bdcbWinson 14140a227337712a881cca4d7dd04323380287b9e40Winson int offscreenYOffset = stackLayout.mStackRect.height(); 142f24f21695f5609d06402cf61e3500d408b99bdcbWinson int taskViewAffiliateGroupEnterOffset = res.getDimensionPixelSize( 14359924fe0d9136cf349759bea1e06b661603f95feWinson R.dimen.recents_task_stack_animation_affiliate_enter_offset); 144899327f5cbbfb0eae5562b262ccea860c98f6bc4Jorim Jaggi int launchedWhileDockingOffset = res.getDimensionPixelSize( 14559924fe0d9136cf349759bea1e06b661603f95feWinson R.dimen.recents_task_stack_animation_launched_while_docking_offset); 146e370e15056d45eba83d6ad96d9be46a17eddff29Jorim Jaggi boolean isLandscape = appResources.getConfiguration().orientation 147e370e15056d45eba83d6ad96d9be46a17eddff29Jorim Jaggi == Configuration.ORIENTATION_LANDSCAPE; 148f24f21695f5609d06402cf61e3500d408b99bdcbWinson 149f24f21695f5609d06402cf61e3500d408b99bdcbWinson // Prepare each of the task views for their enter animation from front to back 150f24f21695f5609d06402cf61e3500d408b99bdcbWinson List<TaskView> taskViews = mStackView.getTaskViews(); 151f24f21695f5609d06402cf61e3500d408b99bdcbWinson for (int i = taskViews.size() - 1; i >= 0; i--) { 152f24f21695f5609d06402cf61e3500d408b99bdcbWinson TaskView tv = taskViews.get(i); 153f24f21695f5609d06402cf61e3500d408b99bdcbWinson Task task = tv.getTask(); 1548a3ef375ee299e4a84936c87f66098fa9fb84258Winson boolean currentTaskOccludesLaunchTarget = launchTargetTask != null && 1558a3ef375ee299e4a84936c87f66098fa9fb84258Winson launchTargetTask.group != null && 1568a3ef375ee299e4a84936c87f66098fa9fb84258Winson launchTargetTask.group.isTaskAboveTask(task, launchTargetTask); 1578a3ef375ee299e4a84936c87f66098fa9fb84258Winson boolean hideTask = launchTargetTask != null && 1588a3ef375ee299e4a84936c87f66098fa9fb84258Winson launchTargetTask.isFreeformTask() && 1598a3ef375ee299e4a84936c87f66098fa9fb84258Winson task.isFreeformTask(); 160f24f21695f5609d06402cf61e3500d408b99bdcbWinson 161f24f21695f5609d06402cf61e3500d408b99bdcbWinson // Get the current transform for the task, which will be used to position it offscreen 162f24f21695f5609d06402cf61e3500d408b99bdcbWinson stackLayout.getStackTransform(task, stackScroller.getStackScroll(), mTmpTransform, 16326f637b5553facca5f7873c28d19af36ffccd634Jiaquan He null); 164f24f21695f5609d06402cf61e3500d408b99bdcbWinson 165f24f21695f5609d06402cf61e3500d408b99bdcbWinson if (hideTask) { 166f24f21695f5609d06402cf61e3500d408b99bdcbWinson tv.setVisibility(View.INVISIBLE); 167c69249fd6f30398780342baed8752ef0eeff7d22Winson } else if (launchState.launchedFromApp && !launchState.launchedViaDockGesture) { 168f24f21695f5609d06402cf61e3500d408b99bdcbWinson if (task.isLaunchTarget) { 169f24f21695f5609d06402cf61e3500d408b99bdcbWinson tv.onPrepareLaunchTargetForEnterAnimation(); 170f24f21695f5609d06402cf61e3500d408b99bdcbWinson } else if (currentTaskOccludesLaunchTarget) { 171f24f21695f5609d06402cf61e3500d408b99bdcbWinson // Move the task view slightly lower so we can animate it in 172c69249fd6f30398780342baed8752ef0eeff7d22Winson mTmpTransform.rect.offset(0, taskViewAffiliateGroupEnterOffset); 173c69249fd6f30398780342baed8752ef0eeff7d22Winson mTmpTransform.alpha = 0f; 174c69249fd6f30398780342baed8752ef0eeff7d22Winson mStackView.updateTaskViewToTransform(tv, mTmpTransform, 175c69249fd6f30398780342baed8752ef0eeff7d22Winson AnimationProps.IMMEDIATE); 17665c851e6e9e08656744b6f66d3da188e3283b17dWinson tv.setClipViewInStack(false); 177f24f21695f5609d06402cf61e3500d408b99bdcbWinson } 178f24f21695f5609d06402cf61e3500d408b99bdcbWinson } else if (launchState.launchedFromHome) { 179f24f21695f5609d06402cf61e3500d408b99bdcbWinson // Move the task view off screen (below) so we can animate it in 180c69249fd6f30398780342baed8752ef0eeff7d22Winson mTmpTransform.rect.offset(0, offscreenYOffset); 181c69249fd6f30398780342baed8752ef0eeff7d22Winson mTmpTransform.alpha = 0f; 182c69249fd6f30398780342baed8752ef0eeff7d22Winson mStackView.updateTaskViewToTransform(tv, mTmpTransform, AnimationProps.IMMEDIATE); 183c69249fd6f30398780342baed8752ef0eeff7d22Winson } else if (launchState.launchedViaDockGesture) { 184545c5c20d3b1f424b2f1917a262a5e8130dab6d0Jorim Jaggi int offset = isLandscape 185545c5c20d3b1f424b2f1917a262a5e8130dab6d0Jorim Jaggi ? launchedWhileDockingOffset 186545c5c20d3b1f424b2f1917a262a5e8130dab6d0Jorim Jaggi : (int) (offscreenYOffset * 0.9f); 187545c5c20d3b1f424b2f1917a262a5e8130dab6d0Jorim Jaggi mTmpTransform.rect.offset(0, offset); 188c69249fd6f30398780342baed8752ef0eeff7d22Winson mTmpTransform.alpha = 0f; 189c69249fd6f30398780342baed8752ef0eeff7d22Winson mStackView.updateTaskViewToTransform(tv, mTmpTransform, AnimationProps.IMMEDIATE); 190f24f21695f5609d06402cf61e3500d408b99bdcbWinson } 191f24f21695f5609d06402cf61e3500d408b99bdcbWinson } 192f24f21695f5609d06402cf61e3500d408b99bdcbWinson } 193f24f21695f5609d06402cf61e3500d408b99bdcbWinson 194f24f21695f5609d06402cf61e3500d408b99bdcbWinson /** 195f24f21695f5609d06402cf61e3500d408b99bdcbWinson * Starts the in-app enter animation, which animates the {@link TaskView}s to their final places 196f24f21695f5609d06402cf61e3500d408b99bdcbWinson * depending on how Recents was triggered. 197f24f21695f5609d06402cf61e3500d408b99bdcbWinson */ 198f24f21695f5609d06402cf61e3500d408b99bdcbWinson public void startEnterAnimation(final ReferenceCountedTrigger postAnimationTrigger) { 199f24f21695f5609d06402cf61e3500d408b99bdcbWinson RecentsConfiguration config = Recents.getConfiguration(); 200f24f21695f5609d06402cf61e3500d408b99bdcbWinson RecentsActivityLaunchState launchState = config.getLaunchState(); 201f24f21695f5609d06402cf61e3500d408b99bdcbWinson Resources res = mStackView.getResources(); 202e370e15056d45eba83d6ad96d9be46a17eddff29Jorim Jaggi Resources appRes = mStackView.getContext().getApplicationContext().getResources(); 203f24f21695f5609d06402cf61e3500d408b99bdcbWinson 204f24f21695f5609d06402cf61e3500d408b99bdcbWinson TaskStackLayoutAlgorithm stackLayout = mStackView.getStackAlgorithm(); 205f24f21695f5609d06402cf61e3500d408b99bdcbWinson TaskStackViewScroller stackScroller = mStackView.getScroller(); 206f24f21695f5609d06402cf61e3500d408b99bdcbWinson TaskStack stack = mStackView.getStack(); 207f24f21695f5609d06402cf61e3500d408b99bdcbWinson Task launchTargetTask = stack.getLaunchTarget(); 208f24f21695f5609d06402cf61e3500d408b99bdcbWinson 209f24f21695f5609d06402cf61e3500d408b99bdcbWinson // Break early if there are no tasks 2104b057c6787624b75613769a857ccdf51114bb7f2Winson if (stack.getTaskCount() == 0) { 211f24f21695f5609d06402cf61e3500d408b99bdcbWinson return; 212f24f21695f5609d06402cf61e3500d408b99bdcbWinson } 213f24f21695f5609d06402cf61e3500d408b99bdcbWinson 214f24f21695f5609d06402cf61e3500d408b99bdcbWinson int taskViewEnterFromAppDuration = res.getInteger( 215f24f21695f5609d06402cf61e3500d408b99bdcbWinson R.integer.recents_task_enter_from_app_duration); 21665c851e6e9e08656744b6f66d3da188e3283b17dWinson int taskViewEnterFromAffiliatedAppDuration = res.getInteger( 21765c851e6e9e08656744b6f66d3da188e3283b17dWinson R.integer.recents_task_enter_from_affiliated_app_duration); 218e370e15056d45eba83d6ad96d9be46a17eddff29Jorim Jaggi int dockGestureAnimDuration = appRes.getInteger( 219e370e15056d45eba83d6ad96d9be46a17eddff29Jorim Jaggi R.integer.long_press_dock_anim_duration); 220f24f21695f5609d06402cf61e3500d408b99bdcbWinson 221f24f21695f5609d06402cf61e3500d408b99bdcbWinson // Create enter animations for each of the views from front to back 222f24f21695f5609d06402cf61e3500d408b99bdcbWinson List<TaskView> taskViews = mStackView.getTaskViews(); 223f24f21695f5609d06402cf61e3500d408b99bdcbWinson int taskViewCount = taskViews.size(); 224f24f21695f5609d06402cf61e3500d408b99bdcbWinson for (int i = taskViewCount - 1; i >= 0; i--) { 22550448630a49a9602eb53561d1c022890d07449d0Winson int taskIndexFromFront = taskViewCount - i - 1; 226899327f5cbbfb0eae5562b262ccea860c98f6bc4Jorim Jaggi int taskIndexFromBack = i; 22765c851e6e9e08656744b6f66d3da188e3283b17dWinson final TaskView tv = taskViews.get(i); 228f24f21695f5609d06402cf61e3500d408b99bdcbWinson Task task = tv.getTask(); 2298a3ef375ee299e4a84936c87f66098fa9fb84258Winson boolean currentTaskOccludesLaunchTarget = launchTargetTask != null && 2308a3ef375ee299e4a84936c87f66098fa9fb84258Winson launchTargetTask.group != null && 2318a3ef375ee299e4a84936c87f66098fa9fb84258Winson launchTargetTask.group.isTaskAboveTask(task, launchTargetTask); 232f24f21695f5609d06402cf61e3500d408b99bdcbWinson 233f24f21695f5609d06402cf61e3500d408b99bdcbWinson // Get the current transform for the task, which will be updated to the final transform 234f24f21695f5609d06402cf61e3500d408b99bdcbWinson // to animate to depending on how recents was invoked 235f24f21695f5609d06402cf61e3500d408b99bdcbWinson stackLayout.getStackTransform(task, stackScroller.getStackScroll(), mTmpTransform, 23626f637b5553facca5f7873c28d19af36ffccd634Jiaquan He null); 237f24f21695f5609d06402cf61e3500d408b99bdcbWinson 238c69249fd6f30398780342baed8752ef0eeff7d22Winson if (launchState.launchedFromApp && !launchState.launchedViaDockGesture) { 239f24f21695f5609d06402cf61e3500d408b99bdcbWinson if (task.isLaunchTarget) { 240e693aafe0511c2a7ffc571b22abeefba44046225Winson tv.onStartLaunchTargetEnterAnimation(mTmpTransform, 241e693aafe0511c2a7ffc571b22abeefba44046225Winson taskViewEnterFromAppDuration, mStackView.mScreenPinningEnabled, 242e693aafe0511c2a7ffc571b22abeefba44046225Winson postAnimationTrigger); 243f24f21695f5609d06402cf61e3500d408b99bdcbWinson } else { 244f24f21695f5609d06402cf61e3500d408b99bdcbWinson // Animate the task up if it was occluding the launch target 245f24f21695f5609d06402cf61e3500d408b99bdcbWinson if (currentTaskOccludesLaunchTarget) { 246be8e696a1f40a61c52a74022f4f084fdc0600f90Winson AnimationProps taskAnimation = new AnimationProps( 247c0d7058b14c24cd07912f5629c26b39b7b4673d5Winson taskViewEnterFromAffiliatedAppDuration, Interpolators.ALPHA_IN, 24865c851e6e9e08656744b6f66d3da188e3283b17dWinson new AnimatorListenerAdapter() { 24965c851e6e9e08656744b6f66d3da188e3283b17dWinson @Override 25065c851e6e9e08656744b6f66d3da188e3283b17dWinson public void onAnimationEnd(Animator animation) { 25165c851e6e9e08656744b6f66d3da188e3283b17dWinson postAnimationTrigger.decrement(); 25259924fe0d9136cf349759bea1e06b661603f95feWinson tv.setClipViewInStack(true); 25365c851e6e9e08656744b6f66d3da188e3283b17dWinson } 25465c851e6e9e08656744b6f66d3da188e3283b17dWinson }); 255f24f21695f5609d06402cf61e3500d408b99bdcbWinson postAnimationTrigger.increment(); 256f24f21695f5609d06402cf61e3500d408b99bdcbWinson mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation); 257f24f21695f5609d06402cf61e3500d408b99bdcbWinson } 258f24f21695f5609d06402cf61e3500d408b99bdcbWinson } 259f24f21695f5609d06402cf61e3500d408b99bdcbWinson 260f24f21695f5609d06402cf61e3500d408b99bdcbWinson } else if (launchState.launchedFromHome) { 2613f32e7eba7aec02edbf542cc11eee13264a5abf2Winson // Animate the tasks up, but offset the animations to be relative to the front-most 2623f32e7eba7aec02edbf542cc11eee13264a5abf2Winson // task animation 26350448630a49a9602eb53561d1c022890d07449d0Winson AnimationProps taskAnimation = new AnimationProps() 2643f32e7eba7aec02edbf542cc11eee13264a5abf2Winson .setInitialPlayTime(AnimationProps.BOUNDS, 2653f32e7eba7aec02edbf542cc11eee13264a5abf2Winson Math.min(ENTER_EXIT_NUM_ANIMATING_TASKS, taskIndexFromFront) * 26645c8048f4f8996f085c78621efaf710c907ce213Manu Cornet mEnterAndExitFromHomeTranslationOffset) 2673f32e7eba7aec02edbf542cc11eee13264a5abf2Winson .setStartDelay(AnimationProps.ALPHA, 2683f32e7eba7aec02edbf542cc11eee13264a5abf2Winson Math.min(ENTER_EXIT_NUM_ANIMATING_TASKS, taskIndexFromFront) * 2693f32e7eba7aec02edbf542cc11eee13264a5abf2Winson FRAME_OFFSET_MS) 2703f32e7eba7aec02edbf542cc11eee13264a5abf2Winson .setDuration(AnimationProps.BOUNDS, ENTER_FROM_HOME_TRANSLATION_DURATION) 27150448630a49a9602eb53561d1c022890d07449d0Winson .setDuration(AnimationProps.ALPHA, ENTER_FROM_HOME_ALPHA_DURATION) 27250448630a49a9602eb53561d1c022890d07449d0Winson .setInterpolator(AnimationProps.BOUNDS, 27350448630a49a9602eb53561d1c022890d07449d0Winson ENTER_FROM_HOME_TRANSLATION_INTERPOLATOR) 2743f32e7eba7aec02edbf542cc11eee13264a5abf2Winson .setInterpolator(AnimationProps.ALPHA, ENTER_FROM_HOME_ALPHA_INTERPOLATOR) 27550448630a49a9602eb53561d1c022890d07449d0Winson .setListener(postAnimationTrigger.decrementOnAnimationEnd()); 276f24f21695f5609d06402cf61e3500d408b99bdcbWinson postAnimationTrigger.increment(); 277f24f21695f5609d06402cf61e3500d408b99bdcbWinson mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation); 27859924fe0d9136cf349759bea1e06b661603f95feWinson if (i == taskViewCount - 1) { 27959924fe0d9136cf349759bea1e06b661603f95feWinson tv.onStartFrontTaskEnterAnimation(mStackView.mScreenPinningEnabled); 28059924fe0d9136cf349759bea1e06b661603f95feWinson } 281c69249fd6f30398780342baed8752ef0eeff7d22Winson } else if (launchState.launchedViaDockGesture) { 282c5887ea7a0b82cc5909743ce14cbda1dcf1dfc82Jorim Jaggi // Animate the tasks up - add some delay to match the divider animation 283899327f5cbbfb0eae5562b262ccea860c98f6bc4Jorim Jaggi AnimationProps taskAnimation = new AnimationProps() 2843f32e7eba7aec02edbf542cc11eee13264a5abf2Winson .setDuration(AnimationProps.BOUNDS, dockGestureAnimDuration + 2853f32e7eba7aec02edbf542cc11eee13264a5abf2Winson (taskIndexFromBack * DOUBLE_FRAME_OFFSET_MS)) 286899327f5cbbfb0eae5562b262ccea860c98f6bc4Jorim Jaggi .setInterpolator(AnimationProps.BOUNDS, 287899327f5cbbfb0eae5562b262ccea860c98f6bc4Jorim Jaggi ENTER_WHILE_DOCKING_INTERPOLATOR) 288c5887ea7a0b82cc5909743ce14cbda1dcf1dfc82Jorim Jaggi .setStartDelay(AnimationProps.BOUNDS, 48) 289899327f5cbbfb0eae5562b262ccea860c98f6bc4Jorim Jaggi .setListener(postAnimationTrigger.decrementOnAnimationEnd()); 290899327f5cbbfb0eae5562b262ccea860c98f6bc4Jorim Jaggi postAnimationTrigger.increment(); 291899327f5cbbfb0eae5562b262ccea860c98f6bc4Jorim Jaggi mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation); 292f24f21695f5609d06402cf61e3500d408b99bdcbWinson } 293f24f21695f5609d06402cf61e3500d408b99bdcbWinson } 294f24f21695f5609d06402cf61e3500d408b99bdcbWinson } 295f24f21695f5609d06402cf61e3500d408b99bdcbWinson 296f24f21695f5609d06402cf61e3500d408b99bdcbWinson /** 297f24f21695f5609d06402cf61e3500d408b99bdcbWinson * Starts an in-app animation to hide all the task views so that we can transition back home. 298f24f21695f5609d06402cf61e3500d408b99bdcbWinson */ 299f24f21695f5609d06402cf61e3500d408b99bdcbWinson public void startExitToHomeAnimation(boolean animated, 300f24f21695f5609d06402cf61e3500d408b99bdcbWinson ReferenceCountedTrigger postAnimationTrigger) { 301f24f21695f5609d06402cf61e3500d408b99bdcbWinson TaskStackLayoutAlgorithm stackLayout = mStackView.getStackAlgorithm(); 302f24f21695f5609d06402cf61e3500d408b99bdcbWinson TaskStack stack = mStackView.getStack(); 303f24f21695f5609d06402cf61e3500d408b99bdcbWinson 304f24f21695f5609d06402cf61e3500d408b99bdcbWinson // Break early if there are no tasks 3054b057c6787624b75613769a857ccdf51114bb7f2Winson if (stack.getTaskCount() == 0) { 306f24f21695f5609d06402cf61e3500d408b99bdcbWinson return; 307f24f21695f5609d06402cf61e3500d408b99bdcbWinson } 308f24f21695f5609d06402cf61e3500d408b99bdcbWinson 30940a227337712a881cca4d7dd04323380287b9e40Winson int offscreenYOffset = stackLayout.mStackRect.height(); 310f24f21695f5609d06402cf61e3500d408b99bdcbWinson 311f24f21695f5609d06402cf61e3500d408b99bdcbWinson // Create the animations for each of the tasks 312f24f21695f5609d06402cf61e3500d408b99bdcbWinson List<TaskView> taskViews = mStackView.getTaskViews(); 313f24f21695f5609d06402cf61e3500d408b99bdcbWinson int taskViewCount = taskViews.size(); 314f24f21695f5609d06402cf61e3500d408b99bdcbWinson for (int i = 0; i < taskViewCount; i++) { 31550448630a49a9602eb53561d1c022890d07449d0Winson int taskIndexFromFront = taskViewCount - i - 1; 316f24f21695f5609d06402cf61e3500d408b99bdcbWinson TaskView tv = taskViews.get(i); 31761560f065a334343d9c552796e1c702f4dfb664bWinson Task task = tv.getTask(); 31861560f065a334343d9c552796e1c702f4dfb664bWinson 31961560f065a334343d9c552796e1c702f4dfb664bWinson if (mStackView.isIgnoredTask(task)) { 32061560f065a334343d9c552796e1c702f4dfb664bWinson continue; 32161560f065a334343d9c552796e1c702f4dfb664bWinson } 32250448630a49a9602eb53561d1c022890d07449d0Winson 32350448630a49a9602eb53561d1c022890d07449d0Winson // Animate the tasks down 32450448630a49a9602eb53561d1c022890d07449d0Winson AnimationProps taskAnimation; 32550448630a49a9602eb53561d1c022890d07449d0Winson if (animated) { 3263f32e7eba7aec02edbf542cc11eee13264a5abf2Winson int delay = Math.min(ENTER_EXIT_NUM_ANIMATING_TASKS , taskIndexFromFront) * 32745c8048f4f8996f085c78621efaf710c907ce213Manu Cornet mEnterAndExitFromHomeTranslationOffset; 32850448630a49a9602eb53561d1c022890d07449d0Winson taskAnimation = new AnimationProps() 3293f32e7eba7aec02edbf542cc11eee13264a5abf2Winson .setStartDelay(AnimationProps.BOUNDS, delay) 3303f32e7eba7aec02edbf542cc11eee13264a5abf2Winson .setDuration(AnimationProps.BOUNDS, EXIT_TO_HOME_TRANSLATION_DURATION) 33150448630a49a9602eb53561d1c022890d07449d0Winson .setInterpolator(AnimationProps.BOUNDS, 33250448630a49a9602eb53561d1c022890d07449d0Winson EXIT_TO_HOME_TRANSLATION_INTERPOLATOR) 33350448630a49a9602eb53561d1c022890d07449d0Winson .setListener(postAnimationTrigger.decrementOnAnimationEnd()); 33450448630a49a9602eb53561d1c022890d07449d0Winson postAnimationTrigger.increment(); 33550448630a49a9602eb53561d1c022890d07449d0Winson } else { 33650448630a49a9602eb53561d1c022890d07449d0Winson taskAnimation = AnimationProps.IMMEDIATE; 33750448630a49a9602eb53561d1c022890d07449d0Winson } 338f24f21695f5609d06402cf61e3500d408b99bdcbWinson 3393b6ba1ab144c53752841869627a1b9f6d357c404Winson mTmpTransform.fillIn(tv); 34040a227337712a881cca4d7dd04323380287b9e40Winson mTmpTransform.rect.offset(0, offscreenYOffset); 341f24f21695f5609d06402cf61e3500d408b99bdcbWinson mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation); 342f24f21695f5609d06402cf61e3500d408b99bdcbWinson } 343f24f21695f5609d06402cf61e3500d408b99bdcbWinson } 344f24f21695f5609d06402cf61e3500d408b99bdcbWinson 345f24f21695f5609d06402cf61e3500d408b99bdcbWinson /** 346f24f21695f5609d06402cf61e3500d408b99bdcbWinson * Starts the animation for the launching task view, hiding any tasks that might occlude the 347f24f21695f5609d06402cf61e3500d408b99bdcbWinson * window transition for the launching task. 348f24f21695f5609d06402cf61e3500d408b99bdcbWinson */ 349f24f21695f5609d06402cf61e3500d408b99bdcbWinson public void startLaunchTaskAnimation(TaskView launchingTaskView, boolean screenPinningRequested, 350f24f21695f5609d06402cf61e3500d408b99bdcbWinson final ReferenceCountedTrigger postAnimationTrigger) { 351f24f21695f5609d06402cf61e3500d408b99bdcbWinson Resources res = mStackView.getResources(); 352f24f21695f5609d06402cf61e3500d408b99bdcbWinson 353f24f21695f5609d06402cf61e3500d408b99bdcbWinson int taskViewExitToAppDuration = res.getInteger( 354f24f21695f5609d06402cf61e3500d408b99bdcbWinson R.integer.recents_task_exit_to_app_duration); 355f24f21695f5609d06402cf61e3500d408b99bdcbWinson int taskViewAffiliateGroupEnterOffset = res.getDimensionPixelSize( 35659924fe0d9136cf349759bea1e06b661603f95feWinson R.dimen.recents_task_stack_animation_affiliate_enter_offset); 357f24f21695f5609d06402cf61e3500d408b99bdcbWinson 358f24f21695f5609d06402cf61e3500d408b99bdcbWinson Task launchingTask = launchingTaskView.getTask(); 359f24f21695f5609d06402cf61e3500d408b99bdcbWinson List<TaskView> taskViews = mStackView.getTaskViews(); 360f24f21695f5609d06402cf61e3500d408b99bdcbWinson int taskViewCount = taskViews.size(); 361f24f21695f5609d06402cf61e3500d408b99bdcbWinson for (int i = 0; i < taskViewCount; i++) { 362f24f21695f5609d06402cf61e3500d408b99bdcbWinson TaskView tv = taskViews.get(i); 363f24f21695f5609d06402cf61e3500d408b99bdcbWinson Task task = tv.getTask(); 3648a3ef375ee299e4a84936c87f66098fa9fb84258Winson boolean currentTaskOccludesLaunchTarget = launchingTask != null && 3658a3ef375ee299e4a84936c87f66098fa9fb84258Winson launchingTask.group != null && 3668a3ef375ee299e4a84936c87f66098fa9fb84258Winson launchingTask.group.isTaskAboveTask(task, launchingTask); 367f24f21695f5609d06402cf61e3500d408b99bdcbWinson 368f24f21695f5609d06402cf61e3500d408b99bdcbWinson if (tv == launchingTaskView) { 369f24f21695f5609d06402cf61e3500d408b99bdcbWinson tv.setClipViewInStack(false); 370a1ededd056d51532ab18354f17f8065ec1134535Winson postAnimationTrigger.addLastDecrementRunnable(new Runnable() { 371a1ededd056d51532ab18354f17f8065ec1134535Winson @Override 372a1ededd056d51532ab18354f17f8065ec1134535Winson public void run() { 373a1ededd056d51532ab18354f17f8065ec1134535Winson tv.setClipViewInStack(true); 374a1ededd056d51532ab18354f17f8065ec1134535Winson } 375a1ededd056d51532ab18354f17f8065ec1134535Winson }); 376f24f21695f5609d06402cf61e3500d408b99bdcbWinson tv.onStartLaunchTargetLaunchAnimation(taskViewExitToAppDuration, 377f24f21695f5609d06402cf61e3500d408b99bdcbWinson screenPinningRequested, postAnimationTrigger); 378f24f21695f5609d06402cf61e3500d408b99bdcbWinson } else if (currentTaskOccludesLaunchTarget) { 379f24f21695f5609d06402cf61e3500d408b99bdcbWinson // Animate this task out of view 380be8e696a1f40a61c52a74022f4f084fdc0600f90Winson AnimationProps taskAnimation = new AnimationProps( 381c0d7058b14c24cd07912f5629c26b39b7b4673d5Winson taskViewExitToAppDuration, Interpolators.ALPHA_OUT, 382f24f21695f5609d06402cf61e3500d408b99bdcbWinson postAnimationTrigger.decrementOnAnimationEnd()); 383f24f21695f5609d06402cf61e3500d408b99bdcbWinson postAnimationTrigger.increment(); 384f24f21695f5609d06402cf61e3500d408b99bdcbWinson 3853b6ba1ab144c53752841869627a1b9f6d357c404Winson mTmpTransform.fillIn(tv); 386f24f21695f5609d06402cf61e3500d408b99bdcbWinson mTmpTransform.alpha = 0f; 387f24f21695f5609d06402cf61e3500d408b99bdcbWinson mTmpTransform.rect.offset(0, taskViewAffiliateGroupEnterOffset); 388f24f21695f5609d06402cf61e3500d408b99bdcbWinson mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation); 389f24f21695f5609d06402cf61e3500d408b99bdcbWinson } 390f24f21695f5609d06402cf61e3500d408b99bdcbWinson } 391f24f21695f5609d06402cf61e3500d408b99bdcbWinson } 392f24f21695f5609d06402cf61e3500d408b99bdcbWinson 393f24f21695f5609d06402cf61e3500d408b99bdcbWinson /** 394f24f21695f5609d06402cf61e3500d408b99bdcbWinson * Starts the delete animation for the specified {@link TaskView}. 395f24f21695f5609d06402cf61e3500d408b99bdcbWinson */ 3965df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet public void startDeleteTaskAnimation(final TaskView deleteTaskView, boolean gridLayout, 397f24f21695f5609d06402cf61e3500d408b99bdcbWinson final ReferenceCountedTrigger postAnimationTrigger) { 3985df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet if (gridLayout) { 3995df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet startTaskGridDeleteTaskAnimation(deleteTaskView, postAnimationTrigger); 4005df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet } else { 4015df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet startTaskStackDeleteTaskAnimation(deleteTaskView, postAnimationTrigger); 4025df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet } 403f24f21695f5609d06402cf61e3500d408b99bdcbWinson } 404f24f21695f5609d06402cf61e3500d408b99bdcbWinson 405f24f21695f5609d06402cf61e3500d408b99bdcbWinson /** 4063b6ba1ab144c53752841869627a1b9f6d357c404Winson * Starts the delete animation for all the {@link TaskView}s. 4073b6ba1ab144c53752841869627a1b9f6d357c404Winson */ 4085df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet public void startDeleteAllTasksAnimation(final List<TaskView> taskViews, boolean gridLayout, 4095df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet final ReferenceCountedTrigger postAnimationTrigger) { 4105df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet if (gridLayout) { 4115df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet for (int i = 0; i < taskViews.size(); i++) { 4125df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet startTaskGridDeleteTaskAnimation(taskViews.get(i), postAnimationTrigger); 4135df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet } 4145df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet } else { 4155df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet startTaskStackDeleteAllTasksAnimation(taskViews, postAnimationTrigger); 4163b6ba1ab144c53752841869627a1b9f6d357c404Winson } 4173b6ba1ab144c53752841869627a1b9f6d357c404Winson } 4183b6ba1ab144c53752841869627a1b9f6d357c404Winson 4193b6ba1ab144c53752841869627a1b9f6d357c404Winson /** 42005e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson * Starts the animation to focus the next {@link TaskView} when paging through recents. 42105e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson * 42205e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson * @return whether or not this will trigger a scroll in the stack 42305e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson */ 42405e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson public boolean startScrollToFocusedTaskAnimation(Task newFocusedTask, 42505e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson boolean requestViewFocus) { 42605e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson TaskStackLayoutAlgorithm stackLayout = mStackView.getStackAlgorithm(); 42705e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson TaskStackViewScroller stackScroller = mStackView.getScroller(); 42805e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson TaskStack stack = mStackView.getStack(); 42905e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson 4303f3d744d5c51d3ecc06af22ac7d69f4437671915Winson final float curScroll = stackScroller.getStackScroll(); 431aeb298c4db913b376fb6053ec30c132a93e04635Winson final float newScroll = stackScroller.getBoundedStackScroll( 432aeb298c4db913b376fb6053ec30c132a93e04635Winson stackLayout.getStackScrollForTask(newFocusedTask)); 4333f3d744d5c51d3ecc06af22ac7d69f4437671915Winson boolean willScrollToFront = newScroll > curScroll; 4343f3d744d5c51d3ecc06af22ac7d69f4437671915Winson boolean willScroll = Float.compare(newScroll, curScroll) != 0; 43505e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson 43605e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson // Get the current set of task transforms 4373f3d744d5c51d3ecc06af22ac7d69f4437671915Winson int taskViewCount = mStackView.getTaskViews().size(); 43805e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson ArrayList<Task> stackTasks = stack.getStackTasks(); 43905e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson mStackView.getCurrentTaskTransforms(stackTasks, mTmpCurrentTaskTransforms); 44005e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson 44105e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson // Pick up the newly visible views after the scroll 44205e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson mStackView.bindVisibleTaskViews(newScroll); 44305e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson 44405e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson // Update the internal state 44505e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson stackLayout.setFocusState(TaskStackLayoutAlgorithm.STATE_FOCUSED); 44605e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson stackScroller.setStackScroll(newScroll, null /* animation */); 44705e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson mStackView.cancelDeferredTaskViewLayoutAnimation(); 44805e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson 44905e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson // Get the final set of task transforms 4501499150478b2836a7d2549129ccaed005b24bc06Winson mStackView.getLayoutTaskTransforms(newScroll, stackLayout.getFocusState(), stackTasks, 451d2a030613154e2007d9816e090c39e9726e7adbaWinson true /* ignoreTaskOverrides */, mTmpFinalTaskTransforms); 45205e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson 45305e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson // Focus the task view 45405e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson TaskView newFocusedTaskView = mStackView.getChildViewForTask(newFocusedTask); 4553f3d744d5c51d3ecc06af22ac7d69f4437671915Winson if (newFocusedTaskView == null) { 4563f3d744d5c51d3ecc06af22ac7d69f4437671915Winson // Log the error if we have no task view, and skip the animation 4573f3d744d5c51d3ecc06af22ac7d69f4437671915Winson Log.e("TaskStackAnimationHelper", "b/27389156 null-task-view prebind:" + taskViewCount + 4583f3d744d5c51d3ecc06af22ac7d69f4437671915Winson " postbind:" + mStackView.getTaskViews().size() + " prescroll:" + curScroll + 4593f3d744d5c51d3ecc06af22ac7d69f4437671915Winson " postscroll: " + newScroll); 4603f3d744d5c51d3ecc06af22ac7d69f4437671915Winson return false; 4613f3d744d5c51d3ecc06af22ac7d69f4437671915Winson } 46205e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson newFocusedTaskView.setFocusedState(true, requestViewFocus); 46305e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson 46405e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson // Setup the end listener to return all the hidden views to the view pool after the 46505e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson // focus animation 46691b225d41f0522c6c106fe2df106ecd5c1f87df9Winson ReferenceCountedTrigger postAnimTrigger = new ReferenceCountedTrigger(); 46791b225d41f0522c6c106fe2df106ecd5c1f87df9Winson postAnimTrigger.addLastDecrementRunnable(new Runnable() { 46805e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson @Override 46991b225d41f0522c6c106fe2df106ecd5c1f87df9Winson public void run() { 47005e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson mStackView.bindVisibleTaskViews(newScroll); 47105e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson } 47291b225d41f0522c6c106fe2df106ecd5c1f87df9Winson }); 47305e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson 47405e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson List<TaskView> taskViews = mStackView.getTaskViews(); 4753f3d744d5c51d3ecc06af22ac7d69f4437671915Winson taskViewCount = taskViews.size(); 47605e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson int newFocusTaskViewIndex = taskViews.indexOf(newFocusedTaskView); 47705e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson for (int i = 0; i < taskViewCount; i++) { 47805e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson TaskView tv = taskViews.get(i); 47905e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson Task task = tv.getTask(); 48005e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson 48105e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson if (mStackView.isIgnoredTask(task)) { 48205e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson continue; 48305e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson } 48405e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson 48505e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson int taskIndex = stackTasks.indexOf(task); 48605e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson TaskViewTransform fromTransform = mTmpCurrentTaskTransforms.get(taskIndex); 48705e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson TaskViewTransform toTransform = mTmpFinalTaskTransforms.get(taskIndex); 48805e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson 48905e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson // Update the task to the initial state (for the newly picked up tasks) 49005e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson mStackView.updateTaskViewToTransform(tv, fromTransform, AnimationProps.IMMEDIATE); 49105e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson 49205e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson int duration; 49305e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson Interpolator interpolator; 49405e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson if (willScrollToFront) { 495d2a030613154e2007d9816e090c39e9726e7adbaWinson duration = calculateStaggeredAnimDuration(i); 49605e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson interpolator = FOCUS_BEHIND_NEXT_TASK_INTERPOLATOR; 49705e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson } else { 49805e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson if (i < newFocusTaskViewIndex) { 49905e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson duration = 150 + ((newFocusTaskViewIndex - i - 1) * 50); 50005e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson interpolator = FOCUS_BEHIND_NEXT_TASK_INTERPOLATOR; 50105e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson } else if (i > newFocusTaskViewIndex) { 50205e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson duration = Math.max(100, 150 - ((i - newFocusTaskViewIndex - 1) * 50)); 50305e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson interpolator = FOCUS_IN_FRONT_NEXT_TASK_INTERPOLATOR; 50405e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson } else { 50505e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson duration = 200; 50605e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson interpolator = FOCUS_NEXT_TASK_INTERPOLATOR; 50705e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson } 50805e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson } 50905e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson 51005e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson AnimationProps anim = new AnimationProps() 51105e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson .setDuration(AnimationProps.BOUNDS, duration) 51205e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson .setInterpolator(AnimationProps.BOUNDS, interpolator) 51391b225d41f0522c6c106fe2df106ecd5c1f87df9Winson .setListener(postAnimTrigger.decrementOnAnimationEnd()); 51491b225d41f0522c6c106fe2df106ecd5c1f87df9Winson postAnimTrigger.increment(); 51505e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson mStackView.updateTaskViewToTransform(tv, toTransform, anim); 51605e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson } 51705e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson return willScroll; 51805e46ca8f3d24cf333e745c8cebb420b2996e9eaWinson } 519d2a030613154e2007d9816e090c39e9726e7adbaWinson 520d2a030613154e2007d9816e090c39e9726e7adbaWinson /** 521d2a030613154e2007d9816e090c39e9726e7adbaWinson * Starts the animation to go to the initial stack layout with a task focused. In addition, the 522d2a030613154e2007d9816e090c39e9726e7adbaWinson * previous task will be animated in after the scroll completes. 523d2a030613154e2007d9816e090c39e9726e7adbaWinson */ 524d2a030613154e2007d9816e090c39e9726e7adbaWinson public void startNewStackScrollAnimation(TaskStack newStack, 525d2a030613154e2007d9816e090c39e9726e7adbaWinson ReferenceCountedTrigger animationTrigger) { 526d2a030613154e2007d9816e090c39e9726e7adbaWinson TaskStackLayoutAlgorithm stackLayout = mStackView.getStackAlgorithm(); 527d2a030613154e2007d9816e090c39e9726e7adbaWinson TaskStackViewScroller stackScroller = mStackView.getScroller(); 528d2a030613154e2007d9816e090c39e9726e7adbaWinson 529d2a030613154e2007d9816e090c39e9726e7adbaWinson // Get the current set of task transforms 530d2a030613154e2007d9816e090c39e9726e7adbaWinson ArrayList<Task> stackTasks = newStack.getStackTasks(); 531d2a030613154e2007d9816e090c39e9726e7adbaWinson mStackView.getCurrentTaskTransforms(stackTasks, mTmpCurrentTaskTransforms); 532d2a030613154e2007d9816e090c39e9726e7adbaWinson 533d2a030613154e2007d9816e090c39e9726e7adbaWinson // Update the stack 534d2a030613154e2007d9816e090c39e9726e7adbaWinson mStackView.setTasks(newStack, false /* allowNotifyStackChanges */); 535d2a030613154e2007d9816e090c39e9726e7adbaWinson mStackView.updateLayoutAlgorithm(false /* boundScroll */); 536d2a030613154e2007d9816e090c39e9726e7adbaWinson 537d2a030613154e2007d9816e090c39e9726e7adbaWinson // Pick up the newly visible views after the scroll 538d2a030613154e2007d9816e090c39e9726e7adbaWinson final float newScroll = stackLayout.mInitialScrollP; 539d2a030613154e2007d9816e090c39e9726e7adbaWinson mStackView.bindVisibleTaskViews(newScroll); 540d2a030613154e2007d9816e090c39e9726e7adbaWinson 541d2a030613154e2007d9816e090c39e9726e7adbaWinson // Update the internal state 542d2a030613154e2007d9816e090c39e9726e7adbaWinson stackLayout.setFocusState(TaskStackLayoutAlgorithm.STATE_UNFOCUSED); 543d2a030613154e2007d9816e090c39e9726e7adbaWinson stackLayout.setTaskOverridesForInitialState(newStack, true /* ignoreScrollToFront */); 544d2a030613154e2007d9816e090c39e9726e7adbaWinson stackScroller.setStackScroll(newScroll); 545d2a030613154e2007d9816e090c39e9726e7adbaWinson mStackView.cancelDeferredTaskViewLayoutAnimation(); 546d2a030613154e2007d9816e090c39e9726e7adbaWinson 547d2a030613154e2007d9816e090c39e9726e7adbaWinson // Get the final set of task transforms 548d2a030613154e2007d9816e090c39e9726e7adbaWinson mStackView.getLayoutTaskTransforms(newScroll, stackLayout.getFocusState(), stackTasks, 549d2a030613154e2007d9816e090c39e9726e7adbaWinson false /* ignoreTaskOverrides */, mTmpFinalTaskTransforms); 550d2a030613154e2007d9816e090c39e9726e7adbaWinson 551d2a030613154e2007d9816e090c39e9726e7adbaWinson // Hide the front most task view until the scroll is complete 552d2a030613154e2007d9816e090c39e9726e7adbaWinson Task frontMostTask = newStack.getStackFrontMostTask(false /* includeFreeform */); 553d2a030613154e2007d9816e090c39e9726e7adbaWinson final TaskView frontMostTaskView = mStackView.getChildViewForTask(frontMostTask); 554d2a030613154e2007d9816e090c39e9726e7adbaWinson final TaskViewTransform frontMostTransform = mTmpFinalTaskTransforms.get( 555d2a030613154e2007d9816e090c39e9726e7adbaWinson stackTasks.indexOf(frontMostTask)); 556d2a030613154e2007d9816e090c39e9726e7adbaWinson if (frontMostTaskView != null) { 557d2a030613154e2007d9816e090c39e9726e7adbaWinson mStackView.updateTaskViewToTransform(frontMostTaskView, 558d2a030613154e2007d9816e090c39e9726e7adbaWinson stackLayout.getFrontOfStackTransform(), AnimationProps.IMMEDIATE); 559d2a030613154e2007d9816e090c39e9726e7adbaWinson } 560d2a030613154e2007d9816e090c39e9726e7adbaWinson 561d2a030613154e2007d9816e090c39e9726e7adbaWinson // Setup the end listener to return all the hidden views to the view pool after the 562d2a030613154e2007d9816e090c39e9726e7adbaWinson // focus animation 563d2a030613154e2007d9816e090c39e9726e7adbaWinson animationTrigger.addLastDecrementRunnable(new Runnable() { 564d2a030613154e2007d9816e090c39e9726e7adbaWinson @Override 565d2a030613154e2007d9816e090c39e9726e7adbaWinson public void run() { 566d2a030613154e2007d9816e090c39e9726e7adbaWinson mStackView.bindVisibleTaskViews(newScroll); 567d2a030613154e2007d9816e090c39e9726e7adbaWinson 568d2a030613154e2007d9816e090c39e9726e7adbaWinson // Now, animate in the front-most task 569d2a030613154e2007d9816e090c39e9726e7adbaWinson if (frontMostTaskView != null) { 570d2a030613154e2007d9816e090c39e9726e7adbaWinson mStackView.updateTaskViewToTransform(frontMostTaskView, frontMostTransform, 5713f32e7eba7aec02edbf542cc11eee13264a5abf2Winson new AnimationProps(75, 250, FOCUS_BEHIND_NEXT_TASK_INTERPOLATOR)); 572d2a030613154e2007d9816e090c39e9726e7adbaWinson } 573d2a030613154e2007d9816e090c39e9726e7adbaWinson } 574d2a030613154e2007d9816e090c39e9726e7adbaWinson }); 575d2a030613154e2007d9816e090c39e9726e7adbaWinson 576d2a030613154e2007d9816e090c39e9726e7adbaWinson List<TaskView> taskViews = mStackView.getTaskViews(); 577d2a030613154e2007d9816e090c39e9726e7adbaWinson int taskViewCount = taskViews.size(); 578d2a030613154e2007d9816e090c39e9726e7adbaWinson for (int i = 0; i < taskViewCount; i++) { 579d2a030613154e2007d9816e090c39e9726e7adbaWinson TaskView tv = taskViews.get(i); 580d2a030613154e2007d9816e090c39e9726e7adbaWinson Task task = tv.getTask(); 581d2a030613154e2007d9816e090c39e9726e7adbaWinson 582d2a030613154e2007d9816e090c39e9726e7adbaWinson if (mStackView.isIgnoredTask(task)) { 583d2a030613154e2007d9816e090c39e9726e7adbaWinson continue; 584d2a030613154e2007d9816e090c39e9726e7adbaWinson } 585d2a030613154e2007d9816e090c39e9726e7adbaWinson if (task == frontMostTask && frontMostTaskView != null) { 586d2a030613154e2007d9816e090c39e9726e7adbaWinson continue; 587d2a030613154e2007d9816e090c39e9726e7adbaWinson } 588d2a030613154e2007d9816e090c39e9726e7adbaWinson 589d2a030613154e2007d9816e090c39e9726e7adbaWinson int taskIndex = stackTasks.indexOf(task); 590d2a030613154e2007d9816e090c39e9726e7adbaWinson TaskViewTransform fromTransform = mTmpCurrentTaskTransforms.get(taskIndex); 591d2a030613154e2007d9816e090c39e9726e7adbaWinson TaskViewTransform toTransform = mTmpFinalTaskTransforms.get(taskIndex); 592d2a030613154e2007d9816e090c39e9726e7adbaWinson 593d2a030613154e2007d9816e090c39e9726e7adbaWinson // Update the task to the initial state (for the newly picked up tasks) 594d2a030613154e2007d9816e090c39e9726e7adbaWinson mStackView.updateTaskViewToTransform(tv, fromTransform, AnimationProps.IMMEDIATE); 595d2a030613154e2007d9816e090c39e9726e7adbaWinson 596d2a030613154e2007d9816e090c39e9726e7adbaWinson int duration = calculateStaggeredAnimDuration(i); 597d2a030613154e2007d9816e090c39e9726e7adbaWinson Interpolator interpolator = FOCUS_BEHIND_NEXT_TASK_INTERPOLATOR; 598d2a030613154e2007d9816e090c39e9726e7adbaWinson 599d2a030613154e2007d9816e090c39e9726e7adbaWinson AnimationProps anim = new AnimationProps() 600d2a030613154e2007d9816e090c39e9726e7adbaWinson .setDuration(AnimationProps.BOUNDS, duration) 601d2a030613154e2007d9816e090c39e9726e7adbaWinson .setInterpolator(AnimationProps.BOUNDS, interpolator) 602d2a030613154e2007d9816e090c39e9726e7adbaWinson .setListener(animationTrigger.decrementOnAnimationEnd()); 603d2a030613154e2007d9816e090c39e9726e7adbaWinson animationTrigger.increment(); 604d2a030613154e2007d9816e090c39e9726e7adbaWinson mStackView.updateTaskViewToTransform(tv, toTransform, anim); 605d2a030613154e2007d9816e090c39e9726e7adbaWinson } 606d2a030613154e2007d9816e090c39e9726e7adbaWinson } 607d2a030613154e2007d9816e090c39e9726e7adbaWinson 608d2a030613154e2007d9816e090c39e9726e7adbaWinson /** 609d2a030613154e2007d9816e090c39e9726e7adbaWinson * Caclulates a staggered duration for {@link #startScrollToFocusedTaskAnimation} and 610d2a030613154e2007d9816e090c39e9726e7adbaWinson * {@link #startNewStackScrollAnimation}. 611d2a030613154e2007d9816e090c39e9726e7adbaWinson */ 612d2a030613154e2007d9816e090c39e9726e7adbaWinson private int calculateStaggeredAnimDuration(int i) { 613d2a030613154e2007d9816e090c39e9726e7adbaWinson return Math.max(100, 100 + ((i - 1) * 50)); 614d2a030613154e2007d9816e090c39e9726e7adbaWinson } 6155df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet 6165df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet private void startTaskGridDeleteTaskAnimation(final TaskView deleteTaskView, 6175df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet final ReferenceCountedTrigger postAnimationTrigger) { 6185df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet postAnimationTrigger.increment(); 6195df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet postAnimationTrigger.addLastDecrementRunnable(() -> { 6205df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet mStackView.getTouchHandler().onChildDismissed(deleteTaskView); 6215df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet }); 6228ea36af22b96189a3f6482d4e5703db34bd48399Manu Cornet deleteTaskView.animate().setDuration(300).scaleX(0.9f).scaleY(0.9f).alpha(0).setListener( 6235df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet new AnimatorListenerAdapter() { 6245df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet @Override 6255df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet public void onAnimationEnd(Animator animation) { 6265df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet postAnimationTrigger.decrement(); 6275df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet }}).start(); 6285df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet } 6295df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet 6305df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet private void startTaskStackDeleteTaskAnimation(final TaskView deleteTaskView, 6315df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet final ReferenceCountedTrigger postAnimationTrigger) { 6325df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet TaskStackViewTouchHandler touchHandler = mStackView.getTouchHandler(); 6335df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet touchHandler.onBeginManualDrag(deleteTaskView); 6345df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet 6355df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet postAnimationTrigger.increment(); 6365df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet postAnimationTrigger.addLastDecrementRunnable(() -> { 6375df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet touchHandler.onChildDismissed(deleteTaskView); 6385df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet }); 6395df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet 6405df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet final float dismissSize = touchHandler.getScaledDismissSize(); 6415df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f); 6425df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet animator.setDuration(400); 6435df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet animator.addUpdateListener((animation) -> { 6445df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet float progress = (Float) animation.getAnimatedValue(); 6455df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet deleteTaskView.setTranslationX(progress * dismissSize); 6465df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet touchHandler.updateSwipeProgress(deleteTaskView, true, progress); 6475df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet }); 6485df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet animator.addListener(new AnimatorListenerAdapter() { 6495df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet @Override 6505df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet public void onAnimationEnd(Animator animation) { 6515df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet postAnimationTrigger.decrement(); 6525df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet } 6535df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet }); 6545df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet animator.start(); 6555df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet } 6565df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet 6575df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet private void startTaskStackDeleteAllTasksAnimation(final List<TaskView> taskViews, 6585df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet final ReferenceCountedTrigger postAnimationTrigger) { 6595df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet TaskStackLayoutAlgorithm stackLayout = mStackView.getStackAlgorithm(); 6605df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet 6615df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet int offscreenXOffset = mStackView.getMeasuredWidth() - stackLayout.getTaskRect().left; 6625df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet 6635df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet int taskViewCount = taskViews.size(); 6645df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet for (int i = taskViewCount - 1; i >= 0; i--) { 6655df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet TaskView tv = taskViews.get(i); 6665df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet int taskIndexFromFront = taskViewCount - i - 1; 6675df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet int startDelay = taskIndexFromFront * DOUBLE_FRAME_OFFSET_MS; 6685df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet 6695df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet // Disabling clipping with the stack while the view is animating away 6705df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet tv.setClipViewInStack(false); 6715df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet 6725df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet // Compose the new animation and transform and star the animation 6735df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet AnimationProps taskAnimation = new AnimationProps(startDelay, 6745df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet DISMISS_ALL_TASKS_DURATION, DISMISS_ALL_TRANSLATION_INTERPOLATOR, 6755df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet new AnimatorListenerAdapter() { 6765df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet @Override 6775df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet public void onAnimationEnd(Animator animation) { 6785df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet postAnimationTrigger.decrement(); 6795df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet 6805df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet // Re-enable clipping with the stack (we will reuse this view) 6815df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet tv.setClipViewInStack(true); 6825df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet } 6835df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet }); 6845df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet postAnimationTrigger.increment(); 6855df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet 6865df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet mTmpTransform.fillIn(tv); 6875df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet mTmpTransform.rect.offset(offscreenXOffset, 0); 6885df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation); 6895df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet } 6905df7667edbabdf8bf43bc08ef7df2859fd620314Manu Cornet } 691f24f21695f5609d06402cf61e3500d408b99bdcbWinson} 692