Commit 7a6c82bc authored by Alex Cooper's avatar Alex Cooper Committed by Commit Bot

Ensure that XRCanvasInputProvider behaves as a transient source

Transient XRInputSources need to be added and removed from the input
source list as they are needed.  This exposes two helper methods on
XRSession to add/remove a transient source, and updates the canvas input
provider to call those methods when sending events.

Bug: 968229
Change-Id: I49e0313217a9d1526722c8a9f1e57f1141d3ee3f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1635775Reviewed-by: default avatarBill Orr <billorr@chromium.org>
Reviewed-by: default avatarBrian Sheedy <bsheedy@chromium.org>
Commit-Queue: Alexander Cooper <alcooper@chromium.org>
Cr-Commit-Position: refs/heads/master@{#664850}
parent f1104e55
......@@ -423,6 +423,40 @@ public class WebXrVrInputTest {
mWebXrVrTestFramework.endTest();
}
/**
* Tests that screen touches are registered as transient XR input when the viewer is Cardboard.
*/
@Test
@MediumTest
@Restriction(RESTRICTION_TYPE_VIEWER_NON_DAYDREAM)
@CommandLineFlags
.Remove({"enable-webvr"})
@CommandLineFlags.Add({"enable-features=WebXR"})
@XrActivityRestriction({XrActivityRestriction.SupportedActivity.ALL})
public void testTransientScreenTapsRegisteredOnCardboard_WebXr()
throws InterruptedException {
mWebXrVrTestFramework.loadUrlAndAwaitInitialization(
WebXrVrTestFramework.getFileUrlForHtmlTestFile("test_webxr_transient_input"),
PAGE_LOAD_TIMEOUT_S);
// Make it so that the webpage doesn't try to finish the JavaScript step after each input
// since we don't need to ack each one like with the Daydream controller.
mWebXrVrTestFramework.runJavaScriptOrFail(
"finishAfterEachInput = false", POLL_TIMEOUT_SHORT_MS);
int numIterations = 10;
mWebXrVrTestFramework.runJavaScriptOrFail(
"stepSetupListeners(" + String.valueOf(numIterations) + ")", POLL_TIMEOUT_SHORT_MS);
int x = mWebXrVrTestFramework.getCurrentContentView().getWidth() / 2;
int y = mWebXrVrTestFramework.getCurrentContentView().getHeight() / 2;
final View presentationView = mWebXrVrTestFramework.getCurrentContentView();
// Tap the screen a bunch of times and make sure that they're all registered.
spamScreenTaps(presentationView, x, y, numIterations);
mWebXrVrTestFramework.waitOnJavaScriptStep();
mWebXrVrTestFramework.endTest();
}
/**
* Tests that focus is locked to the presenting display for purposes of VR input.
*/
......
<!doctype html>
<!--
Tests that the ordering of events is correct when receiving clicks from transient
input such a user tapping on the canvas for an inline session.
-->
<html>
<head>
<link rel="stylesheet" type="text/css" href="../resources/webxr_e2e.css">
</head>
<body>
<canvas id="webgl-canvas"></canvas>
<script src="../../../../../../third_party/blink/web_tests/resources/testharness.js"></script>
<script src="../resources/webxr_e2e.js"></script>
<script src="../resources/webxr_boilerplate.js"></script>
<script>
var selectStartCount = 0;
var selectEndCount = 0;
var selectCount = 0;
var iterations;
var currentIteration = 0;
var finishAfterEachInput = true;
var inputSourceAdded = false;
function onInputSourcesChange() {
// Toggle whether or not we are "inside" a pair of input events
inputSourceAdded = !inputSourceAdded;
if (!inputSourceAdded) {
// If we closed this out, let's ensure we got all of the
// events that we expect.
currentIteration++;
assert_true(selectStartCount == currentIteration,
"selectStartCount should match the current iteration count");
assert_true(selectCount == currentIteration,
"selectCount should match the current iteration count");
assert_true(selectEndCount == currentIteration,
"selectEndCount should match the current iteration count");
if (currentIteration == iterations) {
done();
} else if (finishAfterEachInput) {
finishJavaScriptStep();
}
}
}
function onSelectStart() {
// selectstart should always be fired first, so check that.
assert_true(inputSourceAdded, "Should've seen input source added event");
assert_true(selectStartCount == selectEndCount,
'selectstart fired before selectend');
assert_true(selectStartCount == selectCount,
'selectstart fired before select');
selectStartCount++;
}
function onSelect() {
// select should always be fired between selectstart and selectend.
assert_true(inputSourceAdded, "Should've seen input source added event");
assert_true(selectCount + 1 == selectStartCount,
'select fired after selectstart');
assert_true(selectCount == selectEndCount,
'select fired after selectend');
selectCount++;
}
function onSelectEnd() {
// selectend should always be fired last.
assert_true(inputSourceAdded, "Should've seen input source added event");
selectEndCount++;
assert_true(selectEndCount == selectStartCount,
'selectend fired after selectstart');
assert_true(selectEndCount == selectCount,
'selectend fired before select');
}
function stepSetupListeners(numIterations) {
iterations = numIterations;
let currentSession = sessionInfos[sessionTypes.MAGIC_WINDOW].currentSession;
currentSession.addEventListener('inputsourceschange', onInputSourcesChange, false);
currentSession.addEventListener('selectstart', onSelectStart, false);
currentSession.addEventListener('selectend', onSelectEnd, false);
currentSession.addEventListener('select', onSelect, false);
}
</script>
</body>
</html>
......@@ -199,6 +199,7 @@ function requestMagicWindowSession() {
session.updateRenderState({
outputContext: ctx
});
sessionInfos[sessionTypes.MAGIC_WINDOW].currentSession = session;
onSessionStarted(session);
})
.then( () => {
......
......@@ -93,8 +93,12 @@ void XRCanvasInputProvider::UpdateInputSource(PointerEvent* event) {
return;
if (!input_source_) {
input_source_ = MakeGarbageCollected<XRInputSource>(session_, 0,
// XRSession doesn't like source ID's of 0. We should only be processing
// Canvas Input events in non-immersive sessions anyway, where we don't
// expect other controllers, so this number is somewhat arbitrary anyway.
input_source_ = MakeGarbageCollected<XRInputSource>(session_, 1,
XRInputSource::kScreen);
session_->AddTransientInputSource(input_source_);
}
// Get the event location relative to the canvas element.
......@@ -115,6 +119,7 @@ void XRCanvasInputProvider::UpdateInputSource(PointerEvent* event) {
}
void XRCanvasInputProvider::ClearInputSource() {
session_->RemoveTransientInputSource(input_source_);
input_source_ = nullptr;
}
......
......@@ -827,6 +827,28 @@ void XRSession::OnInputStateChange(
}
}
void XRSession::AddTransientInputSource(XRInputSource* input_source) {
if (ended_)
return;
// Ensure we're not overriding an input source that's already present.
DCHECK(!input_sources_->GetWithSourceId(input_source->source_id()));
input_sources_->SetWithSourceId(input_source->source_id(), input_source);
DispatchEvent(*XRInputSourcesChangeEvent::Create(
event_type_names::kInputsourceschange, this, {input_source}, {}));
}
void XRSession::RemoveTransientInputSource(XRInputSource* input_source) {
if (ended_)
return;
input_sources_->RemoveWithSourceId(input_source->source_id());
DispatchEvent(*XRInputSourcesChangeEvent::Create(
event_type_names::kInputsourceschange, this, {}, {input_source}));
}
void XRSession::OnSelectStart(XRInputSource* input_source) {
// Discard duplicate events, or events after the session has ended.
if (input_source->primaryInputPressed() || ended_)
......
......@@ -137,6 +137,9 @@ class XRSession final : public EventTargetWithInlineData,
WTF::Vector<XRViewData>& views();
void AddTransientInputSource(XRInputSource*);
void RemoveTransientInputSource(XRInputSource*);
void OnSelectStart(XRInputSource*);
void OnSelectEnd(XRInputSource*);
void OnSelect(XRInputSource*);
......
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