blob: cc166db21e6799570a593e1f39c2e22ee190038a [file] [log] [blame]
// 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.stack;
import android.content.Context;
import android.content.res.Resources;
import android.support.annotation.IntDef;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.compositor.animation.FloatProperty;
import org.chromium.chrome.browser.compositor.layouts.ChromeAnimation;
import org.chromium.chrome.browser.compositor.layouts.Layout.Orientation;
import org.chromium.chrome.browser.compositor.layouts.components.LayoutTab;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* StackTab is used to keep track of a thumbnail's bitmap and position and to
* draw itself onto the GL canvas at the desired Y Offset.
* @VisibleForTesting
*/
public class StackTab implements ChromeAnimation.Animatable {
/**
* Properties that can be animated by using a
* {@link org.chromium.chrome.browser.compositor.layouts.ChromeAnimation.Animatable}.
*/
@IntDef({Property.SCALE, Property.SCROLL_OFFSET, Property.ALPHA, Property.X_IN_STACK_INFLUENCE,
Property.X_IN_STACK_OFFSET, Property.X_OUT_OF_STACK, Property.Y_IN_STACK_INFLUENCE,
Property.Y_IN_STACK_OFFSET, Property.Y_OUT_OF_STACK, Property.DISCARD_AMOUNT})
@Retention(RetentionPolicy.SOURCE)
public @interface Property {
int SCALE = 0;
int SCROLL_OFFSET = 1;
int ALPHA = 2;
int X_IN_STACK_INFLUENCE = 3;
int X_IN_STACK_OFFSET = 4;
int X_OUT_OF_STACK = 5;
int Y_IN_STACK_INFLUENCE = 6;
int Y_IN_STACK_OFFSET = 7;
int Y_OUT_OF_STACK = 8;
int DISCARD_AMOUNT = 9;
}
// Cached values from values/dimens.xml
public static float sStackedTabVisibleSize; // stacked_tab_visible_size
public static float sStackBufferWidth; // stack_buffer_width
public static float sStackBufferHeight; // stack_buffer_height
// Positioner selector
private float mXInStackInfluence = 1.0f;
private float mYInStackInfluence = 1.0f;
// In stack positioner
private float mScrollOffset;
private float mXInStackOffset;
private float mYInStackOffset;
// Out of stack positioner
private float mXOutOfStack;
private float mYOutOfStack;
// Values that get animated
private float mAlpha = 1.0f;
private float mScale = 1.0f;
private float mDiscardAmount; // This might alter position, rotation and alpha
// Discard states
private float mDiscardOriginX;
private float mDiscardOriginY;
private boolean mDiscardFromClick;
// The index of the tab in the stack
private int mIndex;
// True if the tab is currently being removed (while animating).
protected boolean mDying;
// The visibility sorting value is used to determine the importance of the tab for
// texture allocation. It is computed from the area and its position in the stack.
// Larger values will have more priority for acquiring texture. Negative values "often"
// means that the tab is not visible at all (but there are no guaranty and it's fine).
private float mCachedVisibleArea; // Intermediate value
private float mCachedIndexDistance; // Intermediate value
private float mCacheStackVisibility = 1.0f; // Intermediate value
private long mVisiblitySortingValue; // Sorting value based on visible area.
private int mOrderSortingValue; // Sorting value based on distance to selection.
private LayoutTab mLayoutTab;
public static final FloatProperty<StackTab> SCROLL_OFFSET =
new FloatProperty<StackTab>("SCROLL_OFFSET") {
@Override
public void setValue(StackTab layoutTab, float v) {
layoutTab.setScrollOffset(v);
}
@Override
public Float get(StackTab layoutTab) {
return layoutTab.getScrollOffset();
}
};
/**
* @param tab The tab this instance is supposed to draw.
*/
public StackTab(LayoutTab tab) {
mLayoutTab = tab;
}
/**
* @param index The new index in the stack layout.
*/
public void setNewIndex(int index) {
mIndex = index;
}
/**
* @return The index in the stack layout.
*/
public int getIndex() {
return mIndex;
}
/**
* @return The {@link LayoutTab} this instance is supposed to draw.
*/
public LayoutTab getLayoutTab() {
return mLayoutTab;
}
/**
* Set the {@link LayoutTab} this instance is supposed to draw.
*/
public void setLayoutTab(LayoutTab tab) {
mLayoutTab = tab;
}
/**
* @return The id of the tab, same as the id from the Tab in TabModel.
*/
public int getId() {
return mLayoutTab.getId();
}
/**
* @param y The vertical translation to be applied after the placement in the stack.
*/
public void setYInStackOffset(float y) {
mYInStackOffset = y;
}
/**
* @return The vertical translation applied after the placement in the stack.
*/
public float getYInStackOffset() {
return mYInStackOffset;
}
/**
* @param x The horizontal translation to be applied after the placement in the stack.
*/
public void setXInStackOffset(float x) {
mXInStackOffset = x;
}
/**
* @return The horizontal translation applied after the placement in the stack.
*/
public float getXInStackOffset() {
return mXInStackOffset;
}
/**
* @param y The vertical absolute position when out of stack.
*/
public void setYOutOfStack(float y) {
mYOutOfStack = y;
}
/**
* @return The vertical absolute position when out of stack.
*/
public float getYOutOfStack() {
return mYOutOfStack;
}
/**
* @param x The horizontal absolute position when out of stack.
*/
public void setXOutOfStack(float x) {
mXOutOfStack = x;
}
/**
* @return The horizontal absolute position when out of stack.
*/
public float getXOutOfStack() {
return mXOutOfStack;
}
/**
* Set the transparency value for all of the tab (the contents,
* border, etc...). For components that allow specifying
* their own alpha values, it will use the min of these two fields.
*
* @param f The transparency value for the tab.
*/
public void setAlpha(float f) {
mAlpha = f;
}
/**
* @return The transparency value for all of the tab components.
*/
public float getAlpha() {
return mAlpha;
}
/**
* @param xInStackInfluence The horizontal blend value between instack
* and out of stack pacement [0 .. 1].
*/
public void setXInStackInfluence(float xInStackInfluence) {
mXInStackInfluence = xInStackInfluence;
}
/**
* @return The horizontal blend value between instack and out of stack pacement [0 .. 1].
*/
public float getXInStackInfluence() {
return mXInStackInfluence;
}
/**
* @param yInStackInfluence The vertical blend value between instack
* and out of stack pacement [0 .. 1].
*/
public void setYInStackInfluence(float yInStackInfluence) {
mYInStackInfluence = yInStackInfluence;
}
/**
* @return The verical blend value between instack and out of stack pacement [0 .. 1].
*/
public float getYInStackInfluence() {
return mYInStackInfluence;
}
/**
* @param scale The scale to apply to the tab, compared to the parent.
*/
public void setScale(float scale) {
mScale = scale;
}
/**
* @return The scale to apply to the tab, compared to the parent.
*/
public float getScale() {
return mScale;
}
/**
* @param offset The offset of the tab along the scrolling direction in scroll space.
*/
public void setScrollOffset(float offset) {
mScrollOffset = offset;
}
/**
* @return The offset of the tab along the scrolling direction in scroll space.
*/
public float getScrollOffset() {
return mScrollOffset;
}
/**
* @param amount The amount of discard displacement. 0 is no discard. Negative is discard
* on the left. Positive is discard on the right.
*/
public void setDiscardAmount(float amount) {
mDiscardAmount = amount;
}
/**
* @param deltaAmount The amount of delta discard to be added to the current discard amount.
*/
public void addToDiscardAmount(float deltaAmount) {
mDiscardAmount += deltaAmount;
}
/**
* @return The amount of discard displacement. 0 is no discard. Negative is discard
* on the left. Positive is discard on the right.
*/
public float getDiscardAmount() {
return mDiscardAmount;
}
/**
* @param x The x coordinate in tab space of where the discard transforms should originate.
*/
public void setDiscardOriginX(float x) {
mDiscardOriginX = x;
}
/**
* @param y The y coordinate in tab space of where the discard transforms should originate.
*/
public void setDiscardOriginY(float y) {
mDiscardOriginY = y;
}
/**
* @return The x coordinate in tab space of where the discard transforms should originate.
*/
public float getDiscardOriginX() {
return mDiscardOriginX;
}
/**
* @return The y coordinate in tab space of where the discard transforms should originate.
*/
public float getDiscardOriginY() {
return mDiscardOriginY;
}
/**
* @param fromClick Whether or not this discard was from a click event.
*/
public void setDiscardFromClick(boolean fromClick) {
mDiscardFromClick = fromClick;
}
/**
* @return Whether or not this discard was from a click event.
*/
public boolean getDiscardFromClick() {
return mDiscardFromClick;
}
/**
* @param dying True if the Tab/ContentView will be destroyed, and we are still animating its
* visible representation.
*/
public void setDying(boolean dying) {
mDying = dying;
}
/**
* @return True if the Tab/ContentView is destroyed, but we are still animating its
* visible representation.
*/
public boolean isDying() {
return mDying;
}
/**
* @param orientation The orientation to choose to get the size.
* @return The size of the content along the provided orientation.
*/
public float getSizeInScrollDirection(@Orientation int orientation) {
if (orientation == Orientation.PORTRAIT) {
return mLayoutTab.getScaledContentHeight();
} else {
return mLayoutTab.getScaledContentWidth();
}
}
/**
* Helper function that gather the static constants from values/dimens.xml.
* @param context The Android Context.
*/
public static void resetDimensionConstants(Context context) {
Resources res = context.getResources();
final float pxToDp = 1.0f / res.getDisplayMetrics().density;
sStackedTabVisibleSize =
res.getDimensionPixelOffset(R.dimen.stacked_tab_visible_size) * pxToDp;
sStackBufferWidth = res.getDimensionPixelOffset(R.dimen.stack_buffer_width) * pxToDp;
sStackBufferHeight = res.getDimensionPixelOffset(R.dimen.stack_buffer_height) * pxToDp;
}
/**
* Reset the offset to factory default.
*/
public void resetOffset() {
mXInStackInfluence = 1.0f;
mYInStackInfluence = 1.0f;
mScrollOffset = 0.0f;
mXInStackOffset = 0.0f;
mYInStackOffset = 0.0f;
mXOutOfStack = 0.0f;
mYOutOfStack = 0.0f;
mDiscardOriginX = 0.f;
mDiscardOriginY = 0.f;
mDiscardFromClick = false;
}
/**
* Updates the cached visible area value to be used to sort tabs by visibility.
* @param referenceIndex The index that has the highest priority.
*/
public void updateVisiblityValue(int referenceIndex) {
mCachedVisibleArea = mLayoutTab.computeVisibleArea();
mCachedIndexDistance = Math.abs(mIndex - referenceIndex);
mOrderSortingValue = computeOrderSortingValue(mCachedIndexDistance, mCacheStackVisibility);
mVisiblitySortingValue = computeVisibilitySortingValue(
mCachedVisibleArea, mOrderSortingValue, mCacheStackVisibility);
}
/**
* Updates the cached visible area value to be used to sort tabs by visibility.
* @param stackVisibility Multiplier that represents how much the stack fills the screen.
*/
public void updateStackVisiblityValue(float stackVisibility) {
mCacheStackVisibility = stackVisibility;
mOrderSortingValue = computeOrderSortingValue(mCachedIndexDistance, mCacheStackVisibility);
mVisiblitySortingValue = computeVisibilitySortingValue(
mCachedVisibleArea, mOrderSortingValue, mCacheStackVisibility);
}
/**
* Computes the visibility sorting value based on the tab visible area, its distance to the
* central index and the overall visibility of the stack.
* The '-index' index factor need to be smaller for stack that have small visibility.
* Multiplying by a small stackVisibility makes it bigger (because it is negative), hence the
* division. To avoid dividing by 0 it need to be offset a bit. 0.1f is the 'a bit' part of
* the explanation.
*/
private static long computeVisibilitySortingValue(
float area, float orderSortingValue, float stackVisibility) {
return (long) (area * stackVisibility - orderSortingValue);
}
/**
* @return The cached visible sorting value. Call updateCachedVisibleArea to update it.
*/
public long getVisiblitySortingValue() {
return mVisiblitySortingValue;
}
/**
* Computes the ordering value only based on the distance of the tab to the center one.
* Low values have higher priority.
*/
private static int computeOrderSortingValue(float indexDistance, float stackVisibility) {
return (int) ((indexDistance + 1) / (0.1f + 0.9f * stackVisibility));
}
/**
* @return The cached order sorting value. Used to sort based on the tab ordering rather than
* visible area.
*/
public int getOrderSortingValue() {
return mOrderSortingValue;
}
/**
* Callback for
* {@link org.chromium.chrome.browser.compositor.layouts.ChromeAnimation.Animatable}
*
* @param prop The property to set
* @param val The value to set it to
*/
@Override
public void setProperty(@Property int prop, float val) {
switch (prop) {
case Property.SCALE:
setScale(val);
break;
case Property.SCROLL_OFFSET:
setScrollOffset(val);
break;
case Property.ALPHA:
setAlpha(val);
break;
case Property.X_IN_STACK_INFLUENCE:
setXInStackInfluence(val);
break;
case Property.X_IN_STACK_OFFSET:
setXInStackOffset(val);
break;
case Property.X_OUT_OF_STACK:
setXOutOfStack(val);
break;
case Property.Y_IN_STACK_INFLUENCE:
setYInStackInfluence(val);
break;
case Property.Y_IN_STACK_OFFSET:
setYInStackOffset(val);
break;
case Property.Y_OUT_OF_STACK:
setYOutOfStack(val);
break;
case Property.DISCARD_AMOUNT:
setDiscardAmount(val);
break;
}
}
@Override
public void onPropertyAnimationFinished(@Property int prop) {}
}