| Index: chrome/android/java_staging/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayout.java
|
| diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayout.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayout.java
|
| deleted file mode 100644
|
| index 3913e0c59d1a839ae232347310651e4a33ad69f1..0000000000000000000000000000000000000000
|
| --- a/chrome/android/java_staging/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayout.java
|
| +++ /dev/null
|
| @@ -1,1191 +0,0 @@
|
| -// Copyright 2015 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -package org.chromium.chrome.browser.compositor.layouts.phone;
|
| -
|
| -import android.content.Context;
|
| -import android.graphics.Rect;
|
| -import android.graphics.RectF;
|
| -import android.os.SystemClock;
|
| -import android.view.ViewConfiguration;
|
| -import android.view.ViewGroup;
|
| -import android.view.ViewGroup.LayoutParams;
|
| -import android.widget.FrameLayout;
|
| -
|
| -import org.chromium.base.VisibleForTesting;
|
| -import org.chromium.chrome.browser.Tab;
|
| -import org.chromium.chrome.browser.compositor.LayerTitleCache;
|
| -import org.chromium.chrome.browser.compositor.layouts.ChromeAnimation.Animatable;
|
| -import org.chromium.chrome.browser.compositor.layouts.Layout;
|
| -import org.chromium.chrome.browser.compositor.layouts.LayoutRenderHost;
|
| -import org.chromium.chrome.browser.compositor.layouts.LayoutUpdateHost;
|
| -import org.chromium.chrome.browser.compositor.layouts.components.LayoutTab;
|
| -import org.chromium.chrome.browser.compositor.layouts.content.TabContentManager;
|
| -import org.chromium.chrome.browser.compositor.layouts.eventfilter.EdgeSwipeEventFilter.ScrollDirection;
|
| -import org.chromium.chrome.browser.compositor.layouts.eventfilter.EventFilter;
|
| -import org.chromium.chrome.browser.compositor.layouts.phone.stack.Stack;
|
| -import org.chromium.chrome.browser.compositor.layouts.phone.stack.StackTab;
|
| -import org.chromium.chrome.browser.compositor.scene_layer.SceneLayer;
|
| -import org.chromium.chrome.browser.compositor.scene_layer.TabListSceneLayer;
|
| -import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager;
|
| -import org.chromium.chrome.browser.partnercustomizations.HomepageManager;
|
| -import org.chromium.chrome.browser.tabmodel.TabModel;
|
| -import org.chromium.chrome.browser.tabmodel.TabModelSelector;
|
| -import org.chromium.chrome.browser.tabmodel.TabModelUtils;
|
| -import org.chromium.chrome.browser.util.MathUtils;
|
| -import org.chromium.ui.base.LocalizationUtils;
|
| -import org.chromium.ui.resources.ResourceManager;
|
| -
|
| -import java.io.Serializable;
|
| -import java.util.ArrayList;
|
| -import java.util.Arrays;
|
| -import java.util.Comparator;
|
| -
|
| -/**
|
| - * Defines the layout for 2 stacks and manages the events to switch between
|
| - * them.
|
| - */
|
| -
|
| -public class StackLayout extends Layout implements Animatable<StackLayout.Property> {
|
| - public enum Property {
|
| - INNER_MARGIN_PERCENT,
|
| - STACK_SNAP,
|
| - STACK_OFFSET_Y_PERCENT,
|
| - }
|
| -
|
| - private enum SwipeMode { NONE, SEND_TO_STACK, SWITCH_STACK }
|
| -
|
| - private static final String TAG = "StackLayout";
|
| - // Width of the partially shown stack when there are multiple stacks.
|
| - private static final int MIN_INNER_MARGIN_PERCENT_DP = 55;
|
| - private static final float INNER_MARGIN_PERCENT_PERCENT = 0.17f;
|
| -
|
| - // Speed of the automatic fling in dp/ms
|
| - private static final float FLING_SPEED_DP = 1.5f; // dp / ms
|
| - private static final int FLING_MIN_DURATION = 100; // ms
|
| -
|
| - private static final float THRESHOLD_TO_SWITCH_STACK = 0.4f;
|
| - private static final float THRESHOLD_TIME_TO_SWITCH_STACK_INPUT_MODE = 200;
|
| -
|
| - /**
|
| - * The delta time applied on the velocity from the fling. This is to compute the kick to help
|
| - * switching the stack.
|
| - */
|
| - private static final float SWITCH_STACK_FLING_DT = 1.0f / 30.0f;
|
| -
|
| - /** The array of potentially visible stacks. The code works for only 2 stacks. */
|
| - private final Stack[] mStacks;
|
| -
|
| - /** Rectangles that defines the area where each stack need to be laid out. */
|
| - private final RectF[] mStackRects;
|
| -
|
| - private int mStackAnimationCount;
|
| -
|
| - private float mFlingSpeed = 0; // pixel/ms
|
| -
|
| - /** Whether the current fling animation is the result of switching stacks. */
|
| - private boolean mFlingFromModelChange;
|
| -
|
| - private boolean mClicked;
|
| -
|
| - // If not overscroll, then mRenderedScrollIndex == mScrollIndex;
|
| - // Otherwise, mRenderedScrollIndex is updated with the actual index passed in
|
| - // from the event handler; and mRenderedScrollIndex is the value we get
|
| - // after map mScrollIndex through a decelerate function.
|
| - // Here we use float as index so we can smoothly animate the transition between stack.
|
| - private float mRenderedScrollOffset = 0.0f;
|
| - private float mScrollIndexOffset = 0.0f;
|
| -
|
| - private final int mMinMaxInnerMargin;
|
| - private float mInnerMarginPercent;
|
| - private float mStackOffsetYPercent;
|
| -
|
| - private SwipeMode mInputMode = SwipeMode.NONE;
|
| - private float mLastOnDownX;
|
| - private float mLastOnDownY;
|
| - private long mLastOnDownTimeStamp;
|
| - private final float mMinShortPressThresholdSqr; // Computed from Android ViewConfiguration
|
| - private final float mMinDirectionThreshold; // Computed from Android ViewConfiguration
|
| -
|
| - // Pre-allocated temporary arrays that store id of visible tabs.
|
| - // They can be used to call populatePriorityVisibilityList.
|
| - // We use StackTab[] instead of ArrayList<StackTab> because the sorting function does
|
| - // an allocation to iterate over the elements.
|
| - // Do not use out of the context of {@link #updateTabPriority}.
|
| - private StackTab[] mSortedPriorityArray = null;
|
| -
|
| - private final ArrayList<Integer> mVisibilityArray = new ArrayList<Integer>();
|
| - private final VisibilityComparator mVisibilityComparator = new VisibilityComparator();
|
| - private final OrderComparator mOrderComparator = new OrderComparator();
|
| - private Comparator<StackTab> mSortingComparator = mVisibilityComparator;
|
| -
|
| - private static final int LAYOUTTAB_ASYNCHRONOUS_INITIALIZATION_BATCH_SIZE = 4;
|
| - private boolean mDelayedLayoutTabInitRequired = false;
|
| -
|
| - private Boolean mTemporarySelectedStack;
|
| -
|
| - // Orientation Variables
|
| - private PortraitViewport mCachedPortraitViewport = null;
|
| - private PortraitViewport mCachedLandscapeViewport = null;
|
| -
|
| - private final ViewGroup mViewContainer;
|
| -
|
| - private final TabListSceneLayer mSceneLayer;
|
| -
|
| - /**
|
| - * @param context The current Android's context.
|
| - * @param updateHost The {@link LayoutUpdateHost} view for this layout.
|
| - * @param renderHost The {@link LayoutRenderHost} view for this layout.
|
| - * @param eventFilter The {@link EventFilter} that is needed for this view.
|
| - */
|
| - public StackLayout(Context context, LayoutUpdateHost updateHost, LayoutRenderHost renderHost,
|
| - EventFilter eventFilter) {
|
| - super(context, updateHost, renderHost, eventFilter);
|
| -
|
| - final ViewConfiguration configuration = ViewConfiguration.get(context);
|
| - mMinDirectionThreshold = configuration.getScaledTouchSlop();
|
| - mMinShortPressThresholdSqr =
|
| - configuration.getScaledPagingTouchSlop() * configuration.getScaledPagingTouchSlop();
|
| -
|
| - mMinMaxInnerMargin = (int) (MIN_INNER_MARGIN_PERCENT_DP + 0.5);
|
| - mFlingSpeed = FLING_SPEED_DP;
|
| - mStacks = new Stack[2];
|
| - mStacks[0] = new Stack(context, this);
|
| - mStacks[1] = new Stack(context, this);
|
| - mStackRects = new RectF[2];
|
| - mStackRects[0] = new RectF();
|
| - mStackRects[1] = new RectF();
|
| -
|
| - mViewContainer = new FrameLayout(getContext());
|
| - mSceneLayer = new TabListSceneLayer();
|
| - }
|
| -
|
| - @Override
|
| - public int getSizingFlags() {
|
| - return SizingFlags.ALLOW_TOOLBAR_SHOW | SizingFlags.REQUIRE_FULLSCREEN_SIZE;
|
| - }
|
| -
|
| - @Override
|
| - public void setTabModelSelector(TabModelSelector modelSelector, TabContentManager manager) {
|
| - super.setTabModelSelector(modelSelector, manager);
|
| - mStacks[0].setTabModel(modelSelector.getModel(false));
|
| - mStacks[1].setTabModel(modelSelector.getModel(true));
|
| - resetScrollData();
|
| - }
|
| -
|
| - /**
|
| - * Get the tab stack state for the specified mode.
|
| - *
|
| - * @param incognito Whether the TabStackState to be returned should be the one for incognito.
|
| - * @return The tab stack state for the given mode.
|
| - * @VisibleForTesting
|
| - */
|
| - public Stack getTabStack(boolean incognito) {
|
| - return mStacks[incognito ? 1 : 0];
|
| - }
|
| -
|
| - /**
|
| - * Get the tab stack state.
|
| - * @return The tab stack index for the given tab id.
|
| - */
|
| - private int getTabStackIndex() {
|
| - return getTabStackIndex(Tab.INVALID_TAB_ID);
|
| - }
|
| -
|
| - /**
|
| - * Get the tab stack state for the specified tab id.
|
| - *
|
| - * @param tabId The id of the tab to lookup.
|
| - * @return The tab stack index for the given tab id.
|
| - * @VisibleForTesting
|
| - */
|
| - protected int getTabStackIndex(int tabId) {
|
| - if (tabId == Tab.INVALID_TAB_ID) {
|
| - boolean incognito = mTemporarySelectedStack != null
|
| - ? mTemporarySelectedStack
|
| - : mTabModelSelector.isIncognitoSelected();
|
| - return incognito ? 1 : 0;
|
| - } else {
|
| - return TabModelUtils.getTabById(mTabModelSelector.getModel(true), tabId) != null ? 1
|
| - : 0;
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Get the tab stack state for the specified tab id.
|
| - *
|
| - * @param tabId The id of the tab to lookup.
|
| - * @return The tab stack state for the given tab id.
|
| - * @VisibleForTesting
|
| - */
|
| - protected Stack getTabStack(int tabId) {
|
| - return mStacks[getTabStackIndex(tabId)];
|
| - }
|
| -
|
| - @Override
|
| - public void onTabSelecting(long time, int tabId) {
|
| - mStacks[1].ensureCleaningUpDyingTabs(time);
|
| - mStacks[0].ensureCleaningUpDyingTabs(time);
|
| - if (tabId == Tab.INVALID_TAB_ID) tabId = mTabModelSelector.getCurrentTabId();
|
| - super.onTabSelecting(time, tabId);
|
| - mStacks[getTabStackIndex()].tabSelectingEffect(time, tabId);
|
| - startMarginAnimation(false);
|
| - startYOffsetAnimation(false);
|
| - finishScrollStacks();
|
| - }
|
| -
|
| - @Override
|
| - public void onTabClosing(long time, int id) {
|
| - Stack stack = getTabStack(id);
|
| - if (stack == null) return;
|
| - stack.tabClosingEffect(time, id);
|
| -
|
| - // Just in case we closed the last tab of a stack we need to trigger the overlap animation.
|
| - startMarginAnimation(true);
|
| -
|
| - // Animate the stack to leave incognito mode.
|
| - if (!mStacks[1].isDisplayable()) uiPreemptivelySelectTabModel(false);
|
| - }
|
| -
|
| - @Override
|
| - public void onTabsAllClosing(long time, boolean incognito) {
|
| - super.onTabsAllClosing(time, incognito);
|
| - getTabStack(incognito).tabsAllClosingEffect(time);
|
| - // trigger the overlap animation.
|
| - startMarginAnimation(true);
|
| - // Animate the stack to leave incognito mode.
|
| - if (!mStacks[1].isDisplayable()) uiPreemptivelySelectTabModel(false);
|
| - }
|
| -
|
| - @Override
|
| - public void onTabClosureCancelled(long time, int id, boolean incognito) {
|
| - super.onTabClosureCancelled(time, id, incognito);
|
| - getTabStack(incognito).undoClosure(time, id);
|
| - }
|
| -
|
| - @Override
|
| - public boolean handlesCloseAll() {
|
| - return true;
|
| - }
|
| -
|
| - @Override
|
| - public boolean handlesTabCreating() {
|
| - return true;
|
| - }
|
| -
|
| - @Override
|
| - public boolean handlesTabClosing() {
|
| - return true;
|
| - }
|
| -
|
| - @Override
|
| - public void attachViews(ViewGroup container) {
|
| - // TODO(dtrainor): This is a hack. We're attaching to the parent of the view container
|
| - // which is the content container of the Activity.
|
| - ((ViewGroup) container.getParent())
|
| - .addView(mViewContainer,
|
| - new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
|
| - }
|
| -
|
| - @Override
|
| - public void detachViews() {
|
| - if (mViewContainer.getParent() != null) {
|
| - ((ViewGroup) mViewContainer.getParent()).removeView(mViewContainer);
|
| - }
|
| - mViewContainer.removeAllViews();
|
| - }
|
| -
|
| - /**
|
| - * @return A {@link ViewGroup} that {@link Stack}s can use to interact with the Android view
|
| - * hierarchy.
|
| - */
|
| - public ViewGroup getViewContainer() {
|
| - return mViewContainer;
|
| - }
|
| -
|
| - @Override
|
| - public void onTabCreating(int sourceTabId) {
|
| - // Force any in progress animations to end. This was introduced because
|
| - // we end up with 0 tabs if the animation for all tabs closing is still
|
| - // running when a new tab is created.
|
| - // See http://crbug.com/496557
|
| - onUpdateAnimation(SystemClock.currentThreadTimeMillis(), true);
|
| - }
|
| -
|
| - @Override
|
| - public void onTabCreated(long time, int id, int tabIndex, int sourceId, boolean newIsIncognito,
|
| - boolean background, float originX, float originY) {
|
| - super.onTabCreated(
|
| - time, id, tabIndex, sourceId, newIsIncognito, background, originX, originY);
|
| - startHiding(id, false);
|
| - mStacks[getTabStackIndex(id)].tabCreated(time, id);
|
| - startMarginAnimation(false);
|
| - uiPreemptivelySelectTabModel(newIsIncognito);
|
| - }
|
| -
|
| - @Override
|
| - public void onTabModelSwitched(boolean toIncognitoTabModel) {
|
| - flingStacks(toIncognitoTabModel);
|
| - mFlingFromModelChange = true;
|
| - }
|
| -
|
| - @Override
|
| - public boolean onUpdateAnimation(long time, boolean jumpToEnd) {
|
| - boolean animationsWasDone = super.onUpdateAnimation(time, jumpToEnd);
|
| - boolean finishedView0 = mStacks[0].onUpdateViewAnimation(time, jumpToEnd);
|
| - boolean finishedView1 = mStacks[1].onUpdateViewAnimation(time, jumpToEnd);
|
| - boolean finishedCompositor0 = mStacks[0].onUpdateCompositorAnimations(time, jumpToEnd);
|
| - boolean finishedCompositor1 = mStacks[1].onUpdateCompositorAnimations(time, jumpToEnd);
|
| - if (animationsWasDone && finishedView0 && finishedView1 && finishedCompositor0
|
| - && finishedCompositor1) {
|
| - return true;
|
| - } else {
|
| - if (!animationsWasDone || !finishedCompositor0 || !finishedCompositor1) {
|
| - requestStackUpdate();
|
| - }
|
| -
|
| - return false;
|
| - }
|
| - }
|
| -
|
| - @Override
|
| - protected void onAnimationStarted() {
|
| - if (mStackAnimationCount == 0) super.onAnimationStarted();
|
| - }
|
| -
|
| - @Override
|
| - protected void onAnimationFinished() {
|
| - mFlingFromModelChange = false;
|
| - if (mTemporarySelectedStack != null) {
|
| - mTabModelSelector.selectModel(mTemporarySelectedStack);
|
| - mTemporarySelectedStack = null;
|
| - }
|
| - if (mStackAnimationCount == 0) super.onAnimationFinished();
|
| - }
|
| -
|
| - /**
|
| - * Called when a UI element is attempting to select a tab. This will perform the animation
|
| - * and then actually propagate the action. This starts hiding this layout which, when complete,
|
| - * will actually select the tab.
|
| - * @param time The current time of the app in ms.
|
| - * @param id The id of the tab to select.
|
| - */
|
| - public void uiSelectingTab(long time, int id) {
|
| - onTabSelecting(time, id);
|
| - }
|
| -
|
| - /**
|
| - * Called when a UI element is attempting to close a tab. This will perform the required close
|
| - * animations. When the UI is ready to actually close the tab
|
| - * {@link #uiDoneClosingTab(long, int, boolean, boolean)} should be called to actually propagate
|
| - * the event to the model.
|
| - * @param time The current time of the app in ms.
|
| - * @param id The id of the tab to close.
|
| - */
|
| - public void uiRequestingCloseTab(long time, int id) {
|
| - // Start the tab closing effect if necessary.
|
| - getTabStack(id).tabClosingEffect(time, id);
|
| -
|
| - int incognitoCount = mTabModelSelector.getModel(true).getCount();
|
| - TabModel model = mTabModelSelector.getModelForTabId(id);
|
| - if (model != null && model.isIncognito()) incognitoCount--;
|
| - boolean incognitoVisible = incognitoCount > 0;
|
| -
|
| - // Make sure we show/hide both stacks depending on which tab we're closing.
|
| - startMarginAnimation(true, incognitoVisible);
|
| - if (!incognitoVisible) uiPreemptivelySelectTabModel(false);
|
| - }
|
| -
|
| - /**
|
| - * Called when a UI element is done animating the close tab effect started by
|
| - * {@link #uiRequestingCloseTab(long, int)}. This actually pushes the close event to the model.
|
| - * @param time The current time of the app in ms.
|
| - * @param id The id of the tab to close.
|
| - * @param canUndo Whether or not this close can be undone.
|
| - * @param incognito Whether or not this was for the incognito stack or not.
|
| - */
|
| - public void uiDoneClosingTab(long time, int id, boolean canUndo, boolean incognito) {
|
| - // If homepage is enabled and there is a maximum of 1 tab in both models
|
| - // (this is the last tab), the tab closure cannot be undone.
|
| - canUndo &= !(HomepageManager.isHomepageEnabled(getContext())
|
| - && (mTabModelSelector.getModel(true).getCount()
|
| - + mTabModelSelector.getModel(false).getCount()
|
| - < 2));
|
| -
|
| - // Propagate the tab closure to the model.
|
| - TabModelUtils.closeTabById(mTabModelSelector.getModel(incognito), id, canUndo);
|
| - }
|
| -
|
| - public void uiDoneClosingAllTabs(boolean incognito) {
|
| - // Propagate the tab closure to the model.
|
| - mTabModelSelector.getModel(incognito).closeAllTabs(false, false);
|
| - }
|
| -
|
| - /**
|
| - * Called when a {@link Stack} instance is done animating the stack enter effect.
|
| - */
|
| - public void uiDoneEnteringStack() {
|
| - mSortingComparator = mVisibilityComparator;
|
| - doneShowing();
|
| - }
|
| -
|
| - private void uiPreemptivelySelectTabModel(boolean incognito) {
|
| - onTabModelSwitched(incognito);
|
| - }
|
| -
|
| - /**
|
| - * Starts the animation for the opposite stack to slide in or out when entering
|
| - * or leaving stack view. The animation should be super fast to match more or less
|
| - * the fling animation.
|
| - * @param enter True if the stack view is being entered, false if the stack view
|
| - * is being left.
|
| - */
|
| - private void startMarginAnimation(boolean enter) {
|
| - startMarginAnimation(enter, mStacks[1].isDisplayable());
|
| - }
|
| -
|
| - private void startMarginAnimation(boolean enter, boolean showIncognito) {
|
| - float start = mInnerMarginPercent;
|
| - float end = enter && showIncognito ? 1.0f : 0.0f;
|
| - if (start != end) {
|
| - addToAnimation(this, Property.INNER_MARGIN_PERCENT, start, end, 200, 0);
|
| - }
|
| - }
|
| -
|
| - private void startYOffsetAnimation(boolean enter) {
|
| - float start = mStackOffsetYPercent;
|
| - float end = enter ? 1.f : 0.f;
|
| - if (start != end) {
|
| - addToAnimation(this, Property.STACK_OFFSET_Y_PERCENT, start, end, 300, 0);
|
| - }
|
| - }
|
| -
|
| - @Override
|
| - public void show(long time, boolean animate) {
|
| - super.show(time, animate);
|
| -
|
| - Tab tab = mTabModelSelector.getCurrentTab();
|
| - if (tab != null && tab.isNativePage()) mTabContentManager.cacheTabThumbnail(tab);
|
| -
|
| - // Remove any views in case we're getting another call to show before we hide (quickly
|
| - // toggling the tab switcher button).
|
| - mViewContainer.removeAllViews();
|
| -
|
| - for (int i = mStacks.length - 1; i >= 0; --i) {
|
| - mStacks[i].reset();
|
| - if (mStacks[i].isDisplayable()) {
|
| - mStacks[i].show();
|
| - } else {
|
| - mStacks[i].cleanupTabs();
|
| - }
|
| - }
|
| - // Initialize the animation and the positioning of all the elements
|
| - mSortingComparator = mOrderComparator;
|
| - resetScrollData();
|
| - for (int i = mStacks.length - 1; i >= 0; --i) {
|
| - if (mStacks[i].isDisplayable()) {
|
| - boolean offscreen = (i != getTabStackIndex());
|
| - mStacks[i].stackEntered(time, !offscreen);
|
| - }
|
| - }
|
| - startMarginAnimation(true);
|
| - startYOffsetAnimation(true);
|
| - flingStacks(getTabStackIndex() == 1);
|
| -
|
| - if (!animate) onUpdateAnimation(time, true);
|
| -
|
| - // We will render before we get a call to updateLayout. Need to make sure all of the tabs
|
| - // we need to render are up to date.
|
| - updateLayout(time, 0);
|
| - }
|
| -
|
| - @Override
|
| - public void swipeStarted(long time, ScrollDirection direction, float x, float y) {
|
| - mStacks[getTabStackIndex()].swipeStarted(time, direction, x, y);
|
| - }
|
| -
|
| - @Override
|
| - public void swipeUpdated(long time, float x, float y, float dx, float dy, float tx, float ty) {
|
| - mStacks[getTabStackIndex()].swipeUpdated(time, x, y, dx, dy, tx, ty);
|
| - }
|
| -
|
| - @Override
|
| - public void swipeFinished(long time) {
|
| - mStacks[getTabStackIndex()].swipeFinished(time);
|
| - }
|
| -
|
| - @Override
|
| - public void swipeCancelled(long time) {
|
| - mStacks[getTabStackIndex()].swipeCancelled(time);
|
| - }
|
| -
|
| - @Override
|
| - public void swipeFlingOccurred(
|
| - long time, float x, float y, float tx, float ty, float vx, float vy) {
|
| - mStacks[getTabStackIndex()].swipeFlingOccurred(time, x, y, tx, ty, vx, vy);
|
| - }
|
| -
|
| - private void requestStackUpdate() {
|
| - // TODO(jgreenwald): It isn't always necessary to invalidate both
|
| - // stacks.
|
| - mStacks[0].requestUpdate();
|
| - mStacks[1].requestUpdate();
|
| - }
|
| -
|
| - @Override
|
| - public void notifySizeChanged(float width, float height, int orientation) {
|
| - mCachedLandscapeViewport = null;
|
| - mCachedPortraitViewport = null;
|
| - mStacks[0].notifySizeChanged(width, height, orientation);
|
| - mStacks[1].notifySizeChanged(width, height, orientation);
|
| - resetScrollData();
|
| - requestStackUpdate();
|
| - }
|
| -
|
| - @Override
|
| - public void contextChanged(Context context) {
|
| - super.contextChanged(context);
|
| - StackTab.resetDimensionConstants(context);
|
| - mStacks[0].contextChanged(context);
|
| - mStacks[1].contextChanged(context);
|
| - requestStackUpdate();
|
| - }
|
| -
|
| - @Override
|
| - public void drag(long time, float x, float y, float amountX, float amountY) {
|
| - SwipeMode oldInputMode = mInputMode;
|
| - mInputMode = computeInputMode(time, x, y, amountX, amountY);
|
| -
|
| - if (oldInputMode == SwipeMode.SEND_TO_STACK && mInputMode == SwipeMode.SWITCH_STACK) {
|
| - mStacks[getTabStackIndex()].onUpOrCancel(time);
|
| - } else if (oldInputMode == SwipeMode.SWITCH_STACK
|
| - && mInputMode == SwipeMode.SEND_TO_STACK) {
|
| - onUpOrCancel(time);
|
| - }
|
| -
|
| - if (mInputMode == SwipeMode.SEND_TO_STACK) {
|
| - mStacks[getTabStackIndex()].drag(time, x, y, amountX, amountY);
|
| - } else if (mInputMode == SwipeMode.SWITCH_STACK) {
|
| - scrollStacks(getOrientation() == Orientation.PORTRAIT ? amountX : amountY);
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Computes the input mode for drag and fling based on the first event position.
|
| - * @param time The current time of the app in ms.
|
| - * @param x The x layout position of the mouse (without the displacement).
|
| - * @param y The y layout position of the mouse (without the displacement).
|
| - * @param dx The x displacement happening this frame.
|
| - * @param dy The y displacement happening this frame.
|
| - * @return The input mode to select.
|
| - */
|
| - private SwipeMode computeInputMode(long time, float x, float y, float dx, float dy) {
|
| - if (!mStacks[1].isDisplayable()) return SwipeMode.SEND_TO_STACK;
|
| - int currentIndex = getTabStackIndex();
|
| - if (currentIndex != getViewportParameters().getStackIndexAt(x, y)) {
|
| - return SwipeMode.SWITCH_STACK;
|
| - }
|
| - float relativeX = mLastOnDownX - (x + dx);
|
| - float relativeY = mLastOnDownY - (y + dy);
|
| - float distanceToDownSqr = dx * dx + dy * dy;
|
| - float switchDelta = getOrientation() == Orientation.PORTRAIT ? relativeX : relativeY;
|
| - float otherDelta = getOrientation() == Orientation.PORTRAIT ? relativeY : relativeX;
|
| -
|
| - // Dragging in the opposite direction of the stack switch
|
| - if (distanceToDownSqr > mMinDirectionThreshold * mMinDirectionThreshold
|
| - && Math.abs(otherDelta) > Math.abs(switchDelta)) {
|
| - return SwipeMode.SEND_TO_STACK;
|
| - }
|
| - // Dragging in a direction the stack cannot switch
|
| - if (Math.abs(switchDelta) > mMinDirectionThreshold) {
|
| - if ((currentIndex == 0) ^ (switchDelta > 0)
|
| - ^ (getOrientation() == Orientation.PORTRAIT
|
| - && LocalizationUtils.isLayoutRtl())) {
|
| - return SwipeMode.SEND_TO_STACK;
|
| - }
|
| - }
|
| - if (isDraggingStackInWrongDirection(
|
| - mLastOnDownX, mLastOnDownY, x, y, dx, dy, getOrientation(), currentIndex)) {
|
| - return SwipeMode.SWITCH_STACK;
|
| - }
|
| - // Not moving the finger
|
| - if (time - mLastOnDownTimeStamp > THRESHOLD_TIME_TO_SWITCH_STACK_INPUT_MODE) {
|
| - return SwipeMode.SEND_TO_STACK;
|
| - }
|
| - // Dragging fast
|
| - if (distanceToDownSqr > mMinShortPressThresholdSqr) {
|
| - return SwipeMode.SWITCH_STACK;
|
| - }
|
| - return SwipeMode.NONE;
|
| - }
|
| -
|
| - @Override
|
| - public void fling(long time, float x, float y, float vx, float vy) {
|
| - if (mInputMode == SwipeMode.NONE) {
|
| - mInputMode = computeInputMode(
|
| - time, x, y, vx * SWITCH_STACK_FLING_DT, vy * SWITCH_STACK_FLING_DT);
|
| - }
|
| -
|
| - if (mInputMode == SwipeMode.SEND_TO_STACK) {
|
| - mStacks[getTabStackIndex()].fling(time, x, y, vx, vy);
|
| - } else if (mInputMode == SwipeMode.SWITCH_STACK) {
|
| - final float velocity = getOrientation() == Orientation.PORTRAIT ? vx : vy;
|
| - final float origin = getOrientation() == Orientation.PORTRAIT ? x : y;
|
| - final float max = getOrientation() == Orientation.PORTRAIT ? getWidth() : getHeight();
|
| - final float predicted = origin + velocity * SWITCH_STACK_FLING_DT;
|
| - final float delta = MathUtils.clamp(predicted, 0, max) - origin;
|
| - scrollStacks(delta);
|
| - }
|
| - requestStackUpdate();
|
| - }
|
| -
|
| - class PortraitViewport {
|
| - protected float mWidth, mHeight;
|
| - PortraitViewport() {
|
| - mWidth = StackLayout.this.getWidth();
|
| - mHeight = StackLayout.this.getHeightMinusTopControls();
|
| - }
|
| -
|
| - float getClampedRenderedScrollOffset() {
|
| - if (mStacks[1].isDisplayable() || mFlingFromModelChange) {
|
| - return MathUtils.clamp(mRenderedScrollOffset, 0, -1);
|
| - } else {
|
| - return 0;
|
| - }
|
| - }
|
| -
|
| - float getInnerMargin() {
|
| - float margin = mInnerMarginPercent
|
| - * Math.max(mMinMaxInnerMargin, mWidth * INNER_MARGIN_PERCENT_PERCENT);
|
| - return margin;
|
| - }
|
| -
|
| - int getStackIndexAt(float x, float y) {
|
| - if (LocalizationUtils.isLayoutRtl()) {
|
| - // On RTL portrait mode, stack1 (incognito) is on the left.
|
| - float separation = getStack0Left();
|
| - return x < separation ? 1 : 0;
|
| - } else {
|
| - float separation = getStack0Left() + getWidth();
|
| - return x < separation ? 0 : 1;
|
| - }
|
| - }
|
| -
|
| - float getStack0Left() {
|
| - return LocalizationUtils.isLayoutRtl()
|
| - ? getInnerMargin() - getClampedRenderedScrollOffset() * getFullScrollDistance()
|
| - : getClampedRenderedScrollOffset() * getFullScrollDistance();
|
| - }
|
| -
|
| - float getWidth() {
|
| - return mWidth - getInnerMargin();
|
| - }
|
| -
|
| - float getHeight() {
|
| - return mHeight;
|
| - }
|
| -
|
| - float getStack0Top() {
|
| - return getTopHeightOffset();
|
| - }
|
| -
|
| - float getStack0ToStack1TranslationX() {
|
| - return Math.round(LocalizationUtils.isLayoutRtl() ? -mWidth + getInnerMargin() : mWidth
|
| - - getInnerMargin());
|
| - }
|
| -
|
| - float getStack0ToStack1TranslationY() {
|
| - return 0.0f;
|
| - }
|
| -
|
| - float getTopHeightOffset() {
|
| - return (StackLayout.this.getHeight() - getHeightMinusTopControls())
|
| - * mStackOffsetYPercent;
|
| - }
|
| - }
|
| -
|
| - class LandscapeViewport extends PortraitViewport {
|
| - LandscapeViewport() {
|
| - // This is purposefully inverted.
|
| - mWidth = StackLayout.this.getHeightMinusTopControls();
|
| - mHeight = StackLayout.this.getWidth();
|
| - }
|
| -
|
| - @Override
|
| - float getInnerMargin() {
|
| - float margin = mInnerMarginPercent
|
| - * Math.max(mMinMaxInnerMargin, mWidth * INNER_MARGIN_PERCENT_PERCENT);
|
| - return margin;
|
| - }
|
| -
|
| - @Override
|
| - int getStackIndexAt(float x, float y) {
|
| - float separation = getStack0Top() + getHeight();
|
| - return y < separation ? 0 : 1;
|
| - }
|
| -
|
| - @Override
|
| - float getStack0Left() {
|
| - return 0.f;
|
| - }
|
| -
|
| - @Override
|
| - float getStack0Top() {
|
| - return getClampedRenderedScrollOffset() * getFullScrollDistance()
|
| - + getTopHeightOffset();
|
| - }
|
| -
|
| - @Override
|
| - float getWidth() {
|
| - return super.getHeight();
|
| - }
|
| -
|
| - @Override
|
| - float getHeight() {
|
| - return super.getWidth();
|
| - }
|
| -
|
| - @Override
|
| - float getStack0ToStack1TranslationX() {
|
| - return super.getStack0ToStack1TranslationY();
|
| - }
|
| -
|
| - @Override
|
| - float getStack0ToStack1TranslationY() {
|
| - return Math.round(mWidth - getInnerMargin());
|
| - }
|
| - }
|
| -
|
| - private PortraitViewport getViewportParameters() {
|
| - if (getOrientation() == Orientation.PORTRAIT) {
|
| - if (mCachedPortraitViewport == null) {
|
| - mCachedPortraitViewport = new PortraitViewport();
|
| - }
|
| - return mCachedPortraitViewport;
|
| - } else {
|
| - if (mCachedLandscapeViewport == null) {
|
| - mCachedLandscapeViewport = new LandscapeViewport();
|
| - }
|
| - return mCachedLandscapeViewport;
|
| - }
|
| - }
|
| -
|
| - @Override
|
| - public void click(long time, float x, float y) {
|
| - // Click event happens before the up event. mClicked is set to mute the up event.
|
| - mClicked = true;
|
| - PortraitViewport viewportParams = getViewportParameters();
|
| - int stackIndexAt = viewportParams.getStackIndexAt(x, y);
|
| - if (stackIndexAt == getTabStackIndex()) {
|
| - mStacks[getTabStackIndex()].click(time, x, y);
|
| - } else {
|
| - flingStacks(getTabStackIndex() == 0);
|
| - }
|
| - requestStackUpdate();
|
| - }
|
| -
|
| - /**
|
| - * Check if we are dragging stack in a wrong direction.
|
| - *
|
| - * @param downX The X coordinate on the last down event.
|
| - * @param downY The Y coordinate on the last down event.
|
| - * @param x The current X coordinate.
|
| - * @param y The current Y coordinate.
|
| - * @param dx The amount of change in X coordinate.
|
| - * @param dy The amount of change in Y coordinate.
|
| - * @param orientation The device orientation (portrait / landscape).
|
| - * @param stackIndex The index of stack tab.
|
| - * @return True iff we are dragging stack in a wrong direction.
|
| - */
|
| - @VisibleForTesting
|
| - public static boolean isDraggingStackInWrongDirection(float downX, float downY, float x,
|
| - float y, float dx, float dy, int orientation, int stackIndex) {
|
| - float switchDelta = orientation == Orientation.PORTRAIT ? x - downX : y - downY;
|
| -
|
| - // Should not prevent scrolling even when switchDelta is in a wrong direction.
|
| - if (Math.abs(dx) < Math.abs(dy)) {
|
| - return false;
|
| - }
|
| - return (stackIndex == 0 && switchDelta < 0) || (stackIndex == 1 && switchDelta > 0);
|
| - }
|
| -
|
| - private void scrollStacks(float delta) {
|
| - cancelAnimation(this, Property.STACK_SNAP);
|
| - float fullDistance = getFullScrollDistance();
|
| - mScrollIndexOffset += MathUtils.flipSignIf(delta / fullDistance,
|
| - getOrientation() == Orientation.PORTRAIT && LocalizationUtils.isLayoutRtl());
|
| - if (canScrollLinearly(getTabStackIndex())) {
|
| - mRenderedScrollOffset = mScrollIndexOffset;
|
| - } else {
|
| - mRenderedScrollOffset = (int) MathUtils.clamp(
|
| - mScrollIndexOffset, 0, mStacks[1].isDisplayable() ? -1 : 0);
|
| - }
|
| - requestStackUpdate();
|
| - }
|
| -
|
| - private void flingStacks(boolean toIncognito) {
|
| - // velocityX is measured in pixel per second.
|
| - if (!canScrollLinearly(toIncognito ? 0 : 1)) return;
|
| - setActiveStackState(toIncognito);
|
| - finishScrollStacks();
|
| - requestStackUpdate();
|
| - }
|
| -
|
| - /**
|
| - * Animate to the final position of the stack. Unfortunately, both touch-up
|
| - * and fling can be called and this depends on fling always being called last.
|
| - * If fling is called first, onUpOrCancel can override the fling position
|
| - * with the opposite. For example, if the user does a very small fling from
|
| - * incognito to non-incognito, which leaves the up event in the incognito side.
|
| - */
|
| - private void finishScrollStacks() {
|
| - cancelAnimation(this, Property.STACK_SNAP);
|
| - final int currentModelIndex = getTabStackIndex();
|
| - float delta = Math.abs(currentModelIndex + mRenderedScrollOffset);
|
| - float target = -currentModelIndex;
|
| - if (delta != 0) {
|
| - long duration = FLING_MIN_DURATION
|
| - + (long) Math.abs(delta * getFullScrollDistance() / mFlingSpeed);
|
| - addToAnimation(this, Property.STACK_SNAP, mRenderedScrollOffset, target, duration, 0);
|
| - } else {
|
| - setProperty(Property.STACK_SNAP, target);
|
| - if (mTemporarySelectedStack != null) {
|
| - mTabModelSelector.selectModel(mTemporarySelectedStack);
|
| - mTemporarySelectedStack = null;
|
| - }
|
| - }
|
| - }
|
| -
|
| - @Override
|
| - public void onDown(long time, float x, float y) {
|
| - mLastOnDownX = x;
|
| - mLastOnDownY = y;
|
| - mLastOnDownTimeStamp = time;
|
| - mInputMode = computeInputMode(time, x, y, 0, 0);
|
| - mStacks[getTabStackIndex()].onDown(time);
|
| - }
|
| -
|
| - @Override
|
| - public void onLongPress(long time, float x, float y) {
|
| - mStacks[getTabStackIndex()].onLongPress(time, x, y);
|
| - }
|
| -
|
| - @Override
|
| - public void onUpOrCancel(long time) {
|
| - int currentIndex = getTabStackIndex();
|
| - int nextIndex = 1 - currentIndex;
|
| - if (!mClicked && Math.abs(currentIndex + mRenderedScrollOffset) > THRESHOLD_TO_SWITCH_STACK
|
| - && mStacks[nextIndex].isDisplayable()) {
|
| - setActiveStackState(nextIndex == 1);
|
| - }
|
| - mClicked = false;
|
| - finishScrollStacks();
|
| - mStacks[getTabStackIndex()].onUpOrCancel(time);
|
| - mInputMode = SwipeMode.NONE;
|
| - }
|
| -
|
| - /**
|
| - * Pushes a rectangle to be drawn on the screen on top of everything.
|
| - *
|
| - * @param rect The rectangle to be drawn on screen
|
| - * @param color The color of the rectangle
|
| - */
|
| - public void pushDebugRect(Rect rect, int color) {
|
| - if (rect.left > rect.right) {
|
| - int tmp = rect.right;
|
| - rect.right = rect.left;
|
| - rect.left = tmp;
|
| - }
|
| - if (rect.top > rect.bottom) {
|
| - int tmp = rect.bottom;
|
| - rect.bottom = rect.top;
|
| - rect.top = tmp;
|
| - }
|
| - mRenderHost.pushDebugRect(rect, color);
|
| - }
|
| -
|
| - @Override
|
| - public void onPinch(long time, float x0, float y0, float x1, float y1, boolean firstEvent) {
|
| - mStacks[getTabStackIndex()].onPinch(time, x0, y0, x1, y1, firstEvent);
|
| - }
|
| -
|
| - @Override
|
| - protected void updateLayout(long time, long dt) {
|
| - super.updateLayout(time, dt);
|
| - boolean needUpdate = false;
|
| -
|
| - final PortraitViewport viewport = getViewportParameters();
|
| - mStackRects[0].left = viewport.getStack0Left();
|
| - mStackRects[0].right = mStackRects[0].left + viewport.getWidth();
|
| - mStackRects[0].top = viewport.getStack0Top();
|
| - mStackRects[0].bottom = mStackRects[0].top + viewport.getHeight();
|
| - mStackRects[1].left = mStackRects[0].left + viewport.getStack0ToStack1TranslationX();
|
| - mStackRects[1].right = mStackRects[1].left + viewport.getWidth();
|
| - mStackRects[1].top = mStackRects[0].top + viewport.getStack0ToStack1TranslationY();
|
| - mStackRects[1].bottom = mStackRects[1].top + viewport.getHeight();
|
| -
|
| - mStacks[0].setStackFocusInfo(1.0f + mRenderedScrollOffset,
|
| - mSortingComparator == mOrderComparator ? mTabModelSelector.getModel(false).index()
|
| - : -1);
|
| - mStacks[1].setStackFocusInfo(-mRenderedScrollOffset, mSortingComparator == mOrderComparator
|
| - ? mTabModelSelector.getModel(true).index()
|
| - : -1);
|
| -
|
| - // Compute position and visibility
|
| - mStacks[0].computeTabPosition(time, mStackRects[0]);
|
| - mStacks[1].computeTabPosition(time, mStackRects[1]);
|
| -
|
| - // Pre-allocate/resize {@link #mLayoutTabs} before it get populated by
|
| - // computeTabPositionAndAppendLayoutTabs.
|
| - final int tabVisibleCount = mStacks[0].getVisibleCount() + mStacks[1].getVisibleCount();
|
| -
|
| - if (tabVisibleCount == 0) {
|
| - mLayoutTabs = null;
|
| - } else if (mLayoutTabs == null || mLayoutTabs.length != tabVisibleCount) {
|
| - mLayoutTabs = new LayoutTab[tabVisibleCount];
|
| - }
|
| -
|
| - int index = 0;
|
| - if (getTabStackIndex() == 1) {
|
| - index = appendVisibleLayoutTabs(time, 0, mLayoutTabs, index);
|
| - index = appendVisibleLayoutTabs(time, 1, mLayoutTabs, index);
|
| - } else {
|
| - index = appendVisibleLayoutTabs(time, 1, mLayoutTabs, index);
|
| - index = appendVisibleLayoutTabs(time, 0, mLayoutTabs, index);
|
| - }
|
| - assert index == tabVisibleCount : "index should be incremented up to tabVisibleCount";
|
| -
|
| - // Update tab snapping
|
| - for (int i = 0; i < tabVisibleCount; i++) {
|
| - if (mLayoutTabs[i].updateSnap(dt)) needUpdate = true;
|
| - }
|
| -
|
| - if (needUpdate) requestUpdate();
|
| -
|
| - // Since we've updated the positions of the stacks and tabs, let's go ahead and update
|
| - // the visible tabs.
|
| - updateTabPriority();
|
| - }
|
| -
|
| - private int appendVisibleLayoutTabs(long time, int stackIndex, LayoutTab[] tabs, int tabIndex) {
|
| - final StackTab[] stackTabs = mStacks[stackIndex].getTabs();
|
| - if (stackTabs != null) {
|
| - for (int i = 0; i < stackTabs.length; i++) {
|
| - LayoutTab t = stackTabs[i].getLayoutTab();
|
| - if (t.isVisible()) tabs[tabIndex++] = t;
|
| - }
|
| - }
|
| - return tabIndex;
|
| - }
|
| -
|
| - /**
|
| - * Sets the active tab stack.
|
| - *
|
| - * @param isIncognito True if the model to select is incognito.
|
| - * @return Whether the tab stack index passed in differed from the currently selected stack.
|
| - */
|
| - public boolean setActiveStackState(boolean isIncognito) {
|
| - if (isIncognito == mTabModelSelector.isIncognitoSelected()) return false;
|
| - mTemporarySelectedStack = isIncognito;
|
| - return true;
|
| - }
|
| -
|
| - private void resetScrollData() {
|
| - mScrollIndexOffset = -getTabStackIndex();
|
| - mRenderedScrollOffset = mScrollIndexOffset;
|
| - }
|
| -
|
| - /**
|
| - * Based on the current position, determine if we will map mScrollDistance linearly to
|
| - * mRenderedScrollDistance. The logic is, if there is only stack, we will not map linearly;
|
| - * if we are scrolling two the boundary of either of the stacks, we will not map linearly;
|
| - * otherwise yes.
|
| - */
|
| - private boolean canScrollLinearly(int fromStackIndex) {
|
| - int count = mStacks.length;
|
| - if (!(mScrollIndexOffset <= 0 && -mScrollIndexOffset <= (count - 1))) {
|
| - return false;
|
| - }
|
| - // since we only have two stacks now, we have a shortcut to calculate
|
| - // empty stacks
|
| - return mStacks[fromStackIndex ^ 0x01].isDisplayable();
|
| - }
|
| -
|
| - private float getFullScrollDistance() {
|
| - float distance =
|
| - getOrientation() == Orientation.PORTRAIT ? getWidth() : getHeightMinusTopControls();
|
| - return distance - 2 * getViewportParameters().getInnerMargin();
|
| - }
|
| -
|
| - @Override
|
| - public void doneHiding() {
|
| - super.doneHiding();
|
| - mTabModelSelector.commitAllTabClosures();
|
| - }
|
| -
|
| - /**
|
| - * Extracts the tabs from a stack and append them into a list.
|
| - * @param stack The stack that contains the tabs.
|
| - * @param outList The output list where will be the tabs from the stack.
|
| - * @param index The current number of item in the outList.
|
| - * @return The updated index incremented by the number of tabs in the stack.
|
| - */
|
| - private static int addAllTabs(Stack stack, StackTab[] outList, int index) {
|
| - StackTab[] stackTabs = stack.getTabs();
|
| - if (stackTabs != null) {
|
| - for (int i = 0; i < stackTabs.length; ++i) {
|
| - outList[index++] = stackTabs[i];
|
| - }
|
| - }
|
| - return index;
|
| - }
|
| -
|
| - /**
|
| - * Comparator that helps ordering StackTab's visibility sorting value in a decreasing order.
|
| - */
|
| - private static class VisibilityComparator implements Comparator<StackTab>, Serializable {
|
| - @Override
|
| - public int compare(StackTab tab1, StackTab tab2) {
|
| - return (int) (tab2.getVisiblitySortingValue() - tab1.getVisiblitySortingValue());
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Comparator that helps ordering StackTab's visibility sorting value in a decreasing order.
|
| - */
|
| - private static class OrderComparator implements Comparator<StackTab>, Serializable {
|
| - @Override
|
| - public int compare(StackTab tab1, StackTab tab2) {
|
| - return tab1.getOrderSortingValue() - tab2.getOrderSortingValue();
|
| - }
|
| - }
|
| -
|
| - private boolean updateSortedPriorityArray(Comparator<StackTab> comparator) {
|
| - final int allTabsCount = mStacks[0].getCount() + mStacks[1].getCount();
|
| - if (allTabsCount == 0) return false;
|
| - if (mSortedPriorityArray == null || mSortedPriorityArray.length != allTabsCount) {
|
| - mSortedPriorityArray = new StackTab[allTabsCount];
|
| - }
|
| - int sortedOffset = 0;
|
| - sortedOffset = addAllTabs(mStacks[0], mSortedPriorityArray, sortedOffset);
|
| - sortedOffset = addAllTabs(mStacks[1], mSortedPriorityArray, sortedOffset);
|
| - assert sortedOffset == mSortedPriorityArray.length;
|
| - Arrays.sort(mSortedPriorityArray, comparator);
|
| - return true;
|
| - }
|
| -
|
| - /**
|
| - * Updates the priority list of the {@link LayoutTab} and sends it the systems having processing
|
| - * to do on a per {@link LayoutTab} basis. Priority meaning may change based on the current
|
| - * comparator stored in {@link #mSortingComparator}.
|
| - *
|
| - * Do not use {@link #mSortedPriorityArray} out side this context. It is only a member to avoid
|
| - * doing an allocation every frames.
|
| - */
|
| - private void updateTabPriority() {
|
| - if (!updateSortedPriorityArray(mSortingComparator)) return;
|
| - updateTabsVisibility(mSortedPriorityArray);
|
| - updateDelayedLayoutTabInit(mSortedPriorityArray);
|
| - }
|
| -
|
| - /**
|
| - * Updates the list of visible tab Id that the tab content manager is suppose to serve. The list
|
| - * is ordered by priority. The first ones must be in the manager, then the remaining ones should
|
| - * have at least approximations if possible.
|
| - *
|
| - * @param sortedPriorityArray The array of all the {@link StackTab} sorted by priority.
|
| - */
|
| - private void updateTabsVisibility(StackTab[] sortedPriorityArray) {
|
| - mVisibilityArray.clear();
|
| - for (int i = 0; i < sortedPriorityArray.length; i++) {
|
| - mVisibilityArray.add(sortedPriorityArray[i].getId());
|
| - }
|
| - updateCacheVisibleIds(mVisibilityArray);
|
| - }
|
| -
|
| - /**
|
| - * Initializes the {@link LayoutTab} a few at a time. This function is to be called once a
|
| - * frame.
|
| - * The logic of that function is not as trivial as it should be because the input array we want
|
| - * to initialize the tab from keeps getting reordered from calls to call. This is needed to
|
| - * get the highest priority tab initialized first.
|
| - *
|
| - * @param sortedPriorityArray The array of all the {@link StackTab} sorted by priority.
|
| - */
|
| - private void updateDelayedLayoutTabInit(StackTab[] sortedPriorityArray) {
|
| - if (!mDelayedLayoutTabInitRequired) return;
|
| -
|
| - int initialized = 0;
|
| - final int count = sortedPriorityArray.length;
|
| - for (int i = 0; i < count; i++) {
|
| - if (initialized >= LAYOUTTAB_ASYNCHRONOUS_INITIALIZATION_BATCH_SIZE) return;
|
| -
|
| - LayoutTab layoutTab = sortedPriorityArray[i].getLayoutTab();
|
| - // The actual initialization is done by the parent class.
|
| - if (super.initLayoutTabFromHost(layoutTab)) {
|
| - initialized++;
|
| - }
|
| - }
|
| - if (initialized == 0) mDelayedLayoutTabInitRequired = false;
|
| - }
|
| -
|
| - @Override
|
| - protected boolean initLayoutTabFromHost(LayoutTab layoutTab) {
|
| - if (layoutTab.isInitFromHostNeeded()) mDelayedLayoutTabInitRequired = true;
|
| - return false;
|
| - }
|
| -
|
| - /**
|
| - * Sets properties for animations.
|
| - * @param prop The property to update
|
| - * @param p New value of the property
|
| - */
|
| - @Override
|
| - public void setProperty(Property prop, float p) {
|
| - switch (prop) {
|
| - case STACK_SNAP:
|
| - mRenderedScrollOffset = p;
|
| - mScrollIndexOffset = p;
|
| - break;
|
| - case INNER_MARGIN_PERCENT:
|
| - mInnerMarginPercent = p;
|
| - break;
|
| - case STACK_OFFSET_Y_PERCENT:
|
| - mStackOffsetYPercent = p;
|
| - break;
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Called by the stacks whenever they start an animation.
|
| - */
|
| - public void onStackAnimationStarted() {
|
| - if (mStackAnimationCount == 0) super.onAnimationStarted();
|
| - mStackAnimationCount++;
|
| - }
|
| -
|
| - /**
|
| - * Called by the stacks whenever they finish their animations.
|
| - */
|
| - public void onStackAnimationFinished() {
|
| - mStackAnimationCount--;
|
| - if (mStackAnimationCount == 0) super.onAnimationFinished();
|
| - }
|
| -
|
| - @Override
|
| - protected SceneLayer getSceneLayer() {
|
| - return mSceneLayer;
|
| - }
|
| -
|
| - @Override
|
| - protected void updateSceneLayer(Rect viewport, Rect contentViewport,
|
| - LayerTitleCache layerTitleCache, TabContentManager tabContentManager,
|
| - ResourceManager resourceManager, ChromeFullscreenManager fullscreenManager) {
|
| - super.updateSceneLayer(viewport, contentViewport, layerTitleCache, tabContentManager,
|
| - resourceManager, fullscreenManager);
|
| - assert mSceneLayer != null;
|
| - mSceneLayer.pushLayers(getContext(), viewport, contentViewport, this, layerTitleCache,
|
| - tabContentManager, resourceManager);
|
| - }
|
| -}
|
|
|