/**
   * Animate opening a tab in the foreground.
   *
   * @param id The id of the new tab to animate.
   * @param sourceId The id of the tab that spawned this new tab.
   * @param newIsIncognito true if the new tab is an incognito tab.
   * @param originX The X coordinate of the last touch down event that spawned this tab.
   * @param originY The Y coordinate of the last touch down event that spawned this tab.
   */
  private void tabCreatedInForeground(
      int id, int sourceId, boolean newIsIncognito, float originX, float originY) {
    LayoutTab newLayoutTab = createLayoutTab(id, newIsIncognito, NO_CLOSE_BUTTON, NO_TITLE);
    if (mLayoutTabs == null || mLayoutTabs.length == 0) {
      mLayoutTabs = new LayoutTab[] {newLayoutTab};
    } else {
      mLayoutTabs = new LayoutTab[] {mLayoutTabs[0], newLayoutTab};
    }
    updateCacheVisibleIds(new LinkedList<Integer>(Arrays.asList(id, sourceId)));

    newLayoutTab.setBorderAlpha(0.0f);
    newLayoutTab.setStaticToViewBlend(1.f);

    forceAnimationToFinish();

    Interpolator interpolator = BakedBezierInterpolator.TRANSFORM_CURVE;
    addToAnimation(
        newLayoutTab,
        LayoutTab.Property.SCALE,
        0.f,
        1.f,
        FOREGROUND_ANIMATION_DURATION,
        0,
        false,
        interpolator);
    addToAnimation(
        newLayoutTab,
        LayoutTab.Property.ALPHA,
        0.f,
        1.f,
        FOREGROUND_ANIMATION_DURATION,
        0,
        false,
        interpolator);
    addToAnimation(
        newLayoutTab,
        LayoutTab.Property.X,
        originX,
        0.f,
        FOREGROUND_ANIMATION_DURATION,
        0,
        false,
        interpolator);
    addToAnimation(
        newLayoutTab,
        LayoutTab.Property.Y,
        originY,
        0.f,
        FOREGROUND_ANIMATION_DURATION,
        0,
        false,
        interpolator);

    mTabModelSelector.selectModel(newIsIncognito);
    startHiding(id, false);
  }
  private void ensureSourceTabCreated(int sourceTabId) {
    if (mLayoutTabs != null && mLayoutTabs.length == 1 && mLayoutTabs[0].getId() == sourceTabId) {
      return;
    }
    // Just draw the source tab on the screen.
    TabModel sourceModel = mTabModelSelector.getModelForTabId(sourceTabId);
    if (sourceModel == null) return;
    LayoutTab sourceLayoutTab =
        createLayoutTab(sourceTabId, sourceModel.isIncognito(), NO_CLOSE_BUTTON, NO_TITLE);
    sourceLayoutTab.setBorderAlpha(0.0f);

    mLayoutTabs = new LayoutTab[] {sourceLayoutTab};
    updateCacheVisibleIds(new LinkedList<Integer>(Arrays.asList(sourceTabId)));
  }
  /**
   * Creates the Base Page's LayoutTab to be presented in the screen.
   *
   * @param layoutTab The {@link Layout} instance.
   */
  private void createBaseLayoutTab(LayoutTab layoutTab) {
    if (mTabModelSelector == null) return;

    int baseTabId = mTabModelSelector.getCurrentTabId();
    if (baseTabId == Tab.INVALID_TAB_ID) return;

    mBaseTab =
        createLayoutTab(
            baseTabId, mTabModelSelector.isIncognitoSelected(), NO_CLOSE_BUTTON, NO_TITLE);

    assert mBaseTab != null;
    mBaseTab.setScale(1.f);
    mBaseTab.setBorderScale(1.f);
    mBaseTab.setBorderAlpha(0.f);

    mLayoutTabs = new LayoutTab[] {mBaseTab};
  }
  /** Set up for the tab closing animation */
  @Override
  public void onTabClosing(long time, int id) {
    reset();

    // Make sure any currently running animations can't influence tab if we are reusing it.
    forceAnimationToFinish();

    // Create the {@link LayoutTab} for the tab before it is destroyed.
    TabModel model = mTabModelSelector.getModelForTabId(id);
    if (model != null) {
      mClosedTab = createLayoutTab(id, model.isIncognito(), NO_CLOSE_BUTTON, NO_TITLE);
      mClosedTab.setBorderAlpha(0.0f);
      mLayoutTabs = new LayoutTab[] {mClosedTab};
      updateCacheVisibleIds(new LinkedList<Integer>(Arrays.asList(id)));
    } else {
      mLayoutTabs = null;
      mClosedTab = null;
    }
    // Only close the id at the end when we are done querying the model.
    super.onTabClosing(time, id);
  }
  /**
   * Animate opening a tab in the background.
   *
   * @param id The id of the new tab to animate.
   * @param sourceId The id of the tab that spawned this new tab.
   * @param newIsIncognito true if the new tab is an incognito tab.
   * @param originX The X screen coordinate in dp of the last touch down event that spawned this
   *     tab.
   * @param originY The Y screen coordinate in dp of the last touch down event that spawned this
   *     tab.
   */
  private void tabCreatedInBackground(
      int id, int sourceId, boolean newIsIncognito, float originX, float originY) {
    LayoutTab newLayoutTab = createLayoutTab(id, newIsIncognito, NO_CLOSE_BUTTON, NEED_TITLE);
    // mLayoutTabs should already have the source tab from tabCreating().
    assert mLayoutTabs.length == 1;
    LayoutTab sourceLayoutTab = mLayoutTabs[0];
    mLayoutTabs = new LayoutTab[] {sourceLayoutTab, newLayoutTab};
    updateCacheVisibleIds(new LinkedList<Integer>(Arrays.asList(id, sourceId)));

    forceAnimationToFinish();

    newLayoutTab.setBorderAlpha(0.0f);
    final float scale = StackAnimation.SCALE_AMOUNT;
    final float margin = Math.min(getWidth(), getHeight()) * (1.0f - scale) / 2.0f;

    // Step 1: zoom out the source tab and bring in the new tab
    addToAnimation(
        sourceLayoutTab,
        LayoutTab.Property.SCALE,
        1.0f,
        scale,
        BACKGROUND_STEP1_DURATION,
        0,
        false,
        BakedBezierInterpolator.TRANSFORM_CURVE);
    addToAnimation(
        sourceLayoutTab,
        LayoutTab.Property.X,
        0.0f,
        margin,
        BACKGROUND_STEP1_DURATION,
        0,
        false,
        BakedBezierInterpolator.TRANSFORM_CURVE);
    addToAnimation(
        sourceLayoutTab,
        LayoutTab.Property.Y,
        0.0f,
        margin,
        BACKGROUND_STEP1_DURATION,
        0,
        false,
        BakedBezierInterpolator.TRANSFORM_CURVE);
    addToAnimation(
        sourceLayoutTab,
        LayoutTab.Property.BORDER_SCALE,
        1.0f / scale,
        1.0f,
        BACKGROUND_STEP1_DURATION,
        0,
        false,
        BakedBezierInterpolator.TRANSFORM_CURVE);
    addToAnimation(
        sourceLayoutTab,
        LayoutTab.Property.BORDER_ALPHA,
        0.0f,
        1.0f,
        BACKGROUND_STEP1_DURATION,
        0,
        false,
        BakedBezierInterpolator.TRANSFORM_CURVE);

    float pauseX = margin;
    float pauseY = margin;
    if (getOrientation() == Orientation.PORTRAIT) {
      pauseY = BACKGROUND_COVER_PCTG * getHeight();
    } else {
      pauseX = BACKGROUND_COVER_PCTG * getWidth();
    }

    addToAnimation(
        newLayoutTab,
        LayoutTab.Property.ALPHA,
        0.0f,
        1.0f,
        BACKGROUND_STEP1_DURATION / 2,
        0,
        false,
        BakedBezierInterpolator.FADE_IN_CURVE);
    addToAnimation(
        newLayoutTab,
        LayoutTab.Property.SCALE,
        0.f,
        scale,
        BACKGROUND_STEP1_DURATION,
        0,
        false,
        BakedBezierInterpolator.FADE_IN_CURVE);
    addToAnimation(
        newLayoutTab,
        LayoutTab.Property.X,
        originX,
        pauseX,
        BACKGROUND_STEP1_DURATION,
        0,
        false,
        BakedBezierInterpolator.FADE_IN_CURVE);
    addToAnimation(
        newLayoutTab,
        LayoutTab.Property.Y,
        originY,
        pauseY,
        BACKGROUND_STEP1_DURATION,
        0,
        false,
        BakedBezierInterpolator.FADE_IN_CURVE);

    // step 2: pause and admire the nice tabs

    // step 3: zoom in the source tab and slide down the new tab
    addToAnimation(
        sourceLayoutTab,
        LayoutTab.Property.SCALE,
        scale,
        1.0f,
        BACKGROUND_STEP3_DURATION,
        BACKGROUND_STEP3_START,
        true,
        BakedBezierInterpolator.TRANSFORM_CURVE);
    addToAnimation(
        sourceLayoutTab,
        LayoutTab.Property.X,
        margin,
        0.0f,
        BACKGROUND_STEP3_DURATION,
        BACKGROUND_STEP3_START,
        true,
        BakedBezierInterpolator.TRANSFORM_CURVE);
    addToAnimation(
        sourceLayoutTab,
        LayoutTab.Property.Y,
        margin,
        0.0f,
        BACKGROUND_STEP3_DURATION,
        BACKGROUND_STEP3_START,
        true,
        BakedBezierInterpolator.TRANSFORM_CURVE);
    addToAnimation(
        sourceLayoutTab,
        LayoutTab.Property.BORDER_SCALE,
        1.0f,
        1.0f / scale,
        BACKGROUND_STEP3_DURATION,
        BACKGROUND_STEP3_START,
        true,
        BakedBezierInterpolator.TRANSFORM_CURVE);
    addToAnimation(
        sourceLayoutTab,
        LayoutTab.Property.BORDER_ALPHA,
        1.0f,
        0.0f,
        BACKGROUND_STEP3_DURATION,
        BACKGROUND_STEP3_START,
        true,
        BakedBezierInterpolator.TRANSFORM_CURVE);

    addToAnimation(
        newLayoutTab,
        LayoutTab.Property.ALPHA,
        1.f,
        0.f,
        BACKGROUND_STEP3_DURATION,
        BACKGROUND_STEP3_START,
        true,
        BakedBezierInterpolator.FADE_OUT_CURVE);
    if (getOrientation() == Orientation.PORTRAIT) {
      addToAnimation(
          newLayoutTab,
          LayoutTab.Property.Y,
          pauseY,
          getHeight(),
          BACKGROUND_STEP3_DURATION,
          BACKGROUND_STEP3_START,
          true,
          BakedBezierInterpolator.FADE_OUT_CURVE);
    } else {
      addToAnimation(
          newLayoutTab,
          LayoutTab.Property.X,
          pauseX,
          getWidth(),
          BACKGROUND_STEP3_DURATION,
          BACKGROUND_STEP3_START,
          true,
          BakedBezierInterpolator.FADE_OUT_CURVE);
    }

    mTabModelSelector.selectModel(newIsIncognito);
    startHiding(sourceId, false);
  }