Beispiel #1
0
  /** Focuses the task at the specified index in the stack */
  public void scrollToChild(int childIndex) {
    if (getCurrentChildIndex() == childIndex) return;

    if (0 <= childIndex && childIndex < mCallback.getData().size()) {
      // Scroll the view into position (just center it in the curve)
      float newScroll =
          mLayoutAlgorithm.getStackScrollForTask(mCallback.getData().get(childIndex)) - 0.5f;
      newScroll = mStackScroller.getBoundedStackScroll(newScroll);
      mStackScroller.setStackScroll(newScroll);
      // Alternate (animated) way
      // mStackScroller.animateScroll(mStackScroller.getStackScroll(), newScroll, null);
    }
  }
Beispiel #2
0
 /** Requests this task stacks to start it's exit-recents animation. */
 public void startExitToHomeAnimation(ViewAnimation.TaskViewExitContext ctx) {
   // Stop any scrolling
   mStackScroller.stopScroller();
   mStackScroller.stopBoundScrollAnimation();
   // Animate all the task views out of view
   ctx.offscreenTranslationY =
       mLayoutAlgorithm.mViewRect.bottom
           - (mLayoutAlgorithm.mTaskRect.top - mLayoutAlgorithm.mViewRect.top);
   int childCount = getChildCount();
   for (int i = 0; i < childCount; i++) {
     DeckChildView tv = (DeckChildView) getChildAt(i);
     tv.startExitToHomeAnimation(ctx);
   }
 }
Beispiel #3
0
  public void initialize(Callback<T> callback) {
    mCallback = callback;
    requestLayout();

    mViewPool = new ViewPool<DeckChildView<T>, T>(getContext(), this);
    mInflater = LayoutInflater.from(getContext());
    mLayoutAlgorithm = new DeckViewLayoutAlgorithm<T>(mConfig);
    mStackScroller = new DeckViewScroller(getContext(), mConfig, mLayoutAlgorithm);
    mStackScroller.setCallbacks(this);
    mTouchHandler = new DeckViewTouchHandler(getContext(), this, mConfig, mStackScroller);

    mUIDozeTrigger =
        new DozeTrigger(
            mConfig.taskBarDismissDozeDelaySeconds,
            new Runnable() {
              @Override
              public void run() {
                // Show the task bar dismiss buttons
                int childCount = getChildCount();
                for (int i = 0; i < childCount; i++) {
                  DeckChildView tv = (DeckChildView) getChildAt(i);
                  tv.startNoUserInteractionAnimation();
                }
              }
            });
  }
Beispiel #4
0
  /** 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;
  }
Beispiel #5
0
  /** Resets this TaskStackView for reuse. */
  void reset() {
    // Reset the focused task
    resetFocusedTask();

    // Return all the views to the pool
    int childCount = getChildCount();
    for (int i = childCount - 1; i >= 0; i--) {
      DeckChildView<T> tv = (DeckChildView) getChildAt(i);
      mViewPool.returnViewToPool(tv);
    }

    // Mark each task view for relayout
    if (mViewPool != null) {
      Iterator<DeckChildView<T>> iter = mViewPool.poolViewIterator();
      if (iter != null) {
        while (iter.hasNext()) {
          DeckChildView tv = iter.next();
          tv.reset();
        }
      }
    }

    // Reset the stack state
    mStackViewsDirty = true;
    mStackViewsClipDirty = true;
    mAwaitingFirstLayout = true;
    mPrevAccessibilityFocusedIndex = -1;
    if (mUIDozeTrigger != null) {
      mUIDozeTrigger.stopDozing();
      mUIDozeTrigger.resetTrigger();
    }
    mStackScroller.reset();
  }
Beispiel #6
0
 @Override
 public void computeScroll() {
   mStackScroller.computeScroll();
   // Synchronize the views
   synchronizeStackViewsWithModel();
   clipTaskViews();
   // Notify accessibility
   sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SCROLLED);
 }
Beispiel #7
0
  /** Updates the min and max virtual scroll bounds */
  void updateMinMaxScroll(
      boolean boundScrollToNewMinMax, boolean launchedWithAltTab, boolean launchedFromHome) {
    // Compute the min and max scroll values
    mLayoutAlgorithm.computeMinMaxScroll(mCallback.getData(), launchedWithAltTab, launchedFromHome);

    // Debug logging
    if (true) {
      mStackScroller.boundScroll();
    }
  }
Beispiel #8
0
  /** Focuses the task at the specified index in the stack */
  void focusTask(int childIndex, boolean scrollToNewPosition, final boolean animateFocusedState) {
    // Return early if the task is already focused
    if (childIndex == mFocusedTaskIndex) return;

    ArrayList<T> data = mCallback.getData();

    if (0 <= childIndex && childIndex < data.size()) {
      mFocusedTaskIndex = childIndex;

      // Focus the view if possible, otherwise, focus the view after we scroll into position
      T key = data.get(childIndex);
      DeckChildView tv = getChildViewForTask(key);
      Runnable postScrollRunnable = null;
      if (tv != null) {
        tv.setFocusedTask(animateFocusedState);
      } else {
        postScrollRunnable =
            new Runnable() {
              @Override
              public void run() {

                DeckChildView tv = getChildViewForTask(mCallback.getData().get(mFocusedTaskIndex));
                if (tv != null) {
                  tv.setFocusedTask(animateFocusedState);
                }
              }
            };
      }

      // Scroll the view into position (just center it in the curve)
      if (scrollToNewPosition) {
        float newScroll = mLayoutAlgorithm.getStackScrollForTask(key) - 0.5f;
        newScroll = mStackScroller.getBoundedStackScroll(newScroll);
        mStackScroller.animateScroll(
            mStackScroller.getStackScroll(), newScroll, postScrollRunnable);
      } else {
        if (postScrollRunnable != null) {
          postScrollRunnable.run();
        }
      }
    }
  }
Beispiel #9
0
  public void notifyDataSetChanged() {
    // Get the stack scroll of the task to anchor to (since we are removing something, the front
    // most task will be our anchor task)
    T anchorTask = null;
    float prevAnchorTaskScroll = 0;
    boolean pullStackForward = mCallback.getData().size() > 0;
    if (pullStackForward) {
      anchorTask = mCallback.getData().get(mCallback.getData().size() - 1);
      prevAnchorTaskScroll = mLayoutAlgorithm.getStackScrollForTask(anchorTask);
    }

    // Update the min/max scroll and animate other task views into their new positions
    updateMinMaxScroll(true, mConfig.launchedWithAltTab, mConfig.launchedFromHome);

    // Offset the stack by as much as the anchor task would otherwise move back
    if (pullStackForward) {
      float anchorTaskScroll = mLayoutAlgorithm.getStackScrollForTask(anchorTask);
      mStackScroller.setStackScroll(
          mStackScroller.getStackScroll() + (anchorTaskScroll - prevAnchorTaskScroll));
      mStackScroller.boundScroll();
    }

    // Animate all the tasks into place
    requestSynchronizeStackViewsWithModel(200);

    T newFrontMostTask =
        mCallback.getData().size() > 0
            ? mCallback.getData().get(mCallback.getData().size() - 1)
            : null;
    // Update the new front most task
    if (newFrontMostTask != null) {
      DeckChildView<T> frontTv = getChildViewForTask(newFrontMostTask);
      if (frontTv != null) {
        frontTv.onTaskBound(newFrontMostTask);
      }
    }

    // If there are no remaining tasks
    if (mCallback.getData().size() == 0) {
      mCallback.onNoViewsToDeck();
    }
  }
Beispiel #10
0
  /**
   * This is called with the full window width and height to allow stack view children to perform
   * the full screen transition down.
   */
  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

    int width = MeasureSpec.getSize(widthMeasureSpec);
    int height = MeasureSpec.getSize(heightMeasureSpec);
    // 可见区域
    Rect _taskStackBounds = new Rect();
    mConfig.getTaskStackBounds(
        width, height, mConfig.systemInsets.top, mConfig.systemInsets.right, _taskStackBounds);

    setStackInsetRect(_taskStackBounds);

    // Compute our stack/task rects
    //        Rect taskStackBounds = new Rect(mTaskStackBounds);
    //        taskStackBounds.bottom -= mConfig.systemInsets.bottom;

    computeRects(
        width, height, _taskStackBounds, mConfig.launchedWithAltTab, mConfig.launchedFromHome);

    // If this is the first layout, then scroll to the front of the stack and synchronize the
    // stack views immediately to load all the views
    if (mAwaitingFirstLayout) {
      mStackScroller.setStackScrollToInitialState();
      //            requestSynchronizeStackViewsWithModel();
      //            synchronizeStackViewsWithModel();
    }

    // Measure each of the TaskViews
    int childCount = getChildCount();
    for (int i = 0; i < childCount; i++) {
      DeckChildView tv = (DeckChildView) getChildAt(i);
      //            if (tv.getBackground() != null) {
      //                tv.getBackground().getPadding(mTmpRect);
      //            } else {
      //                mTmpRect.setEmpty();
      //            }
      tv.measure(
          MeasureSpec.makeMeasureSpec(
              mLayoutAlgorithm.mTaskRect.width() + mTmpRect.left + mTmpRect.right,
              MeasureSpec.EXACTLY),
          MeasureSpec.makeMeasureSpec(
              mLayoutAlgorithm.mTaskRect.height() + mTmpRect.top + mTmpRect.bottom,
              MeasureSpec.EXACTLY));

      //            tv.measure(
      //                    widthMeasureSpec,
      //                    heightMeasureSpec);
    }

    setMeasuredDimension(width, height);
  }
Beispiel #11
0
 @Override
 public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
   super.onInitializeAccessibilityEvent(event);
   int childCount = getChildCount();
   if (childCount > 0) {
     DeckChildView<T> backMostTask = (DeckChildView) getChildAt(0);
     DeckChildView<T> frontMostTask = (DeckChildView) getChildAt(childCount - 1);
     event.setFromIndex(mCallback.getData().indexOf(backMostTask.getAttachedKey()));
     event.setToIndex(mCallback.getData().indexOf(frontMostTask.getAttachedKey()));
   }
   event.setItemCount(mCallback.getData().size());
   event.setScrollY(mStackScroller.mScroller.getCurrY());
   event.setMaxScrollY(mStackScroller.progressToScrollRange(mLayoutAlgorithm.mMaxScrollP));
 }
Beispiel #12
0
  /** 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();
            }
          });
    }
  }