/** Synchronizes the views with the model */ boolean synchronizeStackViewsWithModel() { if (mStackViewsDirty) { // Get all the task transforms ArrayList<T> data = mCallback.getData(); float stackScroll = mStackScroller.getStackScroll(); int[] visibleRange = mTmpVisibleRange; boolean isValidVisibleRange = updateStackTransforms(mCurrentTaskTransforms, data, stackScroll, visibleRange, false); // Return all the invisible children to the pool mTmpTaskViewMap.clear(); int childCount = getChildCount(); for (int i = childCount - 1; i >= 0; i--) { DeckChildView<T> tv = (DeckChildView) getChildAt(i); T key = tv.getAttachedKey(); int taskIndex = data.indexOf(key); if (visibleRange[1] <= taskIndex && taskIndex <= visibleRange[0]) { mTmpTaskViewMap.put(key, tv); } else { mViewPool.returnViewToPool(tv); } } for (int i = visibleRange[0]; isValidVisibleRange && i >= visibleRange[1]; i--) { T key = data.get(i); DeckChildViewTransform transform = mCurrentTaskTransforms.get(i); DeckChildView tv = mTmpTaskViewMap.get(key); if (tv == null) { // TODO Check tv = mViewPool.pickUpViewFromPool(key, key); if (mStackViewsAnimationDuration > 0) { // For items in the list, put them in start animating them from the // approriate ends of the list where they are expected to appear if (Float.compare(transform.p, 0f) <= 0) { mLayoutAlgorithm.getStackTransform(0f, 0f, mTmpTransform, null); } else { mLayoutAlgorithm.getStackTransform(1f, 0f, mTmpTransform, null); } tv.updateViewPropertiesToTaskTransform(mTmpTransform, 0); } } // Animate the task into place tv.updateViewPropertiesToTaskTransform( mCurrentTaskTransforms.get(i), mStackViewsAnimationDuration, mRequestUpdateClippingListener); } // Reset the request-synchronize params mStackViewsAnimationDuration = 0; mStackViewsDirty = false; mStackViewsClipDirty = true; return true; } return false; }
/** Gets the stack transforms of a list of tasks, and returns the visible range of tasks. */ private boolean updateStackTransforms( ArrayList<DeckChildViewTransform> taskTransforms, ArrayList<T> data, float stackScroll, int[] visibleRangeOut, boolean boundTranslationsToRect) { int taskTransformCount = taskTransforms.size(); int taskCount = data.size(); int frontMostVisibleIndex = -1; int backMostVisibleIndex = -1; // We can reuse the task transforms where possible to reduce object allocation if (taskTransformCount < taskCount) { // If there are less transforms than tasks, then add as many transforms as necessary for (int i = taskTransformCount; i < taskCount; i++) { taskTransforms.add(new DeckChildViewTransform()); } } else if (taskTransformCount > taskCount) { // If there are more transforms than tasks, then just subset the transform list taskTransforms.subList(0, taskCount); } // Update the stack transforms DeckChildViewTransform prevTransform = null; for (int i = taskCount - 1; i >= 0; i--) { DeckChildViewTransform transform = mLayoutAlgorithm.getStackTransform( data.get(i), stackScroll, taskTransforms.get(i), prevTransform); if (transform.visible) { if (frontMostVisibleIndex < 0) { frontMostVisibleIndex = i; } backMostVisibleIndex = i; } else { if (backMostVisibleIndex != -1) { // We've reached the end of the visible range, so going down the rest of the // stack, we can just reset the transforms accordingly while (i >= 0) { taskTransforms.get(i).reset(); i--; } break; } } if (boundTranslationsToRect) { transform.translationY = Math.min(transform.translationY, mLayoutAlgorithm.mViewRect.bottom); } prevTransform = transform; } if (visibleRangeOut != null) { visibleRangeOut[0] = frontMostVisibleIndex; visibleRangeOut[1] = backMostVisibleIndex; } return frontMostVisibleIndex != -1 && backMostVisibleIndex != -1; }
/** Requests this task stacks to start it's enter-recents animation */ public void startEnterRecentsAnimation(ViewAnimation.TaskViewEnterContext ctx) { // If we are still waiting to layout, then just defer until then if (mAwaitingFirstLayout) { mStartEnterAnimationRequestedAfterLayout = true; mStartEnterAnimationContext = ctx; return; } if (mCallback.getData().size() > 0) { int childCount = getChildCount(); // Animate all the task views into view for (int i = childCount - 1; i >= 0; i--) { DeckChildView<T> tv = (DeckChildView) getChildAt(i); T key = tv.getAttachedKey(); ctx.currentTaskTransform = new DeckChildViewTransform(); ctx.currentStackViewIndex = i; ctx.currentStackViewCount = childCount; ctx.currentTaskRect = mLayoutAlgorithm.mTaskRect; // TODO: this needs to go ctx.currentTaskOccludesLaunchTarget = false; ctx.updateListener = mRequestUpdateClippingListener; mLayoutAlgorithm.getStackTransform( key, mStackScroller.getStackScroll(), ctx.currentTaskTransform, null); tv.startEnterRecentsAnimation(ctx); } // Add a runnable to the post animation ref counter to clear all the views ctx.postAnimationTrigger.addLastDecrementRunnable( new Runnable() { @Override public void run() { mStartEnterAnimationCompleted = true; // Poke the dozer to restart the trigger after the animation completes mUIDozeTrigger.poke(); } }); } }