chromium/chrome/test/android/javatests/src/org/chromium/chrome/test/transit/edge_to_edge/ViewportFitCoverPageStation.java

// Copyright 2024 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.test.transit.edge_to_edge;

import static org.chromium.base.test.transit.Condition.whether;

import org.chromium.base.supplier.Supplier;
import org.chromium.base.test.transit.ConditionStatus;
import org.chromium.base.test.transit.Elements;
import org.chromium.base.test.transit.LogicalElement;
import org.chromium.chrome.browser.browser_controls.BottomControlsStacker;
import org.chromium.chrome.browser.browser_controls.BottomControlsStacker.LayerType;
import org.chromium.chrome.browser.ui.edge_to_edge.EdgeToEdgeUtils;
import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
import org.chromium.chrome.test.transit.edge_to_edge.EdgeToEdgeConditions.BottomControlsStackerCondition;
import org.chromium.chrome.test.transit.edge_to_edge.EdgeToEdgeConditions.EdgeToEdgeControllerCondition;
import org.chromium.chrome.test.transit.page.PageStation;
import org.chromium.chrome.test.transit.page.WebPageStation;
import org.chromium.content_public.browser.test.transit.HtmlElement;
import org.chromium.content_public.browser.test.transit.HtmlElementSpec;

/**
 * Station represent an page that has viewport-fit=cover. It expects an {@link
 * org.chromium.chrome.browser.ui.edge_to_edge.EdgeToEdgeController} to be ready when the page
 * loads, so it requires the test to have corresponding test flag setup to make {@link
 * EdgeToEdgeUtils#isEnabled()}
 */
public class ViewportFitCoverPageStation extends WebPageStation {
    /** Page opt-in edge-to-edge with sub frames. */
    public static final String PATH_VIEWPORT_FIT_COVER_SUB_FRAMES =
            "/chrome/test/data/android/edge_to_edge/viewport-fit-cover-sub-frames-main.html";

    public static final HtmlElementSpec AVOID_BOTTOM_DIV = new HtmlElementSpec("positioned-bottom");
    public static final HtmlElementSpec FULLSCREEN_MAIN_BUTTON =
            new HtmlElementSpec("fullscreen-main");

    private HtmlElement mAvoidBottomElement;
    private HtmlElement mFullScreenButtonElement;

    protected <T extends ViewportFitCoverPageStation> ViewportFitCoverPageStation(
            Builder<T> builder) {
        super(builder);
    }

    /** Load the test page viewport-fit-cover-sub-frames-main.html. */
    public static ViewportFitCoverPageStation loadViewportFitCoverPage(
            ChromeTabbedActivityTestRule activityTestRule, PageStation currentPageStation) {
        String url = activityTestRule.getTestServer().getURL(PATH_VIEWPORT_FIT_COVER_SUB_FRAMES);
        return currentPageStation.loadPageProgrammatically(
                url, new Builder<>(ViewportFitCoverPageStation::new));
    }

    @Override
    public void declareElements(Elements.Builder elements) {
        super.declareElements(elements);

        // Ensure the web page elements are drawn and visible.
        mAvoidBottomElement =
                elements.declareElement(new HtmlElement(AVOID_BOTTOM_DIV, mWebContentsSupplier));
        mFullScreenButtonElement =
                elements.declareElement(
                        new HtmlElement(FULLSCREEN_MAIN_BUTTON, mWebContentsSupplier));

        // Declare requiring EdgeToEdgeController, meaning #setDecorFitsSystemWindows(false)
        elements.declareEnterCondition(new EdgeToEdgeControllerCondition(mActivityElement));

        // Ensure the bottom chin is on display.
        Supplier<BottomControlsStacker> bottomControlsStacker =
                elements.declareEnterCondition(
                        new BottomControlsStackerCondition(mActivityElement));
        elements.declareLogicalElement(
                LogicalElement.uiThreadLogicalElement(
                        "Bottom chin is not on display",
                        this::isBottomChinShowing,
                        bottomControlsStacker));
    }

    private ConditionStatus isBottomChinShowing(BottomControlsStacker bottomControlsStacker) {
        var bottomChinLayer = bottomControlsStacker.getLayerForTesting(LayerType.BOTTOM_CHIN);
        return whether(bottomChinLayer != null && bottomChinLayer.getHeight() > 0);
    }
}