chromium/chrome/browser/ui/android/toolbar/java/src/org/chromium/chrome/browser/toolbar/bottom/ScrollingBottomViewSceneLayer.java

// Copyright 2018 The Chromium Authors
// 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.bottom;

import android.graphics.RectF;
import android.view.View;

import org.jni_zero.JNINamespace;
import org.jni_zero.NativeMethods;

import org.chromium.chrome.browser.layouts.EventFilter;
import org.chromium.chrome.browser.layouts.SceneOverlay;
import org.chromium.chrome.browser.layouts.components.VirtualView;
import org.chromium.chrome.browser.layouts.scene_layer.SceneLayer;
import org.chromium.chrome.browser.layouts.scene_layer.SceneOverlayLayer;
import org.chromium.components.browser_ui.widget.ViewResourceFrameLayout;
import org.chromium.ui.resources.ResourceManager;

import java.util.List;

/**
 * A composited view that sits at the bottom of the screen and listens to changes in the browser
 * controls. When visible, the view will mimic the behavior of the top browser controls when
 * scrolling.
 */
@JNINamespace("android")
public class ScrollingBottomViewSceneLayer extends SceneOverlayLayer implements SceneOverlay {
    /** Handle to the native side of this class. */
    private long mNativePtr;

    /** The resource ID used to reference the view bitmap in native. */
    private int mResourceId;

    /** The height of the view's top shadow. */
    private int mTopShadowHeightPx;

    /** The current Y offset of the bottom view in px. */
    private int mCurrentYOffsetPx;

    /** The current X offset of the bottom view in px. */
    private int mCurrentXOffsetPx;

    /** Whether the {@link SceneLayer}is visible. */
    private boolean mIsVisible;

    /** The {@link ViewResourceFrameLayout} that this scene layer represents. */
    private ViewResourceFrameLayout mBottomView;

    /**
     * Build a composited bottom view layer.
     * @param bottomView The view used to generate the composited version.
     * @param topShadowHeightPx The height of the shadow on the top of the view in px if it exists.
     */
    public ScrollingBottomViewSceneLayer(
            ViewResourceFrameLayout bottomView, int topShadowHeightPx) {
        mBottomView = bottomView;
        mResourceId = mBottomView.getId();
        mTopShadowHeightPx = topShadowHeightPx;
        mIsVisible = true;
    }

    /**
     * Build a copy of an existing {@link ScrollingBottomViewSceneLayer}.
     * @param sceneLayer The existing scene layer to copy. This only copies the source view,
     *                   resource ID, and shadow height. All other state is ignored.
     */
    public ScrollingBottomViewSceneLayer(ScrollingBottomViewSceneLayer sceneLayer) {
        this(sceneLayer.mBottomView, sceneLayer.mTopShadowHeightPx);
    }

    /**
     * Set the view's offset from the bottom of the screen in px. An offset of 0 means the view is
     * completely visible. An increasing offset will move the view down.
     * @param offsetPx The view's offset in px.
     */
    public void setYOffset(int offsetPx) {
        mCurrentYOffsetPx = offsetPx;
    }

    /**
     * @param offsetPx The view's X translation in px.
     */
    public void setXOffset(int offsetPx) {
        mCurrentXOffsetPx = offsetPx;
    }

    /**
     * @param visible Whether this {@link SceneLayer} is visible.
     */
    public void setIsVisible(boolean visible) {
        mIsVisible = visible;
    }

    @Override
    protected void initializeNative() {
        if (mNativePtr == 0) {
            mNativePtr =
                    ScrollingBottomViewSceneLayerJni.get().init(ScrollingBottomViewSceneLayer.this);
        }
        assert mNativePtr != 0;
    }

    @Override
    public void setContentTree(SceneLayer contentTree) {
        ScrollingBottomViewSceneLayerJni.get()
                .setContentTree(mNativePtr, ScrollingBottomViewSceneLayer.this, contentTree);
    }

    @Override
    public SceneOverlayLayer getUpdatedSceneOverlayTree(
            RectF viewport, RectF visibleViewport, ResourceManager resourceManager, float yOffset) {
        // The composited shadow should be visible if the Android toolbar's isn't.
        boolean isShadowVisible = mBottomView.getVisibility() != View.VISIBLE;

        ScrollingBottomViewSceneLayerJni.get()
                .updateScrollingBottomViewLayer(
                        mNativePtr,
                        ScrollingBottomViewSceneLayer.this,
                        resourceManager,
                        mResourceId,
                        mTopShadowHeightPx,
                        mCurrentXOffsetPx,
                        viewport.height() + mCurrentYOffsetPx,
                        isShadowVisible);

        return this;
    }

    @Override
    public boolean isSceneOverlayTreeShowing() {
        // If the offset is greater than the toolbar's height, don't draw the layer.
        return mIsVisible && mCurrentYOffsetPx < mBottomView.getHeight() - mTopShadowHeightPx;
    }

    @Override
    public EventFilter getEventFilter() {
        return null;
    }

    @Override
    public boolean shouldHideAndroidBrowserControls() {
        return false;
    }

    @Override
    public boolean updateOverlay(long time, long dt) {
        return false;
    }

    @Override
    public boolean onBackPressed() {
        return false;
    }

    @Override
    public boolean handlesTabCreating() {
        return false;
    }

    @Override
    public void onSizeChanged(
            float width, float height, float visibleViewportOffsetY, int orientation) {}

    @Override
    public void getVirtualViews(List<VirtualView> views) {}

    @NativeMethods
    interface Natives {
        long init(ScrollingBottomViewSceneLayer caller);

        void setContentTree(
                long nativeScrollingBottomViewSceneLayer,
                ScrollingBottomViewSceneLayer caller,
                SceneLayer contentTree);

        void updateScrollingBottomViewLayer(
                long nativeScrollingBottomViewSceneLayer,
                ScrollingBottomViewSceneLayer caller,
                ResourceManager resourceManager,
                int viewResourceId,
                int shadowHeightPx,
                float xOffset,
                float yOffset,
                boolean showShadow);
    }
}