chromium/chrome/android/javatests/src/org/chromium/chrome/browser/vr/WebXrArSessionTest.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.vr;

import static org.chromium.chrome.browser.vr.WebXrArTestFramework.PAGE_LOAD_TIMEOUT_S;
import static org.chromium.chrome.browser.vr.WebXrArTestFramework.POLL_TIMEOUT_SHORT_MS;

import androidx.test.filters.MediumTest;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.RuleChain;
import org.junit.runner.RunWith;

import org.chromium.base.test.params.ParameterAnnotations.ClassParameter;
import org.chromium.base.test.params.ParameterAnnotations.UseRunnerDelegate;
import org.chromium.base.test.params.ParameterSet;
import org.chromium.base.test.params.ParameterizedRunner;
import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.chrome.browser.flags.ChromeSwitches;
import org.chromium.chrome.browser.modaldialog.ChromeModalDialogTestUtils;
import org.chromium.chrome.browser.vr.rules.XrActivityRestriction;
import org.chromium.chrome.browser.vr.util.ArTestRuleUtils;
import org.chromium.chrome.browser.vr.util.PermissionUtils;
import org.chromium.chrome.test.ChromeActivityTestRule;
import org.chromium.chrome.test.ChromeJUnit4RunnerDelegate;
import org.chromium.content_public.browser.WebContents;
import org.chromium.content_public.browser.test.util.DOMUtils;

import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeoutException;

/** End-to-end tests for testing WebXR for AR's requestSession behavior. */
@RunWith(ParameterizedRunner.class)
@UseRunnerDelegate(ChromeJUnit4RunnerDelegate.class)
@CommandLineFlags.Add({
    ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
    "enable-features=WebXR,WebXRARModule,WebXRHitTest,LogJsConsoleMessages"
})
public class WebXrArSessionTest {
    @ClassParameter
    private static List<ParameterSet> sClassParams =
            ArTestRuleUtils.generateDefaultTestRuleParameters();

    @Rule public RuleChain mRuleChain;

    private ChromeActivityTestRule mTestRule;
    private WebXrArTestFramework mWebXrArTestFramework;

    public WebXrArSessionTest(Callable<ChromeActivityTestRule> callable) throws Exception {
        mTestRule = callable.call();
        mRuleChain = ArTestRuleUtils.wrapRuleInActivityRestrictionRule(mTestRule);
    }

    @Before
    public void setUp() {
        mWebXrArTestFramework = new WebXrArTestFramework(mTestRule);
    }

    /** Tests that a session request for AR succeeds. */
    @Test
    @MediumTest
    @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL})
    public void testArRequestSessionSucceeds() {
        mWebXrArTestFramework.loadFileAndAwaitInitialization(
                "test_ar_request_session_succeeds", PAGE_LOAD_TIMEOUT_S);
        mWebXrArTestFramework.enterSessionWithUserGestureOrFail();
        mWebXrArTestFramework.assertNoJavaScriptErrors();
    }

    /**
     * Tests that consenting causes future attempts to skip the permission prompt as long as no
     * navigation occurs.
     */
    @Test
    @MediumTest
    @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL})
    public void testArPermissionPersistance() {
        mWebXrArTestFramework.loadFileAndAwaitInitialization(
                "test_ar_request_session_succeeds", PAGE_LOAD_TIMEOUT_S);

        // Start new session, accepting the consent prompt
        mWebXrArTestFramework.enterSessionWithUserGestureOrFail(/* needsCameraPermission= */ false);
        mWebXrArTestFramework.endSession();
        mWebXrArTestFramework.assertNoJavaScriptErrors();
        mWebXrArTestFramework.pollJavaScriptBooleanOrFail(
                "sessionInfos[sessionTypes.AR].currentSession == null", POLL_TIMEOUT_SHORT_MS);

        // Start yet another session, but go through a path that doesn't automatically handle
        // the permission prompt to ensure that it doesn't actually appear.
        mWebXrArTestFramework.enterSessionWithUserGesture();
        mWebXrArTestFramework.pollJavaScriptBooleanOrFail(
                "sessionInfos[sessionTypes.AR].currentSession != null", POLL_TIMEOUT_SHORT_MS);
        mWebXrArTestFramework.assertNoJavaScriptErrors();
    }

    /**
     * Tests that repeatedly starting and stopping AR sessions does not cause any unexpected
     * behavior. Regression test for https://crbug.com/837894.
     */
    @Test
    @MediumTest
    @XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL})
    public void testRepeatedArSessionsSucceed() {
        mWebXrArTestFramework.loadFileAndAwaitInitialization(
                "test_ar_request_session_succeeds", PAGE_LOAD_TIMEOUT_S);
        for (int i = 0; i < 2; i++) {
            mWebXrArTestFramework.enterSessionWithUserGestureOrFail();
            mWebXrArTestFramework.endSession();
        }
        mWebXrArTestFramework.assertNoJavaScriptErrors();
    }

    /**
     * Tests that requesting a permission prompt during an AR Session shows the browser
     * controls/greys out the screen and doesn't exit the AR Session.
     */
    @Test
    @MediumTest
    @XrActivityRestriction({XrActivityRestriction.SupportedActivity.CTA})
    public void testPermissionRequestDuringAr() throws TimeoutException {
        mWebXrArTestFramework.loadFileAndAwaitInitialization(
                "test_permission_request_during_ar", PAGE_LOAD_TIMEOUT_S);
        WebContents contents = mWebXrArTestFramework.getCurrentWebContents();

        // Start new session, accepting the consent prompt
        mWebXrArTestFramework.enterSessionWithUserGestureOrFail(/* needsCameraPermission= */ false);
        mWebXrArTestFramework.assertNoJavaScriptErrors();

        // Trigger a new permission prompt to show when tapping on the canvas, then tap on it.
        mWebXrArTestFramework.runJavaScriptOrFail("setupCanvasClick()", POLL_TIMEOUT_SHORT_MS);
        Assert.assertTrue(DOMUtils.clickNode(contents, "webgl-canvas"));
        PermissionUtils.waitForPermissionPrompt();

        // Now that the new permission prompt is showing, ensure that the browser controls have
        // shown themselves and that we still have an AR Session.
        ChromeModalDialogTestUtils.checkBrowserControls(mTestRule.getActivity(), true);
        Assert.assertTrue(
                Boolean.valueOf(
                        mWebXrArTestFramework.runJavaScriptOrFail(
                                "sessionInfos[sessionTypes.AR].currentSession != null",
                                POLL_TIMEOUT_SHORT_MS)));

        // Reject the permission prompt to hide it again.
        PermissionUtils.denyPermissionPrompt();
        PermissionUtils.waitForPermissionPromptDismissal();

        // Now that the new permission prompt is dismissed, ensure that the browser controls have
        // hidden themselves and that we still have an AR Session.
        ChromeModalDialogTestUtils.checkBrowserControls(mTestRule.getActivity(), false);
        Assert.assertTrue(
                Boolean.valueOf(
                        mWebXrArTestFramework.runJavaScriptOrFail(
                                "sessionInfos[sessionTypes.AR].currentSession != null",
                                POLL_TIMEOUT_SHORT_MS)));

        mWebXrArTestFramework.assertNoJavaScriptErrors();
    }
}