Skip to content

Commit

Permalink
sensors: Read Euler angles instead of quaternions from WebDriver
Browse files Browse the repository at this point in the history
As a result of w3c/deviceorientation#124 and
w3c/orientation-sensor#83.

The reading format is alpha-beta-gamma as described in the spec. They
are measured in degrees and must fall within certain ranges. Internally,
however, we always perform the Euler angles to quaternions conversion at
the edges (i.e. in ChromeDriver and the Internals implementation used by
content_shell), so that the the CDP and //services layers remain
unchanged and continue to support only quaternions and the
{ABSOLUTE,RELATIVE}_ORIENTATION_QUATERNION types for simplicity.

The code to convert Euler angles to quaternions was copied from
SensorInspectorAgent in Blink and is available for use by any callers
that need to validate Euler angles and convert them. The original code
remains in place because the entirety of the SensorInspectorAgent will
be removed soon due to the work on bug 1506995.

The test values for the orientation-sensor web tests had to be adapted:
we now provide the inputs as Euler angles. The expected values have
changed slightly as we had to find Euler _and_ quaternion values that
were easy enough to read.

Written in collaboration with Juha Vainio <juha.j.vainio@intel.com>

Bug: 1506995, 1520912, 1520919
Validate-Test-Flakiness: skip
Change-Id: I047f41f172f0bbcf30c7462926cec7ae0a66d4e5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5229177
Commit-Queue: Raphael Kubo Da Costa <raphael.kubo.da.costa@intel.com>
Reviewed-by: danakj <danakj@chromium.org>
Reviewed-by: Vladimir Nechaev <nechaev@chromium.org>
Reviewed-by: Reilly Grant <reillyg@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1251287}
  • Loading branch information
rakuco authored and Chromium LUCI CQ committed Jan 24, 2024
1 parent 04dd7f1 commit b917760
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 22 deletions.
1 change: 1 addition & 0 deletions BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,7 @@ source_set("lib") {
"//net",
"//net/server:http_server",
"//net/traffic_annotation:test_support",
"//services/device/public/cpp/generic_sensor",
"//services/network:network_service",
"//services/network/public/cpp",
"//services/network/public/mojom",
Expand Down
43 changes: 25 additions & 18 deletions session_commands.cc
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
#include "chrome/test/chromedriver/logging.h"
#include "chrome/test/chromedriver/session.h"
#include "chrome/test/chromedriver/util.h"
#include "services/device/public/cpp/generic_sensor/orientation_util.h"
#include "services/network/public/mojom/url_loader_factory.mojom.h"

namespace {
Expand Down Expand Up @@ -1168,30 +1169,31 @@ bool ParseXYZValue(const base::Value::Dict& params,
return true;
}

bool ParseOrientationQuaternion(const base::Value::Dict& params,
base::Value::Dict* out_params) {
constexpr size_t kQuaternionListSize = 4; // x, y, z, w

const base::Value::List* value_list = params.FindList("quaternion");
if (!value_list || value_list->size() != kQuaternionListSize) {
bool ParseOrientationEuler(const base::Value::Dict& params,
base::Value::Dict* out_params) {
if (!params.contains("alpha") || !params.contains("beta") ||
!params.contains("gamma")) {
return false;
}
std::optional<double> x = (*value_list)[0].GetIfDouble();
if (!x.has_value()) {

std::optional<double> alpha = params.FindDouble("alpha");
if (!alpha.has_value()) {
return false;
}
std::optional<double> y = (*value_list)[1].GetIfDouble();
if (!y.has_value()) {
std::optional<double> beta = params.FindDouble("beta");
if (!beta.has_value()) {
return false;
}
std::optional<double> z = (*value_list)[2].GetIfDouble();
if (!z.has_value()) {
std::optional<double> gamma = params.FindDouble("gamma");
if (!gamma.has_value()) {
return false;
}
std::optional<double> w = (*value_list)[3].GetIfDouble();
if (!w.has_value()) {
device::SensorReading quaternion_readings;
if (!device::ComputeQuaternionFromEulerAngles(*alpha, *beta, *gamma,
&quaternion_readings)) {
return false;
}

// Construct a dict that looks like this:
// {
// quaternion: {
Expand All @@ -1201,9 +1203,13 @@ bool ParseOrientationQuaternion(const base::Value::Dict& params,
// w: VAL4
// }
// }
const double x = quaternion_readings.orientation_quat.x;
const double y = quaternion_readings.orientation_quat.y;
const double z = quaternion_readings.orientation_quat.z;
const double w = quaternion_readings.orientation_quat.w;
out_params->Set(
"quaternion",
base::Value::Dict().Set("x", *x).Set("y", *y).Set("z", *z).Set("w", *w));
base::Value::Dict().Set("x", x).Set("y", y).Set("z", z).Set("w", w));
return true;
}

Expand Down Expand Up @@ -1239,9 +1245,10 @@ base::expected<base::Value::Dict, Status> ParseSensorUpdateParams(
}
} else if (*type == "absolute-orientation" ||
*type == "relative-orientation") {
if (!ParseOrientationQuaternion(*reading_dict, &reading)) {
return base::unexpected(
Status(kInvalidArgument, "Could not parse quaternion"));
if (!ParseOrientationEuler(*reading_dict, &reading)) {
return base::unexpected(Status(
kInvalidArgument, "Could not parse " + *type +
" readings. Invalid alpha/beta/gamma values"));
}
} else {
return base::unexpected(Status(
Expand Down
56 changes: 52 additions & 4 deletions test/run_py_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -4454,39 +4454,87 @@ def testUpdateVirtualSensorWithoutXYZValues(self):
})

def testUpdateVirtualSensorWithoutXYZWValues(self):
expected_error = ("invalid argument: Could not parse absolute-orientation "
"readings. Invalid alpha/beta/gamma values")
self.assertRaisesRegex(chromedriver.InvalidArgument,
"invalid argument: Could not parse quaternion",
expected_error,
self._driver.UpdateVirtualSensor,
'absolute-orientation', {
'y': 2.0,
'z': 3.0,
'w': 4.0
})
self.assertRaisesRegex(chromedriver.InvalidArgument,
"invalid argument: Could not parse quaternion",
expected_error,
self._driver.UpdateVirtualSensor,
'absolute-orientation', {
'x': 1.0,
'z': 3.0,
'w': 4.0
})
self.assertRaisesRegex(chromedriver.InvalidArgument,
"invalid argument: Could not parse quaternion",
expected_error,
self._driver.UpdateVirtualSensor,
'absolute-orientation', {
'x': 1.0,
'y': 2.0,
'w': 4.0
})
self.assertRaisesRegex(chromedriver.InvalidArgument,
"invalid argument: Could not parse quaternion",
expected_error,
self._driver.UpdateVirtualSensor,
'absolute-orientation', {
'x': 1.0,
'y': 2.0,
'z': 3.0
})

def testUpdateVirtualSensorWithoutAlphaBetaGammaValues(self):
expected_error = ("invalid argument: Could not parse relative-orientation "
"readings. Invalid alpha/beta/gamma values")
self.assertRaisesRegex(chromedriver.InvalidArgument,
expected_error,
self._driver.UpdateVirtualSensor,
'relative-orientation', {
'beta': 2.0,
'gamma': 3.0
})
self.assertRaisesRegex(chromedriver.InvalidArgument,
expected_error,
self._driver.UpdateVirtualSensor,
'relative-orientation', {
'alpha': 1.0,
'gamma': 3.0
})
self.assertRaisesRegex(chromedriver.InvalidArgument,
expected_error,
self._driver.UpdateVirtualSensor,
'relative-orientation', {
'alpha': 1.0,
'beta': 2.0
})

def testUpdateVirtualSensorOutOfRangeEulerAngles(self):
# Alpha, beta and gamma must be within the ranges defined by the Device
# Orientation API.
test_inputs = (
# Alpha range: [0, 360).
[-1, 2, 3], [361, 2, 3],
# Beta range: [-180, 180).
[1, -181, 3], [1, 180, 3],
# Gamma range: [-90, 90).
[1, 2, -91], [1, 2, 90]
)
expected_error = ("invalid argument: Could not parse relative-orientation "
"readings. Invalid alpha/beta/gamma values")
for test_input in test_inputs:
alpha, beta, gamma = test_input
self.assertRaisesRegex(chromedriver.InvalidArgument,
expected_error,
self._driver.UpdateVirtualSensor,
'relative-orientation',
{ 'alpha': alpha, 'beta': beta, 'gamma': gamma })

def testRemoveVirtualSensorWithInvalidSensorName(self):
self.assertRaisesRegex(
chromedriver.InvalidArgument,
Expand Down

0 comments on commit b917760

Please sign in to comment.