| Index: chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/ToolbarControlContainer.java
|
| diff --git a/chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/ToolbarControlContainer.java b/chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/ToolbarControlContainer.java
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..306dbb963b93348a1533b1293f8befa29234b55e
|
| --- /dev/null
|
| +++ b/chrome/android/java_staging/src/org/chromium/chrome/browser/toolbar/ToolbarControlContainer.java
|
| @@ -0,0 +1,351 @@
|
| +// 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.toolbar;
|
| +
|
| +import android.content.Context;
|
| +import android.graphics.Canvas;
|
| +import android.graphics.PorterDuff;
|
| +import android.graphics.Rect;
|
| +import android.graphics.drawable.Drawable;
|
| +import android.graphics.drawable.LayerDrawable;
|
| +import android.graphics.drawable.ScaleDrawable;
|
| +import android.util.AttributeSet;
|
| +import android.view.MotionEvent;
|
| +import android.view.View;
|
| +import android.widget.FrameLayout;
|
| +
|
| +import com.google.android.apps.chrome.R;
|
| +
|
| +import org.chromium.chrome.browser.compositor.layouts.eventfilter.EdgeSwipeHandler;
|
| +import org.chromium.chrome.browser.contextualsearch.SwipeRecognizer;
|
| +import org.chromium.chrome.browser.widget.ControlContainer;
|
| +import org.chromium.chrome.browser.widget.SmoothProgressBar;
|
| +import org.chromium.chrome.browser.widget.SmoothProgressBar.ProgressChangeListener;
|
| +import org.chromium.chrome.browser.widget.ViewResourceFrameLayout;
|
| +import org.chromium.chrome.browser.widget.findinpage.FindToolbarManager;
|
| +import org.chromium.ui.UiUtils;
|
| +import org.chromium.ui.resources.dynamics.ViewResourceAdapter;
|
| +
|
| +/**
|
| + * Layout for the browser controls (omnibox, menu, tab strip, etc..).
|
| + */
|
| +public class ToolbarControlContainer extends FrameLayout implements ControlContainer {
|
| + private final float mTabStripHeight;
|
| +
|
| + private Toolbar mToolbar;
|
| + private ToolbarViewResourceFrameLayout mToolbarContainer;
|
| + private View mMenuBtn;
|
| +
|
| + private final SwipeRecognizer mSwipeRecognizer;
|
| + private EdgeSwipeHandler mSwipeHandler;
|
| +
|
| + private FindToolbarManager mFindToolbarManager;
|
| +
|
| + private ViewResourceAdapter mProgressResourceAdapter;
|
| +
|
| + /**
|
| + * Constructs a new control container.
|
| + * <p>
|
| + * This constructor is used when inflating from XML.
|
| + *
|
| + * @param context The context used to build this view.
|
| + * @param attrs The attributes used to determine how to construct this view.
|
| + */
|
| + public ToolbarControlContainer(Context context, AttributeSet attrs) {
|
| + super(context, attrs);
|
| + mTabStripHeight = context.getResources().getDimension(R.dimen.tab_strip_height);
|
| + mSwipeRecognizer = new SwipeRecognizerImpl(context);
|
| + }
|
| +
|
| + @Override
|
| + public ViewResourceAdapter getProgressResourceAdapter() {
|
| + return mProgressResourceAdapter;
|
| + }
|
| +
|
| + @Override
|
| + public ViewResourceAdapter getToolbarResourceAdapter() {
|
| + return mToolbarContainer.getResourceAdapter();
|
| + }
|
| +
|
| + @Override
|
| + public void setSwipeHandler(EdgeSwipeHandler handler) {
|
| + mSwipeHandler = handler;
|
| + mSwipeRecognizer.setSwipeHandler(handler);
|
| + }
|
| +
|
| + /**
|
| + * Sets the manager in charge of find in page.
|
| + */
|
| + public void setFindToolbarManager(FindToolbarManager manager) {
|
| + mFindToolbarManager = manager;
|
| + }
|
| +
|
| + @Override
|
| + public void onFinishInflate() {
|
| + mToolbar = (Toolbar) findViewById(R.id.toolbar);
|
| + mToolbarContainer = (ToolbarViewResourceFrameLayout) findViewById(R.id.toolbar_container);
|
| + mMenuBtn = findViewById(R.id.menu_button);
|
| +
|
| + // TODO(yusufo): Get rid of the calls below and avoid casting to the layout without making
|
| + // the interface bigger.
|
| + SmoothProgressBar progressView = ((ToolbarLayout) mToolbar).getProgressBar();
|
| + if (progressView != null) {
|
| + mProgressResourceAdapter = new ProgressViewResourceAdapter(progressView);
|
| + }
|
| +
|
| + if (mToolbar instanceof ToolbarTablet) {
|
| + // On tablet, draw a fake tab strip and toolbar until the compositor is ready to draw
|
| + // the real tab strip. (On phone, the toolbar is made entirely of Android views, which
|
| + // are already initialized.)
|
| + setBackgroundResource(R.drawable.toolbar_background);
|
| + }
|
| +
|
| + assert mToolbar != null;
|
| + assert mMenuBtn != null;
|
| +
|
| + super.onFinishInflate();
|
| + }
|
| +
|
| + /**
|
| + * Invalidate the entire capturing bitmap region.
|
| + */
|
| + public void invalidateBitmap() {
|
| + ((ToolbarViewResourceAdapter) getToolbarResourceAdapter()).forceInvalidate();
|
| + }
|
| +
|
| + /**
|
| + * Update whether the control container is ready to have the bitmap representation of
|
| + * itself be captured.
|
| + */
|
| + public void setReadyForBitmapCapture(boolean ready) {
|
| + mToolbarContainer.mReadyForBitmapCapture = ready;
|
| + }
|
| +
|
| + /**
|
| + * The layout that handles generating the toolbar view resource.
|
| + */
|
| + // Only publicly visible due to lint warnings.
|
| + public static class ToolbarViewResourceFrameLayout extends ViewResourceFrameLayout {
|
| + private boolean mReadyForBitmapCapture;
|
| +
|
| + public ToolbarViewResourceFrameLayout(Context context, AttributeSet attrs) {
|
| + super(context, attrs);
|
| + }
|
| +
|
| + @Override
|
| + protected ViewResourceAdapter createResourceAdapter() {
|
| + return new ToolbarViewResourceAdapter(
|
| + this, (Toolbar) findViewById(R.id.toolbar));
|
| + }
|
| +
|
| + @Override
|
| + protected boolean isReadyForCapture() {
|
| + return mReadyForBitmapCapture;
|
| + }
|
| + }
|
| +
|
| + private static class ProgressViewResourceAdapter extends ViewResourceAdapter
|
| + implements ProgressChangeListener {
|
| +
|
| + private final SmoothProgressBar mProgressView;
|
| + private final Rect mPreviousDrawBounds = new Rect();
|
| + private int mProgressVisibility;
|
| + private int mProgress;
|
| +
|
| + ProgressViewResourceAdapter(SmoothProgressBar progressView) {
|
| + super(progressView);
|
| +
|
| + mProgressView = progressView;
|
| + mProgressVisibility = mProgressView.getVisibility();
|
| + progressView.addProgressChangeListener(this);
|
| + }
|
| +
|
| + @Override
|
| + public void onProgressChanged(int progress) {
|
| + if (mProgressVisibility != View.VISIBLE) return;
|
| + if (progress < mProgress) {
|
| + mPreviousDrawBounds.setEmpty();
|
| + }
|
| + mProgress = progress;
|
| + invalidate(null);
|
| + }
|
| +
|
| + @Override
|
| + public void onProgressVisibilityChanged(int visibility) {
|
| + if (mProgressVisibility == visibility) return;
|
| +
|
| + if (visibility == View.VISIBLE || mProgressVisibility == View.VISIBLE) {
|
| + invalidate(null);
|
| + mPreviousDrawBounds.setEmpty();
|
| + }
|
| + mProgressVisibility = visibility;
|
| + }
|
| +
|
| + @Override
|
| + protected void onCaptureStart(Canvas canvas, Rect dirtyRect) {
|
| + canvas.save();
|
| + canvas.clipRect(
|
| + mPreviousDrawBounds.right, 0,
|
| + mProgressView.getWidth(), mProgressView.getHeight());
|
| + canvas.drawColor(0, PorterDuff.Mode.CLEAR);
|
| + canvas.restore();
|
| +
|
| + super.onCaptureStart(canvas, dirtyRect);
|
| + }
|
| +
|
| + @Override
|
| + protected void capture(Canvas canvas) {
|
| + if (mProgressVisibility != View.VISIBLE) {
|
| + canvas.drawColor(0, PorterDuff.Mode.CLEAR);
|
| + } else {
|
| + super.capture(canvas);
|
| + }
|
| + }
|
| +
|
| + @Override
|
| + protected void onCaptureEnd() {
|
| + super.onCaptureEnd();
|
| + // If we are unable to get accurate draw bounds, then set the draw bounds to
|
| + // ensure the entire view is cleared.
|
| + mPreviousDrawBounds.setEmpty();
|
| +
|
| + // The secondary drawable has an alpha component, so track the bounds of the
|
| + // primary drawable. This will allow the subsequent draw call to clear the secondary
|
| + // portion not overlapped by the primary to prevent the alpha components from
|
| + // stacking and getting progressively darker.
|
| + Drawable progressDrawable = mProgressView.getProgressDrawable();
|
| + if (progressDrawable instanceof LayerDrawable) {
|
| + LayerDrawable progressLayerDrawable = (LayerDrawable) progressDrawable;
|
| + for (int i = 0; i < progressLayerDrawable.getNumberOfLayers(); i++) {
|
| + if (progressLayerDrawable.getId(i) != android.R.id.progress) continue;
|
| + Drawable primaryProgressDrawable = progressLayerDrawable.getDrawable(i);
|
| + if (!(primaryProgressDrawable instanceof ScaleDrawable)) continue;
|
| +
|
| + ((ScaleDrawable) primaryProgressDrawable).getDrawable().copyBounds(
|
| + mPreviousDrawBounds);
|
| + }
|
| + }
|
| + }
|
| +
|
| + @Override
|
| + protected void computeContentPadding(Rect outContentPadding) {
|
| + super.computeContentPadding(outContentPadding);
|
| + MarginLayoutParams layoutParams =
|
| + (MarginLayoutParams) mProgressView.getLayoutParams();
|
| + outContentPadding.offset(0, layoutParams.topMargin);
|
| + }
|
| + }
|
| +
|
| + private static class ToolbarViewResourceAdapter extends ViewResourceAdapter {
|
| + private final int mToolbarActualHeightPx;
|
| + private final int[] mTempPosition = new int[2];
|
| +
|
| + private final View mToolbarContainer;
|
| + private final Toolbar mToolbar;
|
| +
|
| + /** Builds the resource adapter for the toolbar. */
|
| + public ToolbarViewResourceAdapter(View toolbarContainer, Toolbar toolbar) {
|
| + super(toolbarContainer);
|
| +
|
| + mToolbarContainer = toolbarContainer;
|
| + mToolbar = toolbar;
|
| + mToolbarActualHeightPx = toolbarContainer.getResources().getDimensionPixelSize(
|
| + R.dimen.control_container_height);
|
| + }
|
| +
|
| + /**
|
| + * Force this resource to be recaptured in full, ignoring the checks
|
| + * {@link #invalidate(Rect)} does.
|
| + */
|
| + public void forceInvalidate() {
|
| + super.invalidate(null);
|
| + }
|
| +
|
| + @Override
|
| + public boolean isDirty() {
|
| + return mToolbar != null && mToolbar.isReadyForTextureCapture() && super.isDirty();
|
| + }
|
| +
|
| + @Override
|
| + protected void onCaptureStart(Canvas canvas, Rect dirtyRect) {
|
| + // Erase the shadow component of the bitmap if the clip rect included shadow. Because
|
| + // this region is not opaque painting twice would be bad.
|
| + if (dirtyRect.intersects(
|
| + 0, mToolbarActualHeightPx,
|
| + mToolbarContainer.getWidth(), mToolbarContainer.getHeight())) {
|
| + canvas.save();
|
| + canvas.clipRect(
|
| + 0, mToolbarActualHeightPx,
|
| + mToolbarContainer.getWidth(), mToolbarContainer.getHeight());
|
| + canvas.drawColor(0, PorterDuff.Mode.CLEAR);
|
| + canvas.restore();
|
| + }
|
| +
|
| + mToolbar.setTextureCaptureMode(true);
|
| +
|
| + super.onCaptureStart(canvas, dirtyRect);
|
| + }
|
| +
|
| + @Override
|
| + protected void onCaptureEnd() {
|
| + mToolbar.setTextureCaptureMode(false);
|
| + }
|
| +
|
| + @Override
|
| + protected void computeContentPadding(Rect outContentPadding) {
|
| + outContentPadding.set(0, 0, mToolbarContainer.getWidth(), mToolbarActualHeightPx);
|
| + }
|
| +
|
| + @Override
|
| + protected void computeContentAperture(Rect outContentAperture) {
|
| + mToolbar.getLocationBarContentRect(outContentAperture);
|
| + mToolbar.getPositionRelativeToContainer(mToolbarContainer, mTempPosition);
|
| + outContentAperture.offset(mTempPosition[0], mTempPosition[1]);
|
| + }
|
| + }
|
| +
|
| + @Override
|
| + public boolean onTouchEvent(MotionEvent event) {
|
| + // Don't eat the event if we don't have a handler.
|
| + if (mSwipeHandler == null) return false;
|
| +
|
| + // If we have ACTION_DOWN in this context, that means either no child consumed the event or
|
| + // this class is the top UI at the event position. Then, we don't need to feed the event to
|
| + // mGestureDetector here because the event is already once fed in onInterceptTouchEvent().
|
| + // Moreover, we have to return true so that this class can continue to intercept all the
|
| + // subsequent events.
|
| + if (event.getActionMasked() == MotionEvent.ACTION_DOWN && !isOnTabStrip(event)) {
|
| + return true;
|
| + }
|
| +
|
| + return mSwipeRecognizer.onTouchEvent(event);
|
| + }
|
| +
|
| + @Override
|
| + public boolean onInterceptTouchEvent(MotionEvent event) {
|
| + if (mSwipeHandler == null) return false;
|
| +
|
| + return mSwipeRecognizer.onTouchEvent(event);
|
| + }
|
| +
|
| + private boolean isOnTabStrip(MotionEvent e) {
|
| + return e.getY() <= mTabStripHeight;
|
| + }
|
| +
|
| + private class SwipeRecognizerImpl extends SwipeRecognizer {
|
| + public SwipeRecognizerImpl(Context context) {
|
| + super(context);
|
| + }
|
| +
|
| + @Override
|
| + public boolean shouldRecognizeSwipe(MotionEvent e1, MotionEvent e2) {
|
| + if (isOnTabStrip(e1)) return false;
|
| + if (mToolbar.shouldIgnoreSwipeGesture()) return false;
|
| + if (UiUtils.isKeyboardShowing(getContext(), ToolbarControlContainer.this)) return false;
|
| + if (mFindToolbarManager == null || mFindToolbarManager.isShowing()) return false;
|
| + return true;
|
| + }
|
| + }
|
| +}
|
|
|