chromium/chrome/browser/ui/android/native_page/java/src/org/chromium/chrome/browser/ui/native_page/BasicNativePage.java

// Copyright 2016 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.ui.native_page;

import android.graphics.Rect;
import android.view.View;
import android.widget.FrameLayout.LayoutParams;

import org.chromium.base.Callback;
import org.chromium.base.supplier.DestroyableObservableSupplier;
import org.chromium.components.browser_ui.styles.ChromeColors;
import org.chromium.content_public.browser.LoadUrlParams;

/**
 * A basic implementation of a white {@link NativePage} that docks below the toolbar. This class
 * handles default behavior for background color, URL updates and margins.
 *
 * Sub-classes must call {@link #initWithView(View)} to finish setup.
 */
public abstract class BasicNativePage implements NativePage {
    private final NativePageHost mHost;
    private final int mBackgroundColor;
    private DestroyableObservableSupplier<Rect> mMarginSupplier;
    private Callback<Rect> mMarginObserver;
    private View mView;
    private String mUrl;
    private SmoothTransitionDelegate mSmoothTransitionDelegate;

    protected BasicNativePage(NativePageHost host) {
        mHost = host;
        mBackgroundColor = ChromeColors.getPrimaryBackgroundColor(host.getContext(), false);
    }

    /** Sets the View contained in this native page and finishes BasicNativePage initialization. */
    protected void initWithView(View view) {
        assert mView == null : "initWithView() should only be called once";
        mView = view;

        mMarginObserver = result -> updateMargins(result);
        mMarginSupplier = mHost.createDefaultMarginSupplier();
        mMarginSupplier.addObserver(mMarginObserver);

        // Update margins immediately if available rather than waiting for a posted notification.
        // Waiting for a posted notification could allow a layout pass to occur before the margins
        // are set.
        if (mMarginSupplier.get() != null) {
            updateMargins(mMarginSupplier.get());
        }
    }

    @Override
    public final View getView() {
        assert mView != null : "Need to call initWithView()";

        return mView;
    }

    @Override
    public SmoothTransitionDelegate enableSmoothTransition() {
        if (mSmoothTransitionDelegate == null) {
            mSmoothTransitionDelegate = new BasicSmoothTransitionDelegate(getView());
        }
        return mSmoothTransitionDelegate;
    }

    @Override
    public String getUrl() {
        return mUrl;
    }

    @Override
    public int getBackgroundColor() {
        return mBackgroundColor;
    }

    @Override
    public boolean needsToolbarShadow() {
        return true;
    }

    @Override
    public void updateForUrl(String url) {
        mUrl = url;
    }

    @Override
    public void destroy() {
        if (mMarginSupplier != null) {
            mMarginSupplier.removeObserver(mMarginObserver);
            mMarginSupplier.destroy();
        }
    }

    /**
     * Tells the native page framework that the url should be changed.
     * @param url The URL of the page.
     * @param replaceLastUrl Whether the last navigation entry should be replaced with the new URL.
     */
    public void onStateChange(String url, boolean replaceLastUrl) {
        if (url.equals(mUrl)) return;
        LoadUrlParams params = new LoadUrlParams(url);
        params.setShouldReplaceCurrentEntry(replaceLastUrl);
        mHost.loadUrl(params, /* incognito= */ false);
    }

    /** Updates the top margin depending on whether the browser controls are shown or hidden. */
    private void updateMargins(Rect margins) {
        LayoutParams layoutParams =
                new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
        layoutParams.setMargins(margins.left, margins.top, margins.left, margins.bottom);
        getView().setLayoutParams(layoutParams);
    }

    public SmoothTransitionDelegate getSmoothTransitionDelegateForTesting() {
        return mSmoothTransitionDelegate;
    }
}