Commit 3ff944ee authored by bsheedy's avatar bsheedy Committed by Commit Bot

Reland "Add AR instrumentation test support"

This is a reland of a3015a89

Original change's description:
> Add AR instrumentation test support
>
> Adds the necessary changes to build and run
> AR (augmented reality) tests in Monochrome.
>
> Does not actually enable the test APK to be
> built or run anywhere - that will be added
> at a later time once additional work to
> properly run the tests on bots is done, e.g.
> installing the ArCore APK.
>
> Bug: 851020
> Cq-Include-Trybots: luci.chromium.try:android_optional_gpu_tests_rel;luci.chromium.try:linux_layout_tests_slimming_paint_v2;luci.chromium.try:linux_optional_gpu_tests_rel;luci.chromium.try:linux_vr;luci.chromium.try:mac_optional_gpu_tests_rel;luci.chromium.try:win_optional_gpu_tests_rel;master.tryserver.blink:linux_trusty_blink_rel
> Change-Id: I4148fcc6626ef79852f78f6019cc7c6f297f3e37
> Reviewed-on: https://chromium-review.googlesource.com/1101958
> Commit-Queue: Brian Sheedy <bsheedy@chromium.org>
> Reviewed-by: Yaron Friedman <yfriedman@chromium.org>
> Reviewed-by: Brandon Jones <bajones@chromium.org>
> Reviewed-by: agrieve <agrieve@chromium.org>
> Reviewed-by: Michael Thiessen <mthiesse@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#573599}

TBR=yfriedman@chromium.org,mthiesse@chromium.org,bajones@chromium.org,agrieve@chromium.org

Bug: 851020
Change-Id: If8410366848ff25d276cb2473f773c153a32f94f
Cq-Include-Trybots: luci.chromium.try:android_optional_gpu_tests_rel;luci.chromium.try:linux_layout_tests_slimming_paint_v2;luci.chromium.try:linux_optional_gpu_tests_rel;luci.chromium.try:linux_vr;luci.chromium.try:mac_optional_gpu_tests_rel;luci.chromium.try:win_optional_gpu_tests_rel;master.tryserver.blink:linux_trusty_blink_rel
Reviewed-on: https://chromium-review.googlesource.com/1131715Reviewed-by: default avatarBrian Sheedy <bsheedy@chromium.org>
Commit-Queue: Brian Sheedy <bsheedy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#573899}
parent 59b4cd57
...@@ -2807,6 +2807,8 @@ if (enable_java_templates) { ...@@ -2807,6 +2807,8 @@ if (enable_java_templates) {
# Generate incremental apk related operations at runtime. # Generate incremental apk related operations at runtime.
public_deps += _incremental_apk_operations public_deps += _incremental_apk_operations
} }
} else {
not_needed([ "_incremental_apk_operations" ])
} }
} }
...@@ -2852,13 +2854,18 @@ if (enable_java_templates) { ...@@ -2852,13 +2854,18 @@ if (enable_java_templates) {
template("instrumentation_test_apk") { template("instrumentation_test_apk") {
assert(defined(invoker.apk_name)) assert(defined(invoker.apk_name))
testonly = true testonly = true
_incremental_allowed =
!defined(invoker.never_incremental) || !invoker.never_incremental
_apk_target_name = "${target_name}__apk" _apk_target_name = "${target_name}__apk"
_test_runner_target_name = "${target_name}__test_runner_script" _test_runner_target_name = "${target_name}__test_runner_script"
_dist_ijar_path = _dist_ijar_path =
"$root_build_dir/test.lib.java/" + invoker.apk_name + ".jar" "$root_build_dir/test.lib.java/" + invoker.apk_name + ".jar"
_incremental_test_runner_target_name = if (_incremental_allowed) {
"${_test_runner_target_name}_incremental" _incremental_test_runner_target_name =
_incremental_test_name = "${invoker.target_name}_incremental" "${_test_runner_target_name}_incremental"
_incremental_test_name = "${invoker.target_name}_incremental"
}
if (incremental_apk_by_default) { if (incremental_apk_by_default) {
_incremental_test_runner_target_name = _test_runner_target_name _incremental_test_runner_target_name = _test_runner_target_name
_incremental_test_name = invoker.target_name _incremental_test_name = invoker.target_name
...@@ -2883,22 +2890,24 @@ if (enable_java_templates) { ...@@ -2883,22 +2890,24 @@ if (enable_java_templates) {
test_jar = _dist_ijar_path test_jar = _dist_ijar_path
} }
} }
test_runner_script(_incremental_test_runner_target_name) { if (_incremental_allowed) {
forward_variables_from(invoker, test_runner_script(_incremental_test_runner_target_name) {
[ forward_variables_from(invoker,
"additional_apks", [
"apk_under_test", "additional_apks",
"data", "apk_under_test",
"data_deps", "data",
"deps", "data_deps",
"ignore_all_data_deps", "deps",
"public_deps", "ignore_all_data_deps",
]) "public_deps",
test_name = _incremental_test_name ])
test_type = "instrumentation" test_name = _incremental_test_name
apk_target = ":$_apk_target_name" test_type = "instrumentation"
test_jar = _dist_ijar_path apk_target = ":$_apk_target_name"
incremental_install = true test_jar = _dist_ijar_path
incremental_install = true
}
} }
android_apk(_apk_target_name) { android_apk(_apk_target_name) {
...@@ -2981,14 +2990,16 @@ if (enable_java_templates) { ...@@ -2981,14 +2990,16 @@ if (enable_java_templates) {
} }
} }
group("${target_name}_incremental") { if (_incremental_allowed) {
public_deps = [ group("${target_name}_incremental") {
":$_incremental_test_runner_target_name", public_deps = [
":${_apk_target_name}_dist_ijar", ":$_incremental_test_runner_target_name",
":${_apk_target_name}_incremental", ":${_apk_target_name}_dist_ijar",
] ":${_apk_target_name}_incremental",
if (defined(invoker.apk_under_test)) { ]
public_deps += [ "${invoker.apk_under_test}_incremental" ] if (defined(invoker.apk_under_test)) {
public_deps += [ "${invoker.apk_under_test}_incremental" ]
}
} }
} }
} }
......
...@@ -682,19 +682,45 @@ android_library("chrome_test_java") { ...@@ -682,19 +682,45 @@ android_library("chrome_test_java") {
] ]
} }
if (enable_vr) { if (enable_vr || (enable_arcore && package_arcore)) {
android_library("chrome_test_vr_java") { # Desugaring doesn't seem to play nice with deps when there are multiple
# layers of android_library. If A is included in B's deps, and B is included
# in C's deps, desugar can fail to find classes from A. As a workaround,
# have each android_library have duplicate entries in their deps lists.
# See https://crbug.com/860018.
chrome_test_xr_java_deps = [
"//base:base_java",
"//base:base_java_test_support",
"//chrome/android:app_hooks_java",
"//chrome/android:chrome_java",
"//chrome/android:class_register_java",
"//chrome/test/android:chrome_java_test_support",
"//components/policy/android:policy_java",
"//content/public/android:content_java",
"//content/public/test/android:content_java_test_support",
"//net/android:net_java_test_support",
"//third_party/android_protobuf:protobuf_nano_javalib",
"//third_party/android_support_test_runner:rules_java",
"//third_party/android_support_test_runner:runner_java",
"//third_party/android_tools:android_arch_lifecycle_common_java",
"//third_party/android_tools:android_support_annotations_java",
"//third_party/android_tools:android_support_v7_appcompat_java",
"//third_party/android_tools:android_support_v7_recyclerview_java",
"//third_party/custom_tabs_client:custom_tabs_support_java",
"//third_party/junit",
"//third_party/ub-uiautomator:ub_uiautomator_java",
"//ui/android:ui_java",
]
# Files used for both VR and AR testing
android_library("chrome_test_xr_java") {
testonly = true testonly = true
java_files = [ java_files = [
"javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTestRule.java", "javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTestRule.java",
"javatests/src/org/chromium/chrome/browser/customtabs/CustomTabsTestUtils.java", "javatests/src/org/chromium/chrome/browser/customtabs/CustomTabsTestUtils.java",
"javatests/src/org/chromium/chrome/browser/media/RouterTestUtils.java", "javatests/src/org/chromium/chrome/browser/media/RouterTestUtils.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/EmulatedVrController.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/mock/MockBrowserKeyboardInterface.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/mock/MockVrCoreVersionCheckerImpl.java", "javatests/src/org/chromium/chrome/browser/vr_shell/mock/MockVrCoreVersionCheckerImpl.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/mock/MockVrDaydreamApi.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/nfc_apk/SimNfcActivity.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/rules/ChromeTabbedActivityVrTestRule.java", "javatests/src/org/chromium/chrome/browser/vr_shell/rules/ChromeTabbedActivityVrTestRule.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/rules/CustomTabActivityVrTestRule.java", "javatests/src/org/chromium/chrome/browser/vr_shell/rules/CustomTabActivityVrTestRule.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/rules/HeadTrackingMode.java", "javatests/src/org/chromium/chrome/browser/vr_shell/rules/HeadTrackingMode.java",
...@@ -703,68 +729,79 @@ if (enable_vr) { ...@@ -703,68 +729,79 @@ if (enable_vr) {
"javatests/src/org/chromium/chrome/browser/vr_shell/rules/VrTestRule.java", "javatests/src/org/chromium/chrome/browser/vr_shell/rules/VrTestRule.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/rules/WebappActivityVrTestRule.java", "javatests/src/org/chromium/chrome/browser/vr_shell/rules/WebappActivityVrTestRule.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/util/HeadTrackingUtils.java", "javatests/src/org/chromium/chrome/browser/vr_shell/util/HeadTrackingUtils.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/util/NativeUiUtils.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/util/NfcSimUtils.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/util/TransitionUtils.java", "javatests/src/org/chromium/chrome/browser/vr_shell/util/TransitionUtils.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/util/VrInfoBarUtils.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/util/VrShellDelegateUtils.java", "javatests/src/org/chromium/chrome/browser/vr_shell/util/VrShellDelegateUtils.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/util/VrTestRuleUtils.java", "javatests/src/org/chromium/chrome/browser/vr_shell/util/VrTestRuleUtils.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/util/VrTransitionUtils.java", "javatests/src/org/chromium/chrome/browser/vr_shell/util/VrTransitionUtils.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/util/XrTransitionUtils.java", "javatests/src/org/chromium/chrome/browser/vr_shell/util/XrTransitionUtils.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/TestFramework.java", "javatests/src/org/chromium/chrome/browser/vr_shell/TestFramework.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/TestVrShellDelegate.java", "javatests/src/org/chromium/chrome/browser/vr_shell/TestVrShellDelegate.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/VrFeedbackInfoBarTest.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/VrInstallUpdateInfoBarTest.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/VrShellCompositorViewHolderTest.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/VrShellControllerInputTest.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/VrShellDialogTest.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/VrShellNativeUiTest.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/VrShellNavigationTest.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/VrShellTransitionTest.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/VrShellWebInputEditingTest.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/VrTestFramework.java", "javatests/src/org/chromium/chrome/browser/vr_shell/VrTestFramework.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/WebVrDeviceTest.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/WebVrInputTest.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/WebVrTabTest.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/WebVrTransitionTest.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/XrTestFramework.java", "javatests/src/org/chromium/chrome/browser/vr_shell/XrTestFramework.java",
"javatests/src/org/chromium/chrome/browser/webapps/TestFetchStorageCallback.java", "javatests/src/org/chromium/chrome/browser/webapps/TestFetchStorageCallback.java",
"javatests/src/org/chromium/chrome/browser/webapps/WebappActivityTestRule.java", "javatests/src/org/chromium/chrome/browser/webapps/WebappActivityTestRule.java",
] ]
deps = [ deps = chrome_test_xr_java_deps
"//base:base_java",
"//base:base_java_test_support",
"//chrome/android:app_hooks_java",
"//chrome/android:chrome_java",
"//chrome/android:class_register_java",
"//chrome/test/android:chrome_java_test_support",
"//components/policy/android:policy_java",
"//content/public/android:content_java",
"//content/public/test/android:content_java_test_support",
"//net/android:net_java_test_support",
"//third_party/android_protobuf:protobuf_nano_javalib",
"//third_party/android_support_test_runner:rules_java",
"//third_party/android_support_test_runner:runner_java",
"//third_party/android_tools:android_arch_lifecycle_common_java",
"//third_party/android_tools:android_support_annotations_java",
"//third_party/android_tools:android_support_v7_appcompat_java",
"//third_party/android_tools:android_support_v7_recyclerview_java",
"//third_party/custom_tabs_client:custom_tabs_support_java",
"//third_party/gvr-android-sdk:controller_test_api_java",
"//third_party/gvr-android-sdk:gvr_common_java",
"//third_party/junit",
"//third_party/ub-uiautomator:ub_uiautomator_java",
"//ui/android:ui_java",
]
data = [ data = [
"//chrome/android/shared_preference_files/test/",
"//chrome/test/data/vr/e2e_test_files/", "//chrome/test/data/vr/e2e_test_files/",
"//third_party/gvr-android-sdk/test-apks/",
"//third_party/WebKit/LayoutTests/resources/testharness.js", "//third_party/WebKit/LayoutTests/resources/testharness.js",
] ]
} }
if (enable_vr) {
# All files necessary for VR instrumentation tests
android_library("chrome_test_vr_java") {
testonly = true
java_files = [
"javatests/src/org/chromium/chrome/browser/vr_shell/EmulatedVrController.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/mock/MockBrowserKeyboardInterface.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/mock/MockVrDaydreamApi.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/nfc_apk/SimNfcActivity.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/util/NativeUiUtils.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/util/NfcSimUtils.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/util/VrInfoBarUtils.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/VrFeedbackInfoBarTest.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/VrInstallUpdateInfoBarTest.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/VrShellCompositorViewHolderTest.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/VrShellControllerInputTest.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/VrShellDialogTest.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/VrShellNativeUiTest.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/VrShellNavigationTest.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/VrShellTransitionTest.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/VrShellWebInputEditingTest.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/WebVrDeviceTest.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/WebVrInputTest.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/WebVrTabTest.java",
"javatests/src/org/chromium/chrome/browser/vr_shell/WebVrTransitionTest.java",
]
deps = chrome_test_xr_java_deps + [
"//chrome/android:chrome_test_xr_java",
"//third_party/gvr-android-sdk:controller_test_api_java",
"//third_party/gvr-android-sdk:gvr_common_java",
]
data = [
"//chrome/android/shared_preference_files/test/",
"//third_party/gvr-android-sdk/test-apks/",
]
}
}
if (enable_arcore && package_arcore) {
# All files necessary for AR instrumentation tests
android_library("chrome_test_ar_java") {
testonly = true
java_files = [ "javatests/src/org/chromium/chrome/browser/vr_shell/WebXrArSessionTest.java" ]
deps =
chrome_test_xr_java_deps + [ "//chrome/android:chrome_test_xr_java" ]
}
}
} }
# Overrides icon / name defined in chrome_java_resources. # Overrides icon / name defined in chrome_java_resources.
...@@ -1290,6 +1327,8 @@ chrome_public_test_vr_apk_manifest = ...@@ -1290,6 +1327,8 @@ chrome_public_test_vr_apk_manifest =
"$root_gen_dir/chrome_public_test_vr_apk_manifest/AndroidManifest.xml" "$root_gen_dir/chrome_public_test_vr_apk_manifest/AndroidManifest.xml"
chrome_sync_shell_test_apk_manifest = chrome_sync_shell_test_apk_manifest =
"$root_gen_dir/chrome_sync_shell_test_apk_manifest/AndroidManifest.xml" "$root_gen_dir/chrome_sync_shell_test_apk_manifest/AndroidManifest.xml"
monochrome_public_test_ar_apk_manifest =
"$root_gen_dir/monochrome_public_test_ar_apk_manifest/AndroidManifest.xml"
vr_nfc_simulator_apk_manifest = vr_nfc_simulator_apk_manifest =
"$root_gen_dir/vr_nfc_simulator_apk_manifest/AndroidManifest.xml" "$root_gen_dir/vr_nfc_simulator_apk_manifest/AndroidManifest.xml"
...@@ -1297,12 +1336,28 @@ jinja_template("chrome_public_test_apk_manifest") { ...@@ -1297,12 +1336,28 @@ jinja_template("chrome_public_test_apk_manifest") {
input = "javatests/AndroidManifest.xml" input = "javatests/AndroidManifest.xml"
output = chrome_public_test_apk_manifest output = chrome_public_test_apk_manifest
variables = chrome_public_jinja_variables variables = chrome_public_jinja_variables
variables += [
"min_sdk_version=16",
"target_sdk_version=$android_sdk_version",
]
} }
jinja_template("chrome_public_test_vr_apk_manifest") { jinja_template("chrome_public_test_vr_apk_manifest") {
input = "javatests/AndroidManifest.xml" input = "javatests/AndroidManifest.xml"
output = chrome_public_test_vr_apk_manifest output = chrome_public_test_vr_apk_manifest
variables = chrome_public_jinja_variables variables = chrome_public_jinja_variables
variables += [
"min_sdk_version=16",
"target_sdk_version=$android_sdk_version",
]
}
jinja_template("monochrome_public_test_ar_apk_manifest") {
input = "javatests/AndroidManifest_monochrome.xml"
output = monochrome_public_test_ar_apk_manifest
variables = chrome_public_jinja_variables +
monochrome_android_manifest_jinja_variables +
[ "target_sdk_version=$android_sdk_version" ]
} }
jinja_template("vr_nfc_simulator_apk_manifest") { jinja_template("vr_nfc_simulator_apk_manifest") {
...@@ -1385,6 +1440,35 @@ if (enable_vr) { ...@@ -1385,6 +1440,35 @@ if (enable_vr) {
} }
} }
if (enable_arcore && package_arcore) {
instrumentation_test_apk("monochrome_public_test_ar_apk") {
apk_name = "MonochromePublicTestAr"
apk_under_test = ":monochrome_public_apk"
android_manifest = monochrome_public_test_ar_apk_manifest
android_manifest_dep = ":monochrome_public_test_ar_apk_manifest"
deps = [
":chrome_test_ar_java",
"//third_party/android_tools:android_test_mock_java",
]
additional_apks = [ "//net/android:net_test_support_apk" ]
proguard_enabled = !is_java_debug
if (proguard_enabled && !enable_proguard_obfuscation) {
proguard_configs = [ "//base/android/proguard/enable_obfuscation.flags" ]
proguard_config_exclusions =
[ "//base/android/proguard/disable_chromium_obfuscation.flags" ]
}
alternative_android_sdk_dep = webview_framework_dep
# The test APK contains code from both the APK under test and the
# test APK when proguard is enabled. That causes this APK to exceed
# the dex limit.
enable_multidex = proguard_enabled
never_incremental = true
}
}
instrumentation_test_apk("chrome_sync_shell_test_apk") { instrumentation_test_apk("chrome_sync_shell_test_apk") {
apk_name = "ChromeSyncShellTest" apk_name = "ChromeSyncShellTest"
apk_under_test = ":chrome_sync_shell_apk" apk_under_test = ":chrome_sync_shell_apk"
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.chromium.chrome.tests"> package="org.chromium.chrome.tests">
<uses-sdk android:minSdkVersion="16" android:targetSdkVersion="23" /> <uses-sdk android:minSdkVersion="{{min_sdk_version}}" android:targetSdkVersion="{{target_sdk_version}}" />
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" />
<uses-permission android:name="android.permission.READ_LOGS"/> <uses-permission android:name="android.permission.READ_LOGS"/>
<uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.WAKE_LOCK" />
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<application <application
android:label="ChromePublicTest"> android:label="{% block application_name %}ChromePublicTest{% endblock %}">
<uses-library android:name="android.test.runner" /> <uses-library android:name="android.test.runner" />
......
{% extends "chrome/android/javatests/AndroidManifest.xml" %}
## Copyright 2018 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.
## Note: This is a jinja2 template, processed at build time into the final manifest.
##
{% block application_name %}MonochromePublicTest{% endblock %}
\ No newline at end of file
...@@ -178,6 +178,7 @@ public class CastTestRule extends ChromeActivityTestRule<ChromeActivity> { ...@@ -178,6 +178,7 @@ public class CastTestRule extends ChromeActivityTestRule<ChromeActivity> {
return waitForStates(states, waitTimeMs); return waitForStates(states, waitTimeMs);
} }
@Override
public EmbeddedTestServer getTestServer() { public EmbeddedTestServer getTestServer() {
return mTestServer; return mTestServer;
} }
......
...@@ -61,6 +61,7 @@ public class NotificationTestRule extends ChromeActivityTestRule<ChromeTabbedAct ...@@ -61,6 +61,7 @@ public class NotificationTestRule extends ChromeActivityTestRule<ChromeTabbedAct
} }
/** Returns the test server. */ /** Returns the test server. */
@Override
public EmbeddedTestServer getTestServer() { public EmbeddedTestServer getTestServer() {
return mTestServer; return mTestServer;
} }
......
...@@ -209,6 +209,18 @@ public class TestFramework { ...@@ -209,6 +209,18 @@ public class TestFramework {
} }
} }
/**
* Helper function to make sure that the JavaScript test harness did not detect any failures.
* Similar to endTest, but does not fail if the test is still detected as running. This is
* useful because not all tests make use of the test harness' test/assert features (particularly
* simple enter/exit tests), but may still want to ensure that no unexpected JavaScript errors
* were encountered.
* @param webContents The Webcontents for the tab to check for failures in.
*/
public static void assertNoJavaScriptErrors(WebContents webContents) {
Assert.assertNotEquals(checkTestStatus(webContents), STATUS_FAILED);
}
/** /**
* Polls the provided JavaScript boolean until the timeout is reached or * Polls the provided JavaScript boolean until the timeout is reached or
* the boolean is true. * the boolean is true.
......
// Copyright 2018 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.vr_shell;
import static org.chromium.chrome.browser.vr_shell.TestFramework.PAGE_LOAD_TIMEOUT_S;
import static org.chromium.chrome.browser.vr_shell.XrTestFramework.POLL_TIMEOUT_LONG_MS;
import android.os.Build;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.MediumTest;
import org.junit.After;
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.base.test.util.MinAndroidSdkLevel;
import org.chromium.chrome.browser.ChromeSwitches;
import org.chromium.chrome.browser.vr_shell.rules.VrActivityRestriction;
import org.chromium.chrome.browser.vr_shell.util.VrTestRuleUtils;
import org.chromium.chrome.browser.vr_shell.util.XrTransitionUtils;
import org.chromium.chrome.test.ChromeActivityTestRule;
import org.chromium.chrome.test.ChromeJUnit4RunnerDelegate;
import org.chromium.net.test.EmbeddedTestServer;
import java.util.List;
import java.util.concurrent.Callable;
/**
* 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,WebXRHitTest"})
@MinAndroidSdkLevel(Build.VERSION_CODES.N) // WebXR for AR is only supported on N+
public class WebXrArSessionTest {
@ClassParameter
private static List<ParameterSet> sClassParams =
VrTestRuleUtils.generateDefaultVrTestRuleParameters();
@Rule
public RuleChain mRuleChain;
private ChromeActivityTestRule mTestRule;
private XrTestFramework mXrTestFramework;
private EmbeddedTestServer mServer;
private boolean mShouldCreateServer;
public WebXrArSessionTest(Callable<ChromeActivityTestRule> callable) throws Exception {
mTestRule = callable.call();
mRuleChain = VrTestRuleUtils.wrapRuleInVrActivityRestrictionRule(mTestRule);
}
@Before
public void setUp() throws Exception {
mXrTestFramework = new XrTestFramework(mTestRule);
// WebappActivityTestRule automatically creates a test server, and creating multiple causes
// it to crash hitting a DCHECK. So, only handle the server ourselves if whatever test rule
// we're using doesn't create one itself.
mServer = mTestRule.getTestServer();
if (mServer == null) {
mShouldCreateServer = true;
mServer = EmbeddedTestServer.createAndStartServer(InstrumentationRegistry.getContext());
}
}
@After
public void tearDown() throws Exception {
if (mServer != null && mShouldCreateServer) {
mServer.stopAndDestroyServer();
}
}
/**
* Tests that a session request for AR succeeds.
*/
@Test
@MediumTest
@VrActivityRestriction({VrActivityRestriction.SupportedActivity.ALL})
public void testArRequestSessionSucceeds() throws InterruptedException {
mXrTestFramework.loadUrlAndAwaitInitialization(
mServer.getURL(XrTestFramework.getEmbeddedServerPathForHtmlTestFile(
"test_ar_request_session_succeeds")),
PAGE_LOAD_TIMEOUT_S);
XrTransitionUtils.enterArSessionOrFail(mXrTestFramework.getFirstTabWebContents());
XrTestFramework.assertNoJavaScriptErrors(mXrTestFramework.getFirstTabWebContents());
}
/**
* Tests that repeatedly starting and stopping AR sessions does not cause any unexpected
* behavior. Regression test for https://crbug.com/837894.
*/
@Test
@MediumTest
@VrActivityRestriction({VrActivityRestriction.SupportedActivity.ALL})
public void testRepeatedArSessionsSucceed() throws InterruptedException {
mXrTestFramework.loadUrlAndAwaitInitialization(
mServer.getURL(XrTestFramework.getEmbeddedServerPathForHtmlTestFile(
"test_ar_request_session_succeeds")),
PAGE_LOAD_TIMEOUT_S);
for (int i = 0; i < 2; i++) {
XrTransitionUtils.enterArSessionOrFail(mXrTestFramework.getFirstTabWebContents());
XrTransitionUtils.endArSession(mXrTestFramework.getFirstTabWebContents());
}
XrTestFramework.assertNoJavaScriptErrors(mXrTestFramework.getFirstTabWebContents());
}
/**
* Tests that repeated calls to requestSession on the same page only prompts the user for
* camera permissions once.
*/
@Test
@MediumTest
@VrActivityRestriction({VrActivityRestriction.SupportedActivity.ALL})
public void testRepeatedArSessionsOnlyPromptPermissionsOnce() throws InterruptedException {
mXrTestFramework.loadUrlAndAwaitInitialization(
mServer.getURL(XrTestFramework.getEmbeddedServerPathForHtmlTestFile(
"test_ar_request_session_succeeds")),
PAGE_LOAD_TIMEOUT_S);
Assert.assertTrue(XrTransitionUtils.arSessionRequestWouldTriggerPermissionPrompt(
mXrTestFramework.getFirstTabWebContents()));
XrTransitionUtils.enterArSessionOrFail(mXrTestFramework.getFirstTabWebContents());
XrTransitionUtils.endArSession(mXrTestFramework.getFirstTabWebContents());
// Manually run through the same steps as enterArSessionOrFail so that we don't trigger
// its automatic permission acceptance.
Assert.assertFalse(XrTransitionUtils.arSessionRequestWouldTriggerPermissionPrompt(
mXrTestFramework.getFirstTabWebContents()));
XrTransitionUtils.enterPresentation(mXrTestFramework.getFirstTabWebContents());
Assert.assertTrue(XrTestFramework.pollJavaScriptBoolean(
"sessionInfos[sessionTypes.AR].currentSession != null", POLL_TIMEOUT_LONG_MS,
mXrTestFramework.getFirstTabWebContents()));
}
}
\ No newline at end of file
...@@ -121,7 +121,6 @@ public class TransitionUtils { ...@@ -121,7 +121,6 @@ public class TransitionUtils {
* JavaScript step to finish. * JavaScript step to finish.
* *
* Only meant to be used alongside the test framework from VrTestFramework. * Only meant to be used alongside the test framework from VrTestFramework.
* @param cvc The ContentViewCore for the tab the canvas is in.
* @param webContents The WebContents for the tab the JavaScript step is in. * @param webContents The WebContents for the tab the JavaScript step is in.
*/ */
public static void enterPresentationAndWait(WebContents webContents) { public static void enterPresentationAndWait(WebContents webContents) {
......
...@@ -5,20 +5,23 @@ ...@@ -5,20 +5,23 @@
package org.chromium.chrome.browser.vr_shell.util; package org.chromium.chrome.browser.vr_shell.util;
import static org.chromium.chrome.browser.vr_shell.XrTestFramework.POLL_TIMEOUT_LONG_MS; import static org.chromium.chrome.browser.vr_shell.XrTestFramework.POLL_TIMEOUT_LONG_MS;
import static org.chromium.chrome.browser.vr_shell.XrTestFramework.POLL_TIMEOUT_SHORT_MS;
import android.content.DialogInterface;
import org.junit.Assert; import org.junit.Assert;
import org.chromium.base.ThreadUtils;
import org.chromium.chrome.browser.permissions.PermissionDialogController;
import org.chromium.chrome.browser.vr_shell.TestVrShellDelegate; import org.chromium.chrome.browser.vr_shell.TestVrShellDelegate;
import org.chromium.chrome.browser.vr_shell.XrTestFramework; import org.chromium.chrome.browser.vr_shell.XrTestFramework;
import org.chromium.content.browser.test.util.Criteria;
import org.chromium.content.browser.test.util.CriteriaHelper;
import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.WebContents;
/** /**
* Class containing utility functions for transitioning between different * Class containing utility functions for transitioning between different
* states in VR, such as fullscreen, WebVR presentation, and the VR browser. * states in WebXR, e.g. entering exclusive or AR sessions.
*
* All the transitions in this class are performed directly through Chrome,
* as opposed to NFC tag simulation which involves receiving an intent from
* an outside application (VR Services).
*/ */
public class XrTransitionUtils extends TransitionUtils { public class XrTransitionUtils extends TransitionUtils {
/** /**
...@@ -26,9 +29,72 @@ public class XrTransitionUtils extends TransitionUtils { ...@@ -26,9 +29,72 @@ public class XrTransitionUtils extends TransitionUtils {
* the two APIs. * the two APIs.
*/ */
public static void enterPresentationOrFail(WebContents webContents) { public static void enterPresentationOrFail(WebContents webContents) {
XrTestFramework.runJavaScriptOrFail(
"sessionTypeToRequest = sessionTypes.EXCLUSIVE", POLL_TIMEOUT_LONG_MS, webContents);
enterPresentation(webContents); enterPresentation(webContents);
Assert.assertTrue(XrTestFramework.pollJavaScriptBoolean( Assert.assertTrue(XrTestFramework.pollJavaScriptBoolean(
"exclusiveSession != null", POLL_TIMEOUT_LONG_MS, webContents)); "sessionInfos[sessionTypes.EXCLUSIVE].currentSession != null", POLL_TIMEOUT_LONG_MS,
webContents));
Assert.assertTrue(TestVrShellDelegate.getVrShellForTesting().getWebVrModeEnabled()); Assert.assertTrue(TestVrShellDelegate.getVrShellForTesting().getWebVrModeEnabled());
} }
/**
* Requests that WebXR start an AR session, failing the test if it does not succeed.
* @param webContents The WebContents to run start the AR session in.
*/
public static void enterArSessionOrFail(WebContents webContents) {
XrTestFramework.runJavaScriptOrFail(
"sessionTypeToRequest = sessionTypes.AR", POLL_TIMEOUT_LONG_MS, webContents);
// Requesting an AR session for the first time on a page will always prompt for camera
// permissions, but not on subsequent requests, so check to see if we'll need to accept it
// after requesting the session.
boolean expectPermissionPrompt = arSessionRequestWouldTriggerPermissionPrompt(webContents);
// TODO(bsheedy): Rename enterPresentation since it's used for both presentation and AR?
enterPresentation(webContents);
if (expectPermissionPrompt) {
// Wait for the permission prompt to appear.
CriteriaHelper.pollUiThread(new Criteria() {
@Override
public boolean isSatisfied() {
return PermissionDialogController.getInstance().getCurrentDialogForTesting()
!= null;
}
});
// Accept the permission prompt.
ThreadUtils.runOnUiThreadBlocking(() -> {
PermissionDialogController.getInstance()
.getCurrentDialogForTesting()
.getButton(DialogInterface.BUTTON_POSITIVE)
.performClick();
});
}
Assert.assertTrue(XrTestFramework.pollJavaScriptBoolean(
"sessionInfos[sessionTypes.AR].currentSession != null", POLL_TIMEOUT_LONG_MS,
webContents));
}
/**
* Ends the current AR session.
* @param webContents The WebContents to end the AR session in.
*/
public static void endArSession(WebContents webContents) {
XrTestFramework.runJavaScriptOrFail("sessionInfos[sessionTypes.AR].currentSession.end()",
POLL_TIMEOUT_SHORT_MS, webContents);
}
/**
* Checks whether an AR session request would trigger a Camera permission prompt.
* @param webContents The WebContents to check permissions in.
* @return True if an AR session request will cause a permission prompt, false otherwise.
*/
public static boolean arSessionRequestWouldTriggerPermissionPrompt(WebContents webContents) {
XrTestFramework.runJavaScriptOrFail("checkIfArSessionWouldTriggerPermissionPrompt()",
POLL_TIMEOUT_SHORT_MS, webContents);
Assert.assertTrue(XrTestFramework.pollJavaScriptBoolean(
"arSessionRequestWouldTriggerPermissionPrompt !== null", POLL_TIMEOUT_SHORT_MS,
webContents));
return Boolean.valueOf(
XrTestFramework.runJavaScriptOrFail("arSessionRequestWouldTriggerPermissionPrompt",
POLL_TIMEOUT_SHORT_MS, webContents));
}
} }
...@@ -80,6 +80,7 @@ public class WebappActivityTestRule extends ChromeActivityTestRule<WebappActivit ...@@ -80,6 +80,7 @@ public class WebappActivityTestRule extends ChromeActivityTestRule<WebappActivit
super(WebappActivity0.class); super(WebappActivity0.class);
} }
@Override
public EmbeddedTestServer getTestServer() { public EmbeddedTestServer getTestServer() {
return mTestServerRule.getServer(); return mTestServerRule.getServer();
} }
......
...@@ -24,19 +24,23 @@ void XrBrowserTestBase::EnterPresentation(content::WebContents* web_contents) { ...@@ -24,19 +24,23 @@ void XrBrowserTestBase::EnterPresentation(content::WebContents* web_contents) {
void XrBrowserTestBase::EnterPresentationOrFail( void XrBrowserTestBase::EnterPresentationOrFail(
content::WebContents* web_contents) { content::WebContents* web_contents) {
EnterPresentation(web_contents); EnterPresentation(web_contents);
EXPECT_TRUE(PollJavaScriptBoolean("exclusiveSession!= null", kPollTimeoutLong, EXPECT_TRUE(PollJavaScriptBoolean(
web_contents)); "sessionInfos[sessionTypes.EXCLUSIVE].currentSession != null",
kPollTimeoutLong, web_contents));
} }
void XrBrowserTestBase::ExitPresentation(content::WebContents* web_contents) { void XrBrowserTestBase::ExitPresentation(content::WebContents* web_contents) {
EXPECT_TRUE(content::ExecuteScript(web_contents, "exclusiveSession.end()")); EXPECT_TRUE(content::ExecuteScript(
web_contents,
"sessionInfos[sessionTypes.EXCLUSIVE].currentSession.end()"));
} }
void XrBrowserTestBase::ExitPresentationOrFail( void XrBrowserTestBase::ExitPresentationOrFail(
content::WebContents* web_contents) { content::WebContents* web_contents) {
ExitPresentation(web_contents); ExitPresentation(web_contents);
EXPECT_TRUE(PollJavaScriptBoolean("exclusiveSession == null", EXPECT_TRUE(PollJavaScriptBoolean(
kPollTimeoutLong, web_contents)); "sessionInfos[sessionTypes.EXCLUSIVE].currentSession == null",
kPollTimeoutLong, web_contents));
} }
} // namespace vr } // namespace vr
...@@ -56,6 +56,7 @@ import org.chromium.content.browser.test.util.JavaScriptUtils; ...@@ -56,6 +56,7 @@ import org.chromium.content.browser.test.util.JavaScriptUtils;
import org.chromium.content.browser.test.util.RenderProcessLimit; import org.chromium.content.browser.test.util.RenderProcessLimit;
import org.chromium.content_public.browser.LoadUrlParams; import org.chromium.content_public.browser.LoadUrlParams;
import org.chromium.content_public.browser.WebContents; import org.chromium.content_public.browser.WebContents;
import org.chromium.net.test.EmbeddedTestServer;
import org.chromium.ui.base.PageTransition; import org.chromium.ui.base.PageTransition;
import java.lang.reflect.AnnotatedElement; import java.lang.reflect.AnnotatedElement;
...@@ -621,6 +622,13 @@ public class ChromeActivityTestRule<T extends ChromeActivity> extends ActivityTe ...@@ -621,6 +622,13 @@ public class ChromeActivityTestRule<T extends ChromeActivity> extends ActivityTe
return mCurrentTestName; return mCurrentTestName;
} }
/**
* Gets the ChromeActivityTestRule's EmbeddedTestServer instance if it has one.
*/
public EmbeddedTestServer getTestServer() {
return null;
}
/** /**
* @return {@link WebContents} of the active tab of the activity. * @return {@link WebContents} of the active tab of the activity.
*/ */
......
<!doctype html>
<!--
Tests that AR requestSessions succeed.
-->
<html>
<head>
<link rel="stylesheet" type="text/css" href="../resources/webxr_e2e.css">
</head>
<body>
<canvas id="webgl-canvas"></canvas>
<script src="../../../../../../third_party/WebKit/LayoutTests/resources/testharness.js"></script>
<script src="../resources/webxr_e2e.js"></script>
<script>var shouldAutoCreateNonExclusiveSession = false;</script>
<script src="../resources/webxr_boilerplate.js"></script>
</body>
</html>
...@@ -21,7 +21,7 @@ is active, but resumes afterwards. ...@@ -21,7 +21,7 @@ is active, but resumes afterwards.
// Verify that we call a rAF once, then make sure any subsequent calls // Verify that we call a rAF once, then make sure any subsequent calls
// are not done while there is an exclusive session. // are not done while there is an exclusive session.
onMagicWindowXRFrameCallback = function() { onMagicWindowXRFrameCallback = function() {
if (exclusiveSession !== null) { if (sessionInfos[sessionTypes.EXCLUSIVE].currentSession !== null) {
t.step( () => { t.step( () => {
assert_unreached( assert_unreached(
"Non-exclusive rAF called during exclusive session"); "Non-exclusive rAF called during exclusive session");
......
...@@ -62,9 +62,10 @@ that Daydream controller input is registered when using Daydream View. ...@@ -62,9 +62,10 @@ that Daydream controller input is registered when using Daydream View.
function stepSetupListeners(numIterations) { function stepSetupListeners(numIterations) {
iterations = numIterations; iterations = numIterations;
exclusiveSession.addEventListener('selectstart', onSelectStart, false); let currentSession = sessionInfos[sessionTypes.EXCLUSIVE].currentSession;
exclusiveSession.addEventListener('selectend', onSelectEnd, false); currentSession.addEventListener('selectstart', onSelectStart, false);
exclusiveSession.addEventListener('select', onSelect, false); currentSession.addEventListener('selectend', onSelectEnd, false);
currentSession.addEventListener('select', onSelect, false);
} }
</script> </script>
</body> </body>
......
...@@ -18,6 +18,9 @@ test can query for whether each submitted frame used the correct pose. ...@@ -18,6 +18,9 @@ test can query for whether each submitted frame used the correct pose.
var t = async_test("Pose data is correct"); var t = async_test("Pose data is correct");
var frame_id = 0; var frame_id = 0;
var frame_data_array = {}; var frame_data_array = {};
// We exit presentation before checking stuff that needs the frame of
// reference, so we need to cache its value.
var cached_frame_of_ref = null;
function FloatCompare(a, b) { function FloatCompare(a, b) {
return Math.abs(a-b) < 0.001; return Math.abs(a-b) < 0.001;
...@@ -40,13 +43,13 @@ test can query for whether each submitted frame used the correct pose. ...@@ -40,13 +43,13 @@ test can query for whether each submitted frame used the correct pose.
function checkFrameView(frame_id, eye, expected) { function checkFrameView(frame_id, eye, expected) {
let frame_data = frame_data_array[frame_id]; let frame_data = frame_data_array[frame_id];
let pose = frame_data.getDevicePose(exclusiveFrameOfRef); let pose = frame_data.getDevicePose(cached_frame_of_ref);
return MatrixCompare(pose.getViewMatrix(frame_data_array[frame_id].views[eye]), expected); return MatrixCompare(pose.getViewMatrix(frame_data_array[frame_id].views[eye]), expected);
} }
function checkFramePose(frame_id, expected) { function checkFramePose(frame_id, expected) {
let frame_data = frame_data_array[frame_id]; let frame_data = frame_data_array[frame_id];
let pose = frame_data.getDevicePose(exclusiveFrameOfRef); let pose = frame_data.getDevicePose(cached_frame_of_ref);
if (!pose) { if (!pose) {
// We can intermittently get null poses. For now treat them as passing, // We can intermittently get null poses. For now treat them as passing,
// even though this should be fixed. // even though this should be fixed.
...@@ -63,6 +66,7 @@ test can query for whether each submitted frame used the correct pose. ...@@ -63,6 +66,7 @@ test can query for whether each submitted frame used the correct pose.
// Encode an index into the clear color. // Encode an index into the clear color.
frame_id++; frame_id++;
frame_data_array[frame_id] = frame; frame_data_array[frame_id] = frame;
cached_frame_of_ref = sessionInfos[sessionTypes.EXCLUSIVE].currentFrameOfRef;
var encoded_frame_id = {}; var encoded_frame_id = {};
encoded_frame_id.r = frame_id % 256; encoded_frame_id.r = frame_id % 256;
......
...@@ -27,7 +27,7 @@ Tests that WebXR doesn't update frame data when the tab is not focused ...@@ -27,7 +27,7 @@ Tests that WebXR doesn't update frame data when the tab is not focused
return; return;
} }
onMagicWindowXRFrameCallback = null; onMagicWindowXRFrameCallback = null;
pose = frame.getDevicePose(magicWindowFrameOfRef); pose = frame.getDevicePose(sessionInfos[sessionTypes.MAGIC_WINDOW].currentFrameOfRef);
t.step( () => { t.step( () => {
assert_true(pose != null, assert_true(pose != null,
"getDevicePose returned a non-null object"); "getDevicePose returned a non-null object");
......
...@@ -22,17 +22,81 @@ var onMagicWindowXRFrameCallback = null; ...@@ -22,17 +22,81 @@ var onMagicWindowXRFrameCallback = null;
var onExclusiveXRFrameCallback = null; var onExclusiveXRFrameCallback = null;
var shouldSubmitFrame = true; var shouldSubmitFrame = true;
var hasPresentedFrame = false; var hasPresentedFrame = false;
var arSessionRequestWouldTriggerPermissionPrompt = null;
var magicWindowSession = null; var sessionTypes = Object.freeze({
var magicWindowFrameOfRef = null; EXCLUSIVE: 1,
var exclusiveSession = null; AR: 2,
var exclusiveFrameOfRef = null; MAGIC_WINDOW: 3
});
var sessionTypeToRequest = sessionTypes.EXCLUSIVE;
class SessionInfo {
constructor() {
this.session = null;
this.frameOfRef = null;
}
get currentSession() {
return this.session;
}
get currentFrameOfRef() {
return this.frameOfRef;
}
set currentSession(session) {
this.session = session;
}
set currentFrameOfRef(frameOfRef) {
this.frameOfRef = frameOfRef;
}
clearSession() {
this.session = null;
this.frameOfRef = null;
}
}
var sessionInfos = {}
sessionInfos[sessionTypes.EXCLUSIVE] = new SessionInfo();
sessionInfos[sessionTypes.AR] = new SessionInfo();
sessionInfos[sessionTypes.MAGIC_WINDOW] = new SessionInfo();
function getSessionType(session) {
if (session.exclusive) {
return sessionTypes.EXCLUSIVE;
} else if (sessionInfos[sessionTypes.AR].currentSession == session) {
// TODO(bsheedy): Replace this check if there's ever something like
// session.ar for checking if the session is AR-capable.
return sessionTypes.AR;
} else {
return sessionTypes.MAGIC_WINDOW;
}
}
function onRequestSession() { function onRequestSession() {
xrDevice.requestSession({exclusive: true}).then( (session) => { switch (sessionTypeToRequest) {
exclusiveSession = session; case sessionTypes.EXCLUSIVE:
onSessionStarted(session); xrDevice.requestSession({exclusive: true}).then( (session) => {
}); sessionInfos[sessionTypes.EXCLUSIVE].currentSession = session;
onSessionStarted(session);
});
break;
case sessionTypes.AR:
let sessionOptions = {
requestAR: true,
outputContext: webglCanvas.getContext('xrpresent'),
};
xrDevice.requestSession(sessionOptions).then((session) => {
sessionInfos[sessionTypes.AR].currentSession = session;
onSessionStarted(session);
});
break;
default:
throw 'Given unsupported WebXR session type enum ' + sessionTypeToRequest;
}
} }
function onSessionStarted(session) { function onSessionStarted(session) {
...@@ -45,7 +109,7 @@ function onSessionStarted(session) { ...@@ -45,7 +109,7 @@ function onSessionStarted(session) {
let offscreenCanvas = document.createElement('canvas'); let offscreenCanvas = document.createElement('canvas');
gl = offscreenCanvas.getContext('webgl', glAttribs); gl = offscreenCanvas.getContext('webgl', glAttribs);
if (!gl) { if (!gl) {
console.error('Failed to get WebGL context'); throw 'Failed to get WebGL context';
} }
gl.clearColor(0.0, 1.0, 0.0, 1.0); gl.clearColor(0.0, 1.0, 0.0, 1.0);
gl.enable(gl.DEPTH_TEST); gl.enable(gl.DEPTH_TEST);
...@@ -55,28 +119,21 @@ function onSessionStarted(session) { ...@@ -55,28 +119,21 @@ function onSessionStarted(session) {
session.baseLayer = new XRWebGLLayer(session, gl); session.baseLayer = new XRWebGLLayer(session, gl);
session.requestFrameOfReference('eye-level').then( (frameOfRef) => { session.requestFrameOfReference('eye-level').then( (frameOfRef) => {
if (session.exclusive) { sessionInfos[getSessionType(session)].currentFrameOfRef = frameOfRef;
exclusiveFrameOfRef = frameOfRef;
} else {
magicWindowFrameOfRef = frameOfRef;
}
session.requestAnimationFrame(onXRFrame); session.requestAnimationFrame(onXRFrame);
}); });
} }
function onSessionEnded(event) { function onSessionEnded(event) {
if (event.session.exclusive) sessionInfos[getSessionType(event.session)].clearSession();
exclusiveSession = null
else
magicWindowSession = null;
} }
function onXRFrame(t, frame) { function onXRFrame(t, frame) {
let session = frame.session; let session = frame.session;
session.requestAnimationFrame(onXRFrame); session.requestAnimationFrame(onXRFrame);
let frameOfRef = session.exclusive ?
exclusiveFrameOfRef : let frameOfRef = null;
magicWindowFrameOfRef; frameOfRef = sessionInfos[getSessionType(session)].currentFrameOfRef;
let pose = frame.getDevicePose(frameOfRef); let pose = frame.getDevicePose(frameOfRef);
// Exiting the rAF callback without dirtying the GL context is interpreted // Exiting the rAF callback without dirtying the GL context is interpreted
...@@ -87,22 +144,40 @@ function onXRFrame(t, frame) { ...@@ -87,22 +144,40 @@ function onXRFrame(t, frame) {
gl.bindFramebuffer(gl.FRAMEBUFFER, session.baseLayer.framebuffer); gl.bindFramebuffer(gl.FRAMEBUFFER, session.baseLayer.framebuffer);
// If in an exclusive session, set canvas to blue. Otherwise, red. // If in an exclusive session, set canvas to blue.
if (session.exclusive) { // If in an AR session, just draw the camera.
gl.clearColor(0.0, 0.0, 1.0, 1.0); // Otherwise, red.
if (onExclusiveXRFrameCallback) { switch (getSessionType(session)) {
onExclusiveXRFrameCallback(session, frame, gl); case sessionTypes.EXCLUSIVE:
} gl.clearColor(0.0, 0.0, 1.0, 1.0);
} else { if (onExclusiveXRFrameCallback) {
if (onMagicWindowXRFrameCallback) { onExclusiveXRFrameCallback(session, frame, gl);
onMagicWindowXRFrameCallback(session, frame); }
} gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.clearColor(1.0, 0.0, 0.0, 1.0); break;
case sessionTypes.AR:
// Do nothing for now
break;
default:
if (onMagicWindowXRFrameCallback) {
onMagicWindowXRFrameCallback(session, frame);
}
gl.clearColor(1.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
} }
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
hasPresentedFrame = true; hasPresentedFrame = true;
} }
function checkIfArSessionWouldTriggerPermissionPrompt() {
arSessionRequestWouldTriggerPermissionPrompt = null;
navigator.permissions.query({name: 'camera'}).then( (permission) => {
arSessionRequestWouldTriggerPermissionPrompt = permission.state == 'prompt';
}, () => {
throw 'Permission query rejected';
});
}
// Try to get an XRDevice and set up a non-exclusive session with it // Try to get an XRDevice and set up a non-exclusive session with it
if (navigator.xr) { if (navigator.xr) {
navigator.xr.requestDevice().then( (device) => { navigator.xr.requestDevice().then( (device) => {
...@@ -113,11 +188,22 @@ if (navigator.xr) { ...@@ -113,11 +188,22 @@ if (navigator.xr) {
// Set up the device to have a non-exclusive session (magic window) drawing // Set up the device to have a non-exclusive session (magic window) drawing
// into the full screen canvas on the page // into the full screen canvas on the page
let ctx = webglCanvas.getContext('xrpresent'); let ctx = webglCanvas.getContext('xrpresent');
device.requestSession({outputContext: ctx}).then( (session) => { // WebXR for VR tests want a non-exclusive session to be automatically
onSessionStarted(session); // created on page load to reduce the amount of boilerplate code necessary.
}).then( () => { // However, doing so during AR tests currently fails due to AR sessions
// always requiring a user gesture. So, allow a page to set a variable
// before loading this JavaScript file if they wish to skip the automatic
// non-exclusive session creation.
if (typeof shouldAutoCreateNonExclusiveSession === 'undefined'
|| shouldAutoCreateNonExclusiveSession === true) {
device.requestSession({outputContext: ctx}).then( (session) => {
onSessionStarted(session);
}).then( () => {
initializationSteps['magicWindowStarted'] = true;
});
} else {
initializationSteps['magicWindowStarted'] = true; initializationSteps['magicWindowStarted'] = true;
}); }
}).then( () => { }).then( () => {
initializationSteps['getXRDevice'] = true; initializationSteps['getXRDevice'] = true;
}); });
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment