| // 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. |
| |
| #include "chrome/browser/vr/test/mock_xr_device_hook_base.h" |
| #include "content/public/common/service_manager_connection.h" |
| #include "device/vr/public/mojom/isolated_xr_service.mojom.h" |
| #include "services/service_manager/public/cpp/connector.h" |
| |
| // TODO(https://crbug.com/891832): Remove these conversion functions as part of |
| // the switch to only mojom types. |
| device_test::mojom::ControllerRole DeviceToMojoControllerRole( |
| device::ControllerRole role) { |
| switch (role) { |
| case device::kControllerRoleInvalid: |
| return device_test::mojom::ControllerRole::kControllerRoleInvalid; |
| case device::kControllerRoleRight: |
| return device_test::mojom::ControllerRole::kControllerRoleRight; |
| case device::kControllerRoleLeft: |
| return device_test::mojom::ControllerRole::kControllerRoleLeft; |
| } |
| } |
| |
| device_test::mojom::ControllerFrameDataPtr DeviceToMojoControllerFrameData( |
| const device::ControllerFrameData& data) { |
| device_test::mojom::ControllerFrameDataPtr ret = |
| device_test::mojom::ControllerFrameData::New(); |
| ret->packet_number = data.packet_number; |
| ret->buttons_pressed = data.buttons_pressed; |
| ret->buttons_touched = data.buttons_touched; |
| ret->supported_buttons = data.supported_buttons; |
| for (unsigned int i = 0; i < device::kMaxNumAxes; ++i) { |
| ret->axis_data.emplace_back(device_test::mojom::ControllerAxisData::New()); |
| ret->axis_data[i]->x = data.axis_data[i].x; |
| ret->axis_data[i]->y = data.axis_data[i].y; |
| ret->axis_data[i]->axis_type = data.axis_data[i].axis_type; |
| } |
| ret->role = DeviceToMojoControllerRole(data.role); |
| ret->is_valid = data.is_valid; |
| ret->pose_data = device_test::mojom::PoseFrameData::New(); |
| ret->pose_data->device_to_origin = gfx::Transform(); |
| for (int row = 0; row < 4; ++row) { |
| for (int col = 0; col < 4; ++col) { |
| ret->pose_data->device_to_origin->matrix().set( |
| row, col, data.pose_data.device_to_origin[row * 4 + col]); |
| } |
| } |
| return ret; |
| } |
| |
| MockXRDeviceHookBase::MockXRDeviceHookBase() |
| : tracked_classes_{device_test::mojom::TrackedDeviceClass:: |
| kTrackedDeviceInvalid}, |
| binding_(this) { |
| content::ServiceManagerConnection* connection = |
| content::ServiceManagerConnection::GetForProcess(); |
| connection->GetConnector()->BindInterface( |
| device::mojom::kVrIsolatedServiceName, |
| mojo::MakeRequest(&service_test_hook_)); |
| |
| device_test::mojom::XRTestHookPtr client; |
| binding_.Bind(mojo::MakeRequest(&client)); |
| |
| mojo::ScopedAllowSyncCallForTesting scoped_allow_sync; |
| // For now, always have the HMD connected. |
| tracked_classes_[0] = |
| device_test::mojom::TrackedDeviceClass::kTrackedDeviceHmd; |
| service_test_hook_->SetTestHook(std::move(client)); |
| } |
| |
| MockXRDeviceHookBase::~MockXRDeviceHookBase() { |
| StopHooking(); |
| } |
| |
| void MockXRDeviceHookBase::StopHooking() { |
| // We don't call service_test_hook_->SetTestHook(nullptr), since that |
| // will potentially deadlock with reentrant or crossing synchronous mojo |
| // calls. |
| binding_.Close(); |
| service_test_hook_ = nullptr; |
| } |
| |
| void MockXRDeviceHookBase::OnFrameSubmitted( |
| device_test::mojom::SubmittedFrameDataPtr frame_data, |
| device_test::mojom::XRTestHook::OnFrameSubmittedCallback callback) { |
| std::move(callback).Run(); |
| } |
| |
| void MockXRDeviceHookBase::WaitGetDeviceConfig( |
| device_test::mojom::XRTestHook::WaitGetDeviceConfigCallback callback) { |
| device_test::mojom::DeviceConfigPtr ret = |
| device_test::mojom::DeviceConfig::New(); |
| ret->interpupillary_distance = 0.1f; |
| ret->projection_left = device_test::mojom::ProjectionRaw::New(1, 1, 1, 1); |
| ret->projection_right = device_test::mojom::ProjectionRaw::New(1, 1, 1, 1); |
| std::move(callback).Run(std::move(ret)); |
| } |
| |
| void MockXRDeviceHookBase::WaitGetPresentingPose( |
| device_test::mojom::XRTestHook::WaitGetPresentingPoseCallback callback) { |
| auto pose = device_test::mojom::PoseFrameData::New(); |
| pose->device_to_origin = gfx::Transform(); |
| std::move(callback).Run(std::move(pose)); |
| } |
| |
| void MockXRDeviceHookBase::WaitGetMagicWindowPose( |
| device_test::mojom::XRTestHook::WaitGetMagicWindowPoseCallback callback) { |
| auto pose = device_test::mojom::PoseFrameData::New(); |
| pose->device_to_origin = gfx::Transform(); |
| std::move(callback).Run(std::move(pose)); |
| } |
| |
| void MockXRDeviceHookBase::WaitGetControllerRoleForTrackedDeviceIndex( |
| unsigned int index, |
| device_test::mojom::XRTestHook:: |
| WaitGetControllerRoleForTrackedDeviceIndexCallback callback) { |
| auto iter = controller_data_map_.find(index); |
| auto role = iter == controller_data_map_.end() |
| ? device_test::mojom::ControllerRole::kControllerRoleInvalid |
| : DeviceToMojoControllerRole(iter->second.role); |
| std::move(callback).Run(role); |
| } |
| |
| void MockXRDeviceHookBase::WaitGetTrackedDeviceClass( |
| unsigned int index, |
| device_test::mojom::XRTestHook::WaitGetTrackedDeviceClassCallback |
| callback) { |
| DCHECK(index < device::kMaxTrackedDevices); |
| std::move(callback).Run(tracked_classes_[index]); |
| } |
| |
| void MockXRDeviceHookBase::WaitGetControllerData( |
| unsigned int index, |
| device_test::mojom::XRTestHook::WaitGetControllerDataCallback callback) { |
| if (tracked_classes_[index] == |
| device_test::mojom::TrackedDeviceClass::kTrackedDeviceController) { |
| auto iter = controller_data_map_.find(index); |
| DCHECK(iter != controller_data_map_.end()); |
| std::move(callback).Run(DeviceToMojoControllerFrameData(iter->second)); |
| return; |
| } |
| // Default to not being valid so that controllers aren't connected unless |
| // a test specifically enables it. |
| auto data = |
| CreateValidController(device::ControllerRole::kControllerRoleInvalid); |
| data.is_valid = false; |
| std::move(callback).Run(DeviceToMojoControllerFrameData(data)); |
| } |
| |
| unsigned int MockXRDeviceHookBase::ConnectController( |
| const device::ControllerFrameData& initial_data) { |
| // Find the first open tracked device slot and fill that. |
| for (unsigned int i = 0; i < device::kMaxTrackedDevices; ++i) { |
| if (tracked_classes_[i] == |
| device_test::mojom::TrackedDeviceClass::kTrackedDeviceInvalid) { |
| tracked_classes_[i] = |
| device_test::mojom::TrackedDeviceClass::kTrackedDeviceController; |
| controller_data_map_.insert(std::make_pair(i, initial_data)); |
| return i; |
| } |
| } |
| // We shouldn't be running out of slots during a test. |
| NOTREACHED(); |
| // NOTREACHED should make it unnecessary to return here (as it does elsewhere |
| // in the code), but compilation fails if this is not present. |
| return device::kMaxTrackedDevices; |
| } |
| |
| void MockXRDeviceHookBase::TerminateDeviceServiceProcessForTesting() { |
| mojo::ScopedAllowSyncCallForTesting scoped_allow_sync; |
| service_test_hook_->TerminateDeviceServiceProcessForTesting(); |
| } |
| |
| void MockXRDeviceHookBase::UpdateController( |
| unsigned int index, |
| const device::ControllerFrameData& updated_data) { |
| auto iter = controller_data_map_.find(index); |
| DCHECK(iter != controller_data_map_.end()); |
| iter->second = updated_data; |
| } |
| |
| void MockXRDeviceHookBase::DisconnectController(unsigned int index) { |
| DCHECK(tracked_classes_[index] == |
| device_test::mojom::TrackedDeviceClass::kTrackedDeviceController); |
| auto iter = controller_data_map_.find(index); |
| DCHECK(iter != controller_data_map_.end()); |
| controller_data_map_.erase(iter); |
| tracked_classes_[index] = |
| device_test::mojom::TrackedDeviceClass::kTrackedDeviceInvalid; |
| } |
| |
| device::ControllerFrameData MockXRDeviceHookBase::CreateValidController( |
| device::ControllerRole role) { |
| device::ControllerFrameData ret; |
| // Because why shouldn't a 64 button controller exist? |
| ret.supported_buttons = UINT64_MAX; |
| memset(ret.axis_data, 0, |
| sizeof(device::ControllerAxisData) * device::kMaxNumAxes); |
| ret.role = role; |
| ret.is_valid = true; |
| // Identity matrix. |
| ret.pose_data.device_to_origin[0] = 1; |
| ret.pose_data.device_to_origin[5] = 1; |
| ret.pose_data.device_to_origin[10] = 1; |
| ret.pose_data.device_to_origin[15] = 1; |
| return ret; |
| } |