Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3909)

Unified Diff: chrome/android/java_staging/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutTab.java

Issue 1141283003: Upstream oodles of Chrome for Android code into Chromium. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: final patch? Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/android/java_staging/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutTab.java
diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutTab.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutTab.java
new file mode 100644
index 0000000000000000000000000000000000000000..f4b27e633ab02705c8af67dadb63206b08c57b9b
--- /dev/null
+++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/compositor/overlays/strip/StripLayoutTab.java
@@ -0,0 +1,566 @@
+// 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.overlays.strip;
+
+import static org.chromium.chrome.browser.compositor.layouts.ChromeAnimation.AnimatableAnimation.createAnimation;
+
+import android.content.Context;
+import android.graphics.RectF;
+
+import com.google.android.apps.chrome.R;
+
+import org.chromium.base.VisibleForTesting;
+import org.chromium.chrome.browser.Tab;
+import org.chromium.chrome.browser.compositor.layouts.ChromeAnimation;
+import org.chromium.chrome.browser.compositor.layouts.ChromeAnimation.Animatable;
+import org.chromium.chrome.browser.compositor.layouts.ChromeAnimation.Animation;
+import org.chromium.chrome.browser.compositor.layouts.LayoutRenderHost;
+import org.chromium.chrome.browser.compositor.layouts.components.CompositorButton;
+import org.chromium.chrome.browser.compositor.layouts.components.VirtualView;
+import org.chromium.chrome.browser.compositor.overlays.strip.TabLoadTracker.TabLoadTrackerCallback;
+import org.chromium.chrome.browser.util.MathUtils;
+import org.chromium.ui.base.LocalizationUtils;
+import org.chromium.ui.resources.AndroidResourceType;
+import org.chromium.ui.resources.LayoutResource;
+import org.chromium.ui.resources.ResourceManager;
+
+import java.util.List;
+
+/**
+ * {@link StripLayoutTab} is used to keep track of the strip position and rendering information for
+ * a particular tab so it can draw itself onto the GL canvas.
+ */
+public class StripLayoutTab
+ implements ChromeAnimation.Animatable<StripLayoutTab.Property>, VirtualView {
+ /**
+ * Animatable properties that can be used with a {@link ChromeAnimation.Animatable} on a
+ * {@link StripLayoutTab}.
+ */
+ enum Property {
+ X_OFFSET,
+ Y_OFFSET,
+ WIDTH,
+ }
+
+ // Behavior Constants
+ private static final float VISIBILITY_FADE_CLOSE_BUTTON_PERCENTAGE = 0.99f;
+
+ // Animation/Timer Constants
+ private static final int ANIM_TAB_CLOSE_BUTTON_FADE_MS = 150;
+
+ // Close button width
+ private static final int CLOSE_BUTTON_WIDTH_DP = 36;
+
+ private int mId = Tab.INVALID_TAB_ID;
+
+ private final TabLoadTracker mLoadTracker;
+ private final LayoutRenderHost mRenderHost;
+
+ private boolean mVisible = true;
+ private boolean mIsDying = false;
+ private boolean mCanShowCloseButton = true;
+ private boolean mIncognito;
+ private float mContentOffsetX;
+ private float mVisiblePercentage = 1.f;
+ private String mAccessibilityDescription;
+
+ // Ideal intermediate parameters
+ private float mIdealX;
+ private float mTabOffsetX;
+ private float mTabOffsetY;
+
+ // Actual draw parameters
+ private float mDrawX;
+ private float mDrawY;
+ private float mWidth;
+ private float mHeight;
+ private RectF mTouchTarget = new RectF();
+
+ private boolean mShowingCloseButton = true;
+
+ private final CompositorButton mCloseButton;
+
+ // Content Animations
+ private ChromeAnimation<Animatable<?>> mContentAnimations;
+
+ private float mLoadingSpinnerRotationDegrees = 0.0f;
+
+ // Preallocated
+ private final RectF mClosePlacement = new RectF();
+
+ /**
+ * Create a {@link StripLayoutTab} that represents the {@link Tab} with an id of
+ * {@code id}.
+ *
+ * @param context An Android context for accessing system resources.
+ * @param id The id of the {@link Tab} to visually represent.
+ * @param loadTrackerCallback The {@link TabLoadTrackerCallback} to be notified of loading state
+ * changes.
+ * @param renderHost The {@link LayoutRenderHost}.
+ * @param incogntio Whether or not this layout tab is icognito.
+ */
+ public StripLayoutTab(Context context, int id, TabLoadTrackerCallback loadTrackerCallback,
+ LayoutRenderHost renderHost, boolean incognito) {
+ mId = id;
+ mLoadTracker = new TabLoadTracker(id, loadTrackerCallback);
+ mRenderHost = renderHost;
+ mIncognito = incognito;
+ mCloseButton = new CompositorButton(context, 0, 0);
+ mCloseButton.setResources(R.drawable.btn_tab_close_normal, R.drawable.btn_tab_close_pressed,
+ R.drawable.btn_tab_close_white_normal, R.drawable.btn_tab_close_white_pressed);
+ mCloseButton.setIncognito(mIncognito);
+ mCloseButton.setBounds(getCloseRect());
+ mCloseButton.setClickSlop(0.f);
+ String description =
+ context.getResources().getString(R.string.accessibility_tabstrip_btn_close_tab);
+ mCloseButton.setAccessibilityDescription(description, description);
+ }
+
+ /**
+ * Get a list of virtual views for accessibility events.
+ *
+ * @param views A List to populate with virtual views.
+ */
+ public void getVirtualViews(List<VirtualView> views) {
+ if (mShowingCloseButton) views.add(mCloseButton);
+ views.add(this);
+ }
+
+ /**
+ * @param description A description for accessibility events.
+ */
+ public void setAccessibilityDescription(String description) {
+ mAccessibilityDescription = description;
+ }
+
+ @Override
+ public String getAccessibilityDescription() {
+ return mAccessibilityDescription;
+ }
+
+ @Override
+ public void getTouchTarget(RectF target) {
+ target.set(mTouchTarget);
+ }
+
+ @Override
+ public boolean checkClicked(float x, float y) {
+ return mTouchTarget.contains(x, y);
+ }
+
+ /**
+ * @return The id of the {@link Tab} this {@link StripLayoutTab} represents.
+ */
+ public int getId() {
+ return mId;
+ }
+
+ /**
+ * @param foreground Whether or not this tab is a foreground tab.
+ * @return The Android resource that represents the tab background.
+ */
+ public int getResourceId(boolean foreground) {
+ if (foreground) {
+ return mIncognito ? R.drawable.bg_tabstrip_incognito_tab : R.drawable.bg_tabstrip_tab;
+ }
+ return mIncognito ? R.drawable.bg_tabstrip_incognito_background_tab
+ : R.drawable.bg_tabstrip_background_tab;
+ }
+
+ /**
+ * @param visible Whether or not this {@link StripLayoutTab} should be drawn.
+ */
+ public void setVisible(boolean visible) {
+ mVisible = visible;
+ }
+
+ /**
+ * @return Whether or not this {@link StripLayoutTab} should be drawn.
+ */
+ public boolean isVisible() {
+ return mVisible;
+ }
+
+ /**
+ * Mark this tab as in the process of dying. This lets us track which tabs are dead after
+ * animations.
+ * @param isDying Whether or not the tab is dying.
+ */
+ public void setIsDying(boolean isDying) {
+ mIsDying = isDying;
+ }
+
+ /**
+ * @return Whether or not the tab is dying.
+ */
+ public boolean isDying() {
+ return mIsDying;
+ }
+
+ /**
+ * @return Whether or not this tab should be visually represented as loading.
+ */
+ public boolean isLoading() {
+ return mLoadTracker.isLoading();
+ }
+
+ /**
+ * @return The rotation of the loading spinner in degrees.
+ */
+ public float getLoadingSpinnerRotation() {
+ return mLoadingSpinnerRotationDegrees;
+ }
+
+ /**
+ * Additive spinner rotation update.
+ * @param rotation The amount to rotate the spinner by in degrees.
+ */
+ public void addLoadingSpinnerRotation(float rotation) {
+ mLoadingSpinnerRotationDegrees = (mLoadingSpinnerRotationDegrees + rotation) % 1080;
+ }
+
+ /**
+ * Called when this tab has started loading.
+ */
+ public void pageLoadingStarted() {
+ mLoadTracker.pageLoadingStarted();
+ }
+
+ /**
+ * Called when this tab has finished loading.
+ */
+ public void pageLoadingFinished() {
+ mLoadTracker.pageLoadingFinished();
+ }
+
+ /**
+ * Called when this tab has started loading resources.
+ */
+ public void loadingStarted() {
+ mLoadTracker.loadingStarted();
+ }
+
+ /**
+ * Called when this tab has finished loading resources.
+ */
+ public void loadingFinished() {
+ mLoadTracker.loadingFinished();
+ }
+
+ /**
+ * @param offsetX How far to offset the tab content (favicons and title).
+ */
+ public void setContentOffsetX(float offsetX) {
+ mContentOffsetX = MathUtils.clamp(offsetX, 0.f, mWidth);
+ }
+
+ /**
+ * @return How far to offset the tab content (favicons and title).
+ */
+ public float getContentOffsetX() {
+ return mContentOffsetX;
+ }
+
+ /**
+ * @param visiblePercentage How much of the tab is visible (not overlapped by other tabs).
+ */
+ public void setVisiblePercentage(float visiblePercentage) {
+ mVisiblePercentage = visiblePercentage;
+ checkCloseButtonVisibility(true);
+ }
+
+ /**
+ * @return How much of the tab is visible (not overlapped by other tabs).
+ */
+ @VisibleForTesting
+ public float getVisiblePercentage() {
+ return mVisiblePercentage;
+ }
+
+ /**
+ * @param show Whether or not the close button is allowed to be shown.
+ */
+ public void setCanShowCloseButton(boolean show) {
+ mCanShowCloseButton = show;
+ checkCloseButtonVisibility(true);
+ }
+
+ /**
+ * @param x The actual position in the strip, taking into account stacking, scrolling, etc.
+ */
+ public void setDrawX(float x) {
+ mCloseButton.setX(mCloseButton.getX() + (x - mDrawX));
+ mDrawX = x;
+ mTouchTarget.left = mDrawX;
+ mTouchTarget.right = mDrawX + mWidth;
+ }
+
+ /**
+ * @return The actual position in the strip, taking into account stacking, scrolling, etc.
+ */
+ public float getDrawX() {
+ return mDrawX;
+ }
+
+ /**
+ * @param y The vertical position for the tab.
+ */
+ public void setDrawY(float y) {
+ mCloseButton.setY(mCloseButton.getY() + (y - mDrawY));
+ mDrawY = y;
+ mTouchTarget.top = mDrawY;
+ mTouchTarget.bottom = mDrawY + mHeight;
+ }
+
+ /**
+ * @return The vertical position for the tab.
+ */
+ public float getDrawY() {
+ return mDrawY;
+ }
+
+ /**
+ * @param width The width of the tab.
+ */
+ public void setWidth(float width) {
+ mWidth = width;
+ resetCloseRect();
+ mTouchTarget.right = mDrawX + mWidth;
+ }
+
+ /**
+ * @return The width of the tab.
+ */
+ public float getWidth() {
+ return mWidth;
+ }
+
+ /**
+ * @param height The height of the tab.
+ */
+ public void setHeight(float height) {
+ mHeight = height;
+ resetCloseRect();
+ mTouchTarget.bottom = mDrawY + mHeight;
+ }
+
+ /**
+ * @return The height of the tab.
+ */
+ public float getHeight() {
+ return mHeight;
+ }
+
+ /**
+ * @param closePressed The current pressed state of the attached button.
+ */
+ public void setClosePressed(boolean closePressed) {
+ mCloseButton.setPressed(closePressed);
+ }
+
+ /**
+ * @return The current pressed state of the close button.
+ */
+ public boolean getClosePressed() {
+ return mCloseButton.isPressed();
+ }
+
+ /**
+ * @return The close button for this tab.
+ */
+ public CompositorButton getCloseButton() {
+ return mCloseButton;
+ }
+
+ /**
+ * This represents how much this tab's width should be counted when positioning tabs in the
+ * stack. As tabs close or open, their width weight is increased. They visually take up
+ * the same amount of space but the other tabs will smoothly move out of the way to make room.
+ * @return The weight from 0 to 1 that the width of this tab should have on the stack.
+ */
+ public float getWidthWeight() {
+ return MathUtils.clamp(1.f - mDrawY / mHeight, 0.f, 1.f);
+ }
+
+ /**
+ * @param x The x position of the position to test.
+ * @param y The y position of the position to test.
+ * @return Whether or not {@code x} and {@code y} is over the close button for this tab and
+ * if the button can be clicked.
+ */
+ public boolean checkCloseHitTest(float x, float y) {
+ return mShowingCloseButton ? mCloseButton.checkClicked(x, y) : false;
+ }
+
+ /**
+ * This is used to help calculate the tab's position and is not used for rendering.
+ * @param offsetX The offset of the tab (used for drag and drop, slide animating, etc).
+ */
+ public void setOffsetX(float offsetX) {
+ mTabOffsetX = offsetX;
+ }
+
+ /**
+ * This is used to help calculate the tab's position and is not used for rendering.
+ * @return The offset of the tab (used for drag and drop, slide animating, etc).
+ */
+ public float getOffsetX() {
+ return mTabOffsetX;
+ }
+
+ /**
+ * This is used to help calculate the tab's position and is not used for rendering.
+ * @param x The ideal position, in an infinitely long strip, of this tab.
+ */
+ public void setIdealX(float x) {
+ mIdealX = x;
+ }
+
+ /**
+ * This is used to help calculate the tab's position and is not used for rendering.
+ * @return The ideal position, in an infinitely long strip, of this tab.
+ */
+ public float getIdealX() {
+ return mIdealX;
+ }
+
+ /**
+ * This is used to help calculate the tab's position and is not used for rendering.
+ * @param offsetY The vertical offset of the tab.
+ */
+ public void setOffsetY(float offsetY) {
+ mTabOffsetY = offsetY;
+ }
+
+ /**
+ * This is used to help calculate the tab's position and is not used for rendering.
+ * @return The vertical offset of the tab.
+ */
+ public float getOffsetY() {
+ return mTabOffsetY;
+ }
+
+ private void startAnimation(Animation<Animatable<?>> animation, boolean finishPrevious) {
+ if (finishPrevious) finishAnimation();
+
+ if (mContentAnimations == null) {
+ mContentAnimations = new ChromeAnimation<Animatable<?>>();
+ }
+
+ mContentAnimations.add(animation);
+ }
+
+ /**
+ * Finishes any content animations currently owned and running on this StripLayoutTab.
+ */
+ public void finishAnimation() {
+ if (mContentAnimations == null) return;
+
+ mContentAnimations.updateAndFinish();
+ mContentAnimations = null;
+ }
+
+ /**
+ * @return Whether or not there are any content animations running on this StripLayoutTab.
+ */
+ public boolean isAnimating() {
+ return mContentAnimations != null;
+ }
+
+ /**
+ * Updates any content animations on this StripLayoutTab.
+ * @param time The current time of the app in ms.
+ * @param jumpToEnd Whether or not to force any current animations to end.
+ * @return Whether or not animations are done.
+ */
+ public boolean onUpdateAnimation(long time, boolean jumpToEnd) {
+ if (mContentAnimations == null) return true;
+
+ boolean finished = true;
+ if (jumpToEnd) {
+ finished = mContentAnimations.finished();
+ } else {
+ finished = mContentAnimations.update(time);
+ }
+
+ if (jumpToEnd || finished) finishAnimation();
+
+ return finished;
+ }
+
+ @Override
+ public void setProperty(Property prop, float val) {
+ switch (prop) {
+ case X_OFFSET:
+ setOffsetX(val);
+ break;
+ case Y_OFFSET:
+ setOffsetY(val);
+ break;
+ case WIDTH:
+ setWidth(val);
+ break;
+ }
+ }
+
+ private void resetCloseRect() {
+ RectF closeRect = getCloseRect();
+ mCloseButton.setWidth(closeRect.width());
+ mCloseButton.setHeight(closeRect.height());
+ mCloseButton.setX(closeRect.left);
+ mCloseButton.setY(closeRect.top);
+ }
+
+ private RectF getCloseRect() {
+ if (!LocalizationUtils.isLayoutRtl()) {
+ mClosePlacement.left = getWidth() - CLOSE_BUTTON_WIDTH_DP;
+ mClosePlacement.right = mClosePlacement.left + CLOSE_BUTTON_WIDTH_DP;
+ } else {
+ mClosePlacement.left = 0;
+ mClosePlacement.right = CLOSE_BUTTON_WIDTH_DP;
+ }
+
+ mClosePlacement.top = 0;
+ mClosePlacement.bottom = getHeight();
+
+ float xOffset = 0;
+ ResourceManager manager = mRenderHost.getResourceManager();
+ if (manager != null) {
+ LayoutResource resource =
+ manager.getResource(AndroidResourceType.STATIC, getResourceId(false));
+ if (resource != null) {
+ xOffset = LocalizationUtils.isLayoutRtl()
+ ? resource.getPadding().left
+ : -(resource.getBitmapSize().width() - resource.getPadding().right);
+ }
+ }
+
+ mClosePlacement.offset(getDrawX() + xOffset, getDrawY());
+ return mClosePlacement;
+ }
+
+ // TODO(dtrainor): Don't animate this if we're selecting or deselecting this tab.
+ private void checkCloseButtonVisibility(boolean animate) {
+ boolean shouldShow =
+ mCanShowCloseButton && mVisiblePercentage > VISIBILITY_FADE_CLOSE_BUTTON_PERCENTAGE;
+
+ if (shouldShow != mShowingCloseButton) {
+ float opacity = shouldShow ? 1.f : 0.f;
+ if (animate) {
+ startAnimation(buildCloseButtonOpacityAnimation(opacity), true);
+ } else {
+ mCloseButton.setOpacity(opacity);
+ }
+ mShowingCloseButton = shouldShow;
+ if (!mShowingCloseButton) mCloseButton.setPressed(false);
+ }
+ }
+
+ private Animation<Animatable<?>> buildCloseButtonOpacityAnimation(float finalOpacity) {
+ return createAnimation(mCloseButton, CompositorButton.Property.OPACITY,
+ mCloseButton.getOpacity(), finalOpacity, ANIM_TAB_CLOSE_BUTTON_FADE_MS, 0, false,
+ ChromeAnimation.getLinearInterpolator());
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698