| // Copyright 2014 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 "ui/display/manager/touch_transform_controller.h" |
| |
| #include <memory> |
| #include <string> |
| #include <utility> |
| |
| #include "base/strings/string_number_conversions.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/display/manager/default_touch_transform_setter.h" |
| #include "ui/display/manager/display_manager.h" |
| #include "ui/display/manager/test/touch_device_manager_test_api.h" |
| #include "ui/display/manager/touch_device_manager.h" |
| #include "ui/display/screen_base.h" |
| #include "ui/events/devices/device_data_manager.h" |
| |
| namespace display { |
| namespace test { |
| namespace { |
| |
| constexpr int kDisplayId1 = 1; |
| constexpr int kDisplayId2 = 2; |
| constexpr int kTouchId1 = 5; |
| constexpr int kTouchId2 = 6; |
| |
| ui::TouchDeviceTransform CreateTouchDeviceTransform( |
| int64_t display_id, |
| int32_t device_id, |
| const gfx::Transform& transform, |
| double radius_scale = 1.0) { |
| ui::TouchDeviceTransform touch_device_transform; |
| touch_device_transform.display_id = display_id; |
| touch_device_transform.device_id = device_id; |
| touch_device_transform.transform = transform; |
| touch_device_transform.radius_scale = radius_scale; |
| return touch_device_transform; |
| } |
| |
| ui::TouchscreenDevice CreateTouchscreenDevice(unsigned int id, |
| const gfx::Size& size) { |
| return ui::TouchscreenDevice(id, ui::InputDeviceType::INPUT_DEVICE_USB, |
| std::string(), size, 0); |
| } |
| |
| std::string GetTouchPointString( |
| const TouchCalibrationData::CalibrationPointPairQuad& pts) { |
| std::string str = "Failed for point pairs: "; |
| for (std::size_t row = 0; row < pts.size(); row++) { |
| str += "{(" + base::NumberToString(pts[row].first.x()) + "," + |
| base::NumberToString(pts[row].first.y()) + "), (" + |
| base::NumberToString(pts[row].second.x()) + "," + |
| base::NumberToString(pts[row].second.y()) + ")} "; |
| } |
| return str; |
| } |
| |
| // Checks if the touch input has been calibrated properly. The input is said to |
| // be calibrated if any touch input is transformed to the correct corresponding |
| // display point within an error delta of |max_error_delta.width()| along the X |
| // axis and |max_error_delta.height()| along the Y axis; |
| void CheckPointsOfInterests(const int touch_id, |
| const gfx::Size& touch_size, |
| const gfx::Size& display_size, |
| const gfx::Size& max_error_delta, |
| const std::string& error_msg) { |
| ui::DeviceDataManager* device_manager = ui::DeviceDataManager::GetInstance(); |
| float x, y; |
| |
| // Origin of the touch device should correspond to origin of the display. |
| x = y = 0.0; |
| device_manager->ApplyTouchTransformer(touch_id, &x, &y); |
| EXPECT_NEAR(0, x, max_error_delta.width()) << error_msg; |
| EXPECT_NEAR(0, y, max_error_delta.height()) << error_msg; |
| |
| // Center of the touch device should correspond to the center of the display |
| // device. |
| x = touch_size.width() / 2; |
| y = touch_size.height() / 2; |
| device_manager->ApplyTouchTransformer(touch_id, &x, &y); |
| EXPECT_NEAR(display_size.width() / 2, x, max_error_delta.width()) |
| << error_msg; |
| EXPECT_NEAR(display_size.height() / 2, y, max_error_delta.height()) |
| << error_msg; |
| |
| // Bottom right corner of the touch device should correspond to rightmost |
| // corner of display device. |
| x = touch_size.width(); |
| y = touch_size.height(); |
| device_manager->ApplyTouchTransformer(touch_id, &x, &y); |
| EXPECT_NEAR(display_size.width(), x, max_error_delta.width()) << error_msg; |
| EXPECT_NEAR(display_size.height(), y, max_error_delta.height()) << error_msg; |
| } |
| |
| } // namespace |
| |
| class TouchTransformControllerTest : public testing::Test { |
| public: |
| TouchTransformControllerTest() {} |
| ~TouchTransformControllerTest() override {} |
| |
| gfx::Transform GetTouchTransform( |
| const ManagedDisplayInfo& display, |
| const ManagedDisplayInfo& touch_display, |
| const ui::TouchscreenDevice& touchscreen) const { |
| return touch_transform_controller_->GetTouchTransform( |
| display, touch_display, touchscreen); |
| } |
| |
| double GetTouchResolutionScale( |
| const ManagedDisplayInfo& touch_display, |
| const ui::TouchscreenDevice& touch_device) const { |
| return touch_transform_controller_->GetTouchResolutionScale(touch_display, |
| touch_device); |
| } |
| |
| TouchDeviceManager* touch_device_manager() { return touch_device_manager_; } |
| |
| // testing::Test: |
| void SetUp() override { |
| ui::DeviceDataManager::CreateInstance(); |
| std::unique_ptr<ScreenBase> screen = std::make_unique<ScreenBase>(); |
| Screen::SetScreenInstance(screen.get()); |
| display_manager_ = std::make_unique<DisplayManager>(std::move(screen)); |
| touch_device_manager_ = display_manager_->touch_device_manager(); |
| touch_transform_controller_ = std::make_unique<TouchTransformController>( |
| display_manager_.get(), |
| std::make_unique<DefaultTouchTransformSetter>()); |
| } |
| |
| void TearDown() override { |
| Screen::SetScreenInstance(nullptr); |
| ui::DeviceDataManager::DeleteInstance(); |
| } |
| |
| ManagedDisplayInfo CreateDisplayInfo(int64_t id, |
| const ui::TouchscreenDevice& device, |
| const gfx::Rect& bounds) { |
| ManagedDisplayInfo info(id, std::string(), false); |
| info.SetBounds(bounds); |
| |
| // Create a default mode. |
| ManagedDisplayInfo::ManagedDisplayModeList default_modes( |
| 1, ManagedDisplayMode(bounds.size(), 60, false, true)); |
| info.SetManagedDisplayModes(default_modes); |
| |
| // Associate the display and touch device. |
| test::TouchDeviceManagerTestApi tdm_test_api(touch_device_manager_); |
| tdm_test_api.Associate(&info, device); |
| |
| return info; |
| } |
| |
| private: |
| std::unique_ptr<DisplayManager> display_manager_; |
| std::unique_ptr<TouchTransformController> touch_transform_controller_; |
| TouchDeviceManager* touch_device_manager_; |
| |
| DISALLOW_COPY_AND_ASSIGN(TouchTransformControllerTest); |
| }; |
| |
| TEST_F(TouchTransformControllerTest, MirrorModeLetterboxing) { |
| gfx::Size fb_size(1920, 1200); |
| // TODO(kylechar): Check the TouchscreenDevice size makes sense for Ozone. |
| ui::TouchscreenDevice internal_touchscreen = |
| CreateTouchscreenDevice(10, fb_size); |
| ui::TouchscreenDevice external_touchscreen = |
| CreateTouchscreenDevice(11, fb_size); |
| |
| // The internal display has native resolution of 2560x1700, and in |
| // mirror mode it is configured as 1920x1200. This is in letterboxing |
| // mode. |
| ManagedDisplayInfo internal_display_info = |
| CreateDisplayInfo(1, internal_touchscreen, gfx::Rect(0, 0, 1920, 1200)); |
| internal_display_info.set_is_aspect_preserving_scaling(true); |
| |
| ManagedDisplayInfo::ManagedDisplayModeList internal_modes; |
| |
| internal_modes.push_back( |
| ManagedDisplayMode(gfx::Size(2560, 1700), 60, false, true)); |
| internal_modes.push_back( |
| ManagedDisplayMode(gfx::Size(1920, 1200), 60, false, false)); |
| internal_display_info.SetManagedDisplayModes(internal_modes); |
| |
| ManagedDisplayInfo external_display_info = |
| CreateDisplayInfo(2, external_touchscreen, gfx::Rect(0, 0, 1920, 1200)); |
| |
| ui::DeviceDataManager* device_manager = ui::DeviceDataManager::GetInstance(); |
| |
| std::vector<ui::TouchDeviceTransform> transforms; |
| transforms.push_back(CreateTouchDeviceTransform( |
| internal_display_info.id(), internal_touchscreen.id, |
| GetTouchTransform(internal_display_info, internal_display_info, |
| internal_touchscreen))); |
| transforms.push_back(CreateTouchDeviceTransform( |
| internal_display_info.id(), external_touchscreen.id, |
| GetTouchTransform(external_display_info, external_display_info, |
| external_touchscreen))); |
| device_manager->ConfigureTouchDevices(transforms); |
| |
| EXPECT_EQ(1, device_manager->GetTargetDisplayForTouchDevice(10)); |
| EXPECT_EQ(1, device_manager->GetTargetDisplayForTouchDevice(11)); |
| |
| // External touch display has the default TouchTransformer. |
| float x = 100.0; |
| float y = 100.0; |
| device_manager->ApplyTouchTransformer(11, &x, &y); |
| EXPECT_EQ(100, x); |
| EXPECT_EQ(100, y); |
| |
| // In letterboxing, there is (1-2560*(1200/1920)/1700)/2 = 2.95% of the |
| // height on both the top & bottom region of the screen is blank. |
| // When touch events coming at Y range [0, 1200), the mapping should be |
| // [0, ~35] ---> < 0 |
| // [~35, ~1165] ---> [0, 1200) |
| // [~1165, 1200] ---> >= 1200 |
| x = 100.0; |
| y = 35.0; |
| device_manager->ApplyTouchTransformer(10, &x, &y); |
| EXPECT_NEAR(100, x, 0.5); |
| EXPECT_NEAR(0, y, 0.5); |
| |
| x = 100.0; |
| y = 1165.0; |
| device_manager->ApplyTouchTransformer(10, &x, &y); |
| EXPECT_NEAR(100, x, 0.5); |
| EXPECT_NEAR(1200, y, 0.5); |
| } |
| |
| TEST_F(TouchTransformControllerTest, MirrorModePillarboxing) { |
| gfx::Size fb_size(1024, 768); |
| // TODO(kylechar): Check the TouchscreenDevice size makes sense for Ozone. |
| ui::TouchscreenDevice internal_touchscreen = |
| CreateTouchscreenDevice(10, fb_size); |
| ui::TouchscreenDevice external_touchscreen = |
| CreateTouchscreenDevice(11, fb_size); |
| |
| // The internal display has native resolution of 1366x768, and in |
| // mirror mode it is configured as 1024x768. This is in pillarboxing |
| // mode. |
| ManagedDisplayInfo internal_display_info = |
| CreateDisplayInfo(1, internal_touchscreen, gfx::Rect(0, 0, 1024, 768)); |
| internal_display_info.set_is_aspect_preserving_scaling(true); |
| ManagedDisplayInfo::ManagedDisplayModeList internal_modes; |
| internal_modes.push_back( |
| ManagedDisplayMode(gfx::Size(1366, 768), 60, false, true)); |
| internal_modes.push_back( |
| ManagedDisplayMode(gfx::Size(1024, 768), 60, false, false)); |
| internal_display_info.SetManagedDisplayModes(internal_modes); |
| |
| ManagedDisplayInfo external_display_info = |
| CreateDisplayInfo(2, external_touchscreen, gfx::Rect(0, 0, 1024, 768)); |
| |
| ui::DeviceDataManager* device_manager = ui::DeviceDataManager::GetInstance(); |
| std::vector<ui::TouchDeviceTransform> transforms; |
| |
| transforms.push_back(CreateTouchDeviceTransform( |
| internal_display_info.id(), internal_touchscreen.id, |
| GetTouchTransform(internal_display_info, internal_display_info, |
| internal_touchscreen))); |
| |
| transforms.push_back(CreateTouchDeviceTransform( |
| internal_display_info.id(), external_touchscreen.id, |
| GetTouchTransform(external_display_info, external_display_info, |
| external_touchscreen))); |
| device_manager->ConfigureTouchDevices(transforms); |
| |
| EXPECT_EQ(1, device_manager->GetTargetDisplayForTouchDevice(10)); |
| EXPECT_EQ(1, device_manager->GetTargetDisplayForTouchDevice(11)); |
| |
| // External touch display has the default TouchTransformer. |
| float x = 100.0; |
| float y = 100.0; |
| device_manager->ApplyTouchTransformer(11, &x, &y); |
| EXPECT_EQ(100, x); |
| EXPECT_EQ(100, y); |
| |
| // In pillarboxing, there is (1-768*(1024/768)/1366)/2 = 12.5% of the |
| // width on both the left & rigth region of the screen is blank. |
| // When touch events coming at X range [0, 1024), the mapping should be |
| // [0, ~128] ---> < 0 |
| // [~128, ~896] ---> [0, 1024) |
| // [~896, 1024] ---> >= 1024 |
| x = 128.0; |
| y = 100.0; |
| device_manager->ApplyTouchTransformer(10, &x, &y); |
| EXPECT_NEAR(0, x, 0.5); |
| EXPECT_NEAR(100, y, 0.5); |
| |
| x = 896.0; |
| y = 100.0; |
| device_manager->ApplyTouchTransformer(10, &x, &y); |
| EXPECT_NEAR(1024, x, 0.5); |
| EXPECT_NEAR(100, y, 0.5); |
| } |
| |
| TEST_F(TouchTransformControllerTest, SoftwareMirrorMode) { |
| gfx::Size fb_size(1920, 1990); |
| // TODO(kylechar): Check the TouchscreenDevice size makes sense for Ozone. |
| ui::TouchscreenDevice display1_touchscreen = |
| CreateTouchscreenDevice(10, fb_size); |
| ui::TouchscreenDevice display2_touchscreen = |
| CreateTouchscreenDevice(11, fb_size); |
| |
| // External display 1 has size 1280x850. External display 2 has size |
| // 1920x1080. When using software mirroring to mirror display 1 onto |
| // display 2, the displays are in extended mode and we map touches from both |
| // displays to display 1. |
| // The total frame buffer is 1920x1990, |
| // where 1990 = 850 + 60 (hidden gap) + 1080 and the second monitor is |
| // translated to point (0, 950) in the framebuffer. |
| ManagedDisplayInfo display1_info = |
| CreateDisplayInfo(1, display1_touchscreen, gfx::Rect(0, 0, 1280, 850)); |
| ManagedDisplayInfo::ManagedDisplayModeList display1_modes; |
| display1_modes.push_back( |
| ManagedDisplayMode(gfx::Size(1280, 850), 60, false, true)); |
| display1_info.SetManagedDisplayModes(display1_modes); |
| |
| ManagedDisplayInfo display2_info = |
| CreateDisplayInfo(2, display2_touchscreen, gfx::Rect(0, 950, 1920, 1080)); |
| ManagedDisplayInfo::ManagedDisplayModeList display2_modes; |
| display2_modes.push_back( |
| ManagedDisplayMode(gfx::Size(1920, 1080), 60, false, true)); |
| display2_info.SetManagedDisplayModes(display2_modes); |
| |
| ui::DeviceDataManager* device_manager = ui::DeviceDataManager::GetInstance(); |
| std::vector<ui::TouchDeviceTransform> transforms; |
| |
| transforms.push_back(CreateTouchDeviceTransform( |
| display1_info.id(), display1_touchscreen.id, |
| GetTouchTransform(display1_info, display1_info, display1_touchscreen))); |
| |
| transforms.push_back(CreateTouchDeviceTransform( |
| display1_info.id(), display2_touchscreen.id, |
| GetTouchTransform(display1_info, display2_info, display2_touchscreen))); |
| |
| device_manager->ConfigureTouchDevices(transforms); |
| |
| EXPECT_EQ(1, device_manager->GetTargetDisplayForTouchDevice(10)); |
| EXPECT_EQ(1, device_manager->GetTargetDisplayForTouchDevice(11)); |
| |
| // Mapping for touch events from display 1's touchscreen: |
| // [0, 1920) x [0, 1990) -> [0, 1280) x [0, 850) |
| float x = 0.0; |
| float y = 0.0; |
| device_manager->ApplyTouchTransformer(10, &x, &y); |
| EXPECT_NEAR(0, x, 0.5); |
| EXPECT_NEAR(0, y, 0.5); |
| |
| x = 1920.0; |
| y = 1990.0; |
| device_manager->ApplyTouchTransformer(10, &x, &y); |
| EXPECT_NEAR(1280, x, 0.5); |
| EXPECT_NEAR(850, y, 0.5); |
| |
| // In pillarboxing, there is (1-1280*(1080/850)/1920)/2 = 7.65% of the |
| // width on both the left & right region of the screen is blank. |
| // Events come in the range [0, 1920) x [0, 1990). |
| // |
| // X mapping: |
| // [0, ~147] ---> < 0 |
| // [~147, ~1773] ---> [0, 1280) |
| // [~1773, 1920] ---> >= 1280 |
| // Y mapping: |
| // [0, 1990) -> [0, 1080) |
| x = 147.0; |
| y = 0.0; |
| device_manager->ApplyTouchTransformer(11, &x, &y); |
| EXPECT_NEAR(0, x, 0.5); |
| EXPECT_NEAR(0, y, 0.5); |
| |
| x = 1773.0; |
| y = 1990.0; |
| device_manager->ApplyTouchTransformer(11, &x, &y); |
| EXPECT_NEAR(1280, x, 0.5); |
| EXPECT_NEAR(850, y, 0.5); |
| } |
| |
| TEST_F(TouchTransformControllerTest, ExtendedMode) { |
| gfx::Size fb_size(2560, 2428); |
| |
| // TODO(kylechar): Check the TouchscreenDevice size makes sense for Ozone. |
| ui::TouchscreenDevice touchscreen1 = CreateTouchscreenDevice(5, fb_size); |
| ui::TouchscreenDevice touchscreen2 = CreateTouchscreenDevice(6, fb_size); |
| |
| // The internal display has size 1366 x 768. The external display has |
| // size 2560x1600. The total frame buffer is 2560x2428, |
| // where 2428 = 768 + 60 (hidden gap) + 1600 |
| // and the second monitor is translated to Point (0, 828) in the |
| // framebuffer. |
| ManagedDisplayInfo display1 = |
| CreateDisplayInfo(1, touchscreen1, gfx::Rect(0, 0, 1366, 768)); |
| ManagedDisplayInfo display2 = |
| CreateDisplayInfo(2, touchscreen2, gfx::Rect(0, 828, 2560, 1600)); |
| |
| ui::DeviceDataManager* device_manager = ui::DeviceDataManager::GetInstance(); |
| std::vector<ui::TouchDeviceTransform> transforms; |
| transforms.push_back(CreateTouchDeviceTransform( |
| display1.id(), touchscreen1.id, |
| GetTouchTransform(display1, display1, touchscreen1))); |
| |
| transforms.push_back(CreateTouchDeviceTransform( |
| display2.id(), touchscreen2.id, |
| GetTouchTransform(display2, display2, touchscreen2))); |
| device_manager->ConfigureTouchDevices(transforms); |
| |
| EXPECT_EQ(1, device_manager->GetTargetDisplayForTouchDevice(5)); |
| EXPECT_EQ(2, device_manager->GetTargetDisplayForTouchDevice(6)); |
| |
| // Mapping for touch events from internal touch display: |
| // [0, 2560) x [0, 2428) -> [0, 1366) x [0, 768) |
| float x = 0.0; |
| float y = 0.0; |
| device_manager->ApplyTouchTransformer(5, &x, &y); |
| EXPECT_NEAR(0, x, 0.5); |
| EXPECT_NEAR(0, y, 0.5); |
| |
| x = 2559.0; |
| y = 2427.0; |
| device_manager->ApplyTouchTransformer(5, &x, &y); |
| EXPECT_NEAR(1365, x, 0.5); |
| EXPECT_NEAR(768, y, 0.5); |
| |
| // Mapping for touch events from external touch display: |
| // [0, 2560) x [0, 2428) -> [0, 2560) x [0, 1600) |
| x = 0.0; |
| y = 0.0; |
| device_manager->ApplyTouchTransformer(6, &x, &y); |
| // On ozone we expect screen coordinates so add display origin. |
| EXPECT_NEAR(0 + 0, x, 0.5); |
| EXPECT_NEAR(0 + 828, y, 0.5); |
| |
| x = 2559.0; |
| y = 2427.0; |
| device_manager->ApplyTouchTransformer(6, &x, &y); |
| // On ozone we expect screen coordinates so add display origin. |
| EXPECT_NEAR(2559 + 0, x, 0.5); |
| EXPECT_NEAR(1599 + 828, y, 0.5); |
| } |
| |
| TEST_F(TouchTransformControllerTest, TouchRadiusScale) { |
| ui::TouchscreenDevice touch_device = |
| CreateTouchscreenDevice(5, gfx::Size(1001, 1001)); |
| ManagedDisplayInfo display = |
| CreateDisplayInfo(1, touch_device, gfx::Rect(0, 0, 2560, 1600)); |
| |
| // Default touchscreen position range is 1001x1001; |
| EXPECT_EQ(sqrt((2560.0 * 1600.0) / (1001.0 * 1001.0)), |
| GetTouchResolutionScale(display, touch_device)); |
| } |
| |
| TEST_F(TouchTransformControllerTest, OzoneTranslation) { |
| // The internal display has size 1920 x 1200. The external display has |
| // size 1920x1200. The total frame buffer is 1920x2450, |
| // where 2458 = 1200 + 50 (hidden gap) + 1200 |
| // and the second monitor is translated to Point (0, 1250) in the |
| // framebuffer. |
| const gfx::Size kDisplaySize(1920, 1200); |
| const int kHiddenGap = 50; |
| |
| ui::TouchscreenDevice touchscreen1 = |
| CreateTouchscreenDevice(kTouchId1, kDisplaySize); |
| ui::TouchscreenDevice touchscreen2 = |
| CreateTouchscreenDevice(kTouchId2, kDisplaySize); |
| |
| ManagedDisplayInfo display1 = CreateDisplayInfo( |
| kDisplayId1, touchscreen1, |
| gfx::Rect(0, 0, kDisplaySize.width(), kDisplaySize.height())); |
| ManagedDisplayInfo display2 = |
| CreateDisplayInfo(kDisplayId2, touchscreen2, |
| gfx::Rect(0, kDisplaySize.height() + kHiddenGap, |
| kDisplaySize.width(), kDisplaySize.height())); |
| |
| ui::DeviceDataManager* device_manager = ui::DeviceDataManager::GetInstance(); |
| std::vector<ui::TouchDeviceTransform> transforms; |
| |
| // Mirror displays. Touch screen 2 is associated to display 1. |
| transforms.push_back(CreateTouchDeviceTransform( |
| display1.id(), touchscreen1.id, |
| GetTouchTransform(display1, display1, touchscreen1))); |
| |
| transforms.push_back(CreateTouchDeviceTransform( |
| display1.id(), touchscreen2.id, |
| GetTouchTransform(display1, display2, touchscreen2))); |
| device_manager->ConfigureTouchDevices(transforms); |
| |
| EXPECT_EQ(kDisplayId1, |
| device_manager->GetTargetDisplayForTouchDevice(kTouchId1)); |
| EXPECT_EQ(kDisplayId1, |
| device_manager->GetTargetDisplayForTouchDevice(kTouchId2)); |
| |
| float x, y; |
| |
| x = y = 0.0; |
| device_manager->ApplyTouchTransformer(kTouchId1, &x, &y); |
| EXPECT_NEAR(0, x, 0.5); |
| EXPECT_NEAR(0, y, 0.5); |
| |
| x = y = 0.0; |
| device_manager->ApplyTouchTransformer(kTouchId2, &x, &y); |
| EXPECT_NEAR(0, x, 0.5); |
| EXPECT_NEAR(0, y, 0.5); |
| |
| x = 1920.0; |
| y = 1200.0; |
| device_manager->ApplyTouchTransformer(kTouchId1, &x, &y); |
| EXPECT_NEAR(1920, x, 0.5); |
| EXPECT_NEAR(1200, y, 0.5); |
| |
| x = 1920.0; |
| y = 1200.0; |
| device_manager->ApplyTouchTransformer(kTouchId2, &x, &y); |
| EXPECT_NEAR(1920, x, 0.5); |
| EXPECT_NEAR(1200, y, 0.5); |
| |
| // Remove mirroring of displays. |
| transforms.push_back(CreateTouchDeviceTransform( |
| display2.id(), touchscreen2.id, |
| GetTouchTransform(display2, display2, touchscreen2))); |
| device_manager->ConfigureTouchDevices(transforms); |
| |
| x = 1920.0; |
| y = 1200.0; |
| device_manager->ApplyTouchTransformer(kTouchId1, &x, &y); |
| EXPECT_NEAR(1920, x, 0.5); |
| EXPECT_NEAR(1200, y, 0.5); |
| |
| x = 1920.0; |
| y = 1200.0; |
| device_manager->ApplyTouchTransformer(kTouchId2, &x, &y); |
| EXPECT_NEAR(1920, x, 0.5); |
| EXPECT_NEAR(1200 + kDisplaySize.height() + kHiddenGap, y, 0.5); |
| } |
| |
| TEST_F(TouchTransformControllerTest, AccurateUserTouchCalibration) { |
| const gfx::Size kDisplaySize(1920, 1200); |
| const gfx::Size kTouchSize(1920, 1200); |
| |
| ui::TouchscreenDevice touchscreen = |
| CreateTouchscreenDevice(kTouchId1, kTouchSize); |
| |
| ManagedDisplayInfo display = CreateDisplayInfo( |
| kDisplayId1, touchscreen, |
| gfx::Rect(0, 0, kDisplaySize.width(), kDisplaySize.height())); |
| |
| // Assuming the user provided accurate inputs during calibration. ie the user |
| // actually tapped (100,100) when asked to tap (100,100) with no human error. |
| TouchCalibrationData::CalibrationPointPairQuad user_input = {{ |
| std::make_pair(gfx::Point(100, 100), gfx::Point(100, 100)), |
| std::make_pair(gfx::Point(1820, 100), gfx::Point(1820, 100)), |
| std::make_pair(gfx::Point(100, 1100), gfx::Point(100, 1100)), |
| std::make_pair(gfx::Point(1820, 1100), gfx::Point(1820, 1100)), |
| }}; |
| TouchCalibrationData touch_data(user_input, kDisplaySize); |
| |
| const std::string msg = GetTouchPointString(user_input); |
| |
| touch_device_manager()->AddTouchCalibrationData( |
| display::TouchDeviceIdentifier::FromDevice(touchscreen), display.id(), |
| touch_data); |
| |
| EXPECT_FALSE(touch_device_manager() |
| ->GetCalibrationData(touchscreen, display.id()) |
| .IsEmpty()); |
| |
| ui::DeviceDataManager* device_manager = ui::DeviceDataManager::GetInstance(); |
| std::vector<ui::TouchDeviceTransform> transforms; |
| transforms.push_back(CreateTouchDeviceTransform( |
| display.id(), touchscreen.id, |
| GetTouchTransform(display, display, touchscreen))); |
| device_manager->ConfigureTouchDevices(transforms); |
| |
| EXPECT_EQ(kDisplayId1, |
| device_manager->GetTargetDisplayForTouchDevice(kTouchId1)); |
| |
| CheckPointsOfInterests(kTouchId1, kTouchSize, kDisplaySize, gfx::Size(1, 1), |
| msg); |
| } |
| |
| TEST_F(TouchTransformControllerTest, ErrorProneUserTouchCalibration) { |
| const gfx::Size kDisplaySize(1920, 1200); |
| const gfx::Size kTouchSize(1920, 1200); |
| // User touch inputs have a max error of 5%. |
| const float kError = 0.05; |
| // The maximum user error rate is |kError|%. Since the calibration is |
| // performed with a best fit algorithm, the error rate observed should be less |
| // than |kError|. |
| const gfx::Size kMaxErrorDelta = gfx::ScaleToCeiledSize(kTouchSize, kError); |
| |
| ui::TouchscreenDevice touchscreen = |
| CreateTouchscreenDevice(kTouchId1, kTouchSize); |
| |
| ManagedDisplayInfo display = CreateDisplayInfo( |
| kDisplayId1, touchscreen, |
| gfx::Rect(0, 0, kDisplaySize.width(), kDisplaySize.height())); |
| |
| // Assuming the user provided inaccurate inputs during calibration. ie the |
| // user did not tap (100,100) when asked to tap (100,100) due to human error. |
| TouchCalibrationData::CalibrationPointPairQuad user_input = { |
| {std::make_pair(gfx::Point(100, 100), gfx::Point(130, 60)), |
| std::make_pair(gfx::Point(1820, 100), gfx::Point(1878, 130)), |
| std::make_pair(gfx::Point(100, 1100), gfx::Point(158, 1060)), |
| std::make_pair(gfx::Point(1820, 1100), gfx::Point(1790, 1140))}}; |
| TouchCalibrationData touch_data(user_input, kDisplaySize); |
| |
| const std::string msg = GetTouchPointString(user_input); |
| |
| touch_device_manager()->AddTouchCalibrationData( |
| display::TouchDeviceIdentifier::FromDevice(touchscreen), display.id(), |
| touch_data); |
| |
| EXPECT_FALSE(touch_device_manager() |
| ->GetCalibrationData(touchscreen, display.id()) |
| .IsEmpty()); |
| |
| ui::DeviceDataManager* device_manager = ui::DeviceDataManager::GetInstance(); |
| std::vector<ui::TouchDeviceTransform> transforms; |
| transforms.push_back(CreateTouchDeviceTransform( |
| display.id(), touchscreen.id, |
| GetTouchTransform(display, display, touchscreen))); |
| device_manager->ConfigureTouchDevices(transforms); |
| |
| EXPECT_EQ(kDisplayId1, |
| device_manager->GetTargetDisplayForTouchDevice(kTouchId1)); |
| |
| CheckPointsOfInterests(kTouchId1, kTouchSize, kDisplaySize, kMaxErrorDelta, |
| msg); |
| } |
| |
| TEST_F(TouchTransformControllerTest, ResolutionChangeUserTouchCalibration) { |
| const gfx::Size kDisplaySize(2560, 1600); |
| const gfx::Size kTouchSize(1920, 1200); |
| // User touch inputs have a max error of 5%. |
| const float kError = 0.05; |
| // The maximum user error rate is |kError|%. Since the calibration is |
| // performed with a best fit algorithm, the error rate observed should be less |
| // tha |kError|. |
| gfx::Size kMaxErrorDelta = gfx::ScaleToCeiledSize(kDisplaySize, kError); |
| |
| ui::TouchscreenDevice touchscreen = |
| CreateTouchscreenDevice(kTouchId1, kTouchSize); |
| |
| ManagedDisplayInfo display = CreateDisplayInfo( |
| kDisplayId1, touchscreen, |
| gfx::Rect(0, 0, kDisplaySize.width(), kDisplaySize.height())); |
| |
| // The calibration was performed at a resolution different from the curent |
| // resolution of the display. |
| const gfx::Size CALIBRATION_SIZE(1920, 1200); |
| TouchCalibrationData::CalibrationPointPairQuad user_input = { |
| {std::make_pair(gfx::Point(100, 100), gfx::Point(50, 70)), |
| std::make_pair(gfx::Point(1820, 100), gfx::Point(1780, 70)), |
| std::make_pair(gfx::Point(100, 1100), gfx::Point(70, 1060)), |
| std::make_pair(gfx::Point(1820, 1100), gfx::Point(1770, 1140))}}; |
| |
| TouchCalibrationData touch_data(user_input, CALIBRATION_SIZE); |
| |
| const std::string msg = GetTouchPointString(user_input); |
| |
| touch_device_manager()->AddTouchCalibrationData( |
| display::TouchDeviceIdentifier::FromDevice(touchscreen), display.id(), |
| touch_data); |
| |
| EXPECT_FALSE(touch_device_manager() |
| ->GetCalibrationData(touchscreen, display.id()) |
| .IsEmpty()); |
| |
| ui::DeviceDataManager* device_manager = ui::DeviceDataManager::GetInstance(); |
| std::vector<ui::TouchDeviceTransform> transforms; |
| transforms.push_back(CreateTouchDeviceTransform( |
| display.id(), touchscreen.id, |
| GetTouchTransform(display, display, touchscreen))); |
| device_manager->ConfigureTouchDevices(transforms); |
| |
| EXPECT_EQ(kDisplayId1, |
| device_manager->GetTargetDisplayForTouchDevice(kTouchId1)); |
| |
| CheckPointsOfInterests(kTouchId1, kTouchSize, kDisplaySize, kMaxErrorDelta, |
| msg); |
| } |
| |
| TEST_F(TouchTransformControllerTest, DifferentBoundsUserTouchCalibration) { |
| // The display bounds is different from the touch device bounds in this test. |
| const gfx::Size kDisplaySize(1024, 600); |
| const gfx::Size kTouchSize(4096, 4096); |
| const float kAcceptableError = 0.04; |
| gfx::Size kMaxErrorDelta = |
| gfx::ScaleToCeiledSize(kDisplaySize, kAcceptableError); |
| |
| ui::TouchscreenDevice touchscreen = |
| CreateTouchscreenDevice(kTouchId1, kTouchSize); |
| |
| ManagedDisplayInfo display = CreateDisplayInfo( |
| kDisplayId1, touchscreen, |
| gfx::Rect(0, 0, kDisplaySize.width(), kDisplaySize.height())); |
| |
| // Real world data. |
| TouchCalibrationData::CalibrationPointPairQuad user_input = { |
| {std::make_pair(gfx::Point(136, 136), gfx::Point(538, 931)), |
| std::make_pair(gfx::Point(873, 136), gfx::Point(3475, 922)), |
| std::make_pair(gfx::Point(136, 411), gfx::Point(611, 2800)), |
| std::make_pair(gfx::Point(873, 411), gfx::Point(3535, 2949))}}; |
| TouchCalibrationData touch_data(user_input, kDisplaySize); |
| |
| const std::string msg = GetTouchPointString(user_input); |
| |
| touch_device_manager()->AddTouchCalibrationData( |
| display::TouchDeviceIdentifier::FromDevice(touchscreen), display.id(), |
| touch_data); |
| |
| EXPECT_FALSE(touch_device_manager() |
| ->GetCalibrationData(touchscreen, display.id()) |
| .IsEmpty()); |
| |
| ui::DeviceDataManager* device_manager = ui::DeviceDataManager::GetInstance(); |
| |
| std::vector<ui::TouchDeviceTransform> transforms; |
| transforms.push_back(CreateTouchDeviceTransform( |
| display.id(), touchscreen.id, |
| GetTouchTransform(display, display, touchscreen))); |
| device_manager->ConfigureTouchDevices(transforms); |
| |
| EXPECT_EQ(kDisplayId1, |
| device_manager->GetTargetDisplayForTouchDevice(kTouchId1)); |
| |
| CheckPointsOfInterests(kTouchId1, kTouchSize, kDisplaySize, kMaxErrorDelta, |
| msg); |
| } |
| |
| TEST_F(TouchTransformControllerTest, LetterboxingUserTouchCalibration) { |
| // The internal display has native resolution of 2560x1700, and in |
| // mirror mode it is configured as 1920x1200. This is in letterboxing |
| // mode. |
| const gfx::Size kNativeDisplaySize(2560, 1700); |
| const gfx::Size kDisplaySize(1920, 1200); |
| const gfx::Size kTouchSize(1920, 1200); |
| |
| ui::TouchscreenDevice internal_touchscreen = |
| CreateTouchscreenDevice(kTouchId1, kTouchSize); |
| |
| ManagedDisplayInfo internal_display_info = CreateDisplayInfo( |
| kDisplayId1, internal_touchscreen, |
| gfx::Rect(0, 0, kDisplaySize.width(), kDisplaySize.height())); |
| internal_display_info.set_is_aspect_preserving_scaling(true); |
| |
| ManagedDisplayInfo::ManagedDisplayModeList internal_modes; |
| |
| internal_modes.push_back(ManagedDisplayMode( |
| gfx::Size(kNativeDisplaySize.width(), kNativeDisplaySize.height()), 60, |
| false, true)); |
| internal_modes.push_back( |
| ManagedDisplayMode(gfx::Size(kDisplaySize.width(), kDisplaySize.height()), |
| 60, false, false)); |
| internal_display_info.SetManagedDisplayModes(internal_modes); |
| |
| ui::DeviceDataManager* device_manager = ui::DeviceDataManager::GetInstance(); |
| |
| // Assuming the user provided inaccurate inputs during calibration. ie the |
| // user did not tap (100,100) when asked to tap (100,100) due to human error. |
| // Since the display is of size 2560x1700 and the touch device is of size |
| // 1920x1200, the corresponding points have to be scaled. |
| TouchCalibrationData::CalibrationPointPairQuad user_input = {{ |
| std::make_pair(gfx::Point(100, 100), gfx::Point(75, 71)), |
| std::make_pair(gfx::Point(2460, 100), gfx::Point(1845, 71)), |
| std::make_pair(gfx::Point(100, 1600), gfx::Point(75, 1130)), |
| std::make_pair(gfx::Point(2460, 1600), gfx::Point(1845, 1130)), |
| }}; |
| // The calibration was performed at the native display resolution. |
| TouchCalibrationData touch_data(user_input, kNativeDisplaySize); |
| touch_device_manager()->AddTouchCalibrationData( |
| display::TouchDeviceIdentifier::FromDevice(internal_touchscreen), |
| internal_display_info.id(), touch_data); |
| |
| EXPECT_FALSE( |
| touch_device_manager() |
| ->GetCalibrationData(internal_touchscreen, internal_display_info.id()) |
| .IsEmpty()); |
| |
| std::vector<ui::TouchDeviceTransform> transforms; |
| transforms.push_back(CreateTouchDeviceTransform( |
| internal_display_info.id(), internal_touchscreen.id, |
| GetTouchTransform(internal_display_info, internal_display_info, |
| internal_touchscreen))); |
| device_manager->ConfigureTouchDevices(transforms); |
| |
| EXPECT_EQ(kDisplayId1, |
| device_manager->GetTargetDisplayForTouchDevice(kTouchId1)); |
| |
| float x, y; |
| // In letterboxing, there is (1-2560*(1200/1920)/1700)/2 = 2.95% of the |
| // height on both the top & bottom region of the screen is blank. |
| // When touch events coming at Y range [0, 1200), the mapping should be |
| // [0, ~35] ---> < 0 |
| // [~35, ~1165] ---> [0, 1200) |
| // [~1165, 1200] ---> >= 1200 |
| x = 100.0; |
| y = 35.0; |
| device_manager->ApplyTouchTransformer(kTouchId1, &x, &y); |
| EXPECT_NEAR(100, x, 0.5); |
| EXPECT_NEAR(0, y, 0.5); |
| |
| x = 100.0; |
| y = 1165.0; |
| device_manager->ApplyTouchTransformer(kTouchId1, &x, &y); |
| EXPECT_NEAR(100, x, 0.5); |
| EXPECT_NEAR(1200, y, 0.5); |
| } |
| |
| TEST_F(TouchTransformControllerTest, PillarBoxingUserTouchCalibration) { |
| // The internal display has native resolution of 2560x1700, and in |
| // mirror mode it is configured as 1920x1200. This is in letterboxing |
| // mode. |
| const gfx::Size kNativeDisplaySize(2560, 1600); |
| const gfx::Size kDisplaySize(1920, 1400); |
| |
| ui::TouchscreenDevice internal_touchscreen = |
| CreateTouchscreenDevice(kTouchId1, kDisplaySize); |
| |
| ManagedDisplayInfo internal_display_info = CreateDisplayInfo( |
| kDisplayId1, internal_touchscreen, |
| gfx::Rect(0, 0, kDisplaySize.width(), kDisplaySize.height())); |
| internal_display_info.set_is_aspect_preserving_scaling(true); |
| |
| ManagedDisplayInfo::ManagedDisplayModeList internal_modes; |
| |
| internal_modes.push_back(ManagedDisplayMode( |
| gfx::Size(kNativeDisplaySize.width(), kNativeDisplaySize.height()), 60, |
| false, true)); |
| internal_modes.push_back( |
| ManagedDisplayMode(gfx::Size(kDisplaySize.width(), kDisplaySize.height()), |
| 60, false, false)); |
| internal_display_info.SetManagedDisplayModes(internal_modes); |
| |
| ui::DeviceDataManager* device_manager = ui::DeviceDataManager::GetInstance(); |
| |
| // Assuming the user provided accurate inputs during calibration. ie the user |
| // actually tapped (100,100) when asked to tap (100,100) with no human error. |
| // Since the display is of size 2560x1600 and the touch device is of size |
| // 1920x1400, the corresponding points have to be scaled. |
| TouchCalibrationData::CalibrationPointPairQuad user_input = {{ |
| std::make_pair(gfx::Point(100, 100), gfx::Point(75, 88)), |
| std::make_pair(gfx::Point(2460, 100), gfx::Point(1845, 88)), |
| std::make_pair(gfx::Point(100, 1500), gfx::Point(75, 1313)), |
| std::make_pair(gfx::Point(2460, 1500), gfx::Point(1845, 1313)), |
| }}; |
| // The calibration was performed at the native display resolution. |
| TouchCalibrationData touch_data(user_input, kNativeDisplaySize); |
| |
| touch_device_manager()->AddTouchCalibrationData( |
| display::TouchDeviceIdentifier::FromDevice(internal_touchscreen), |
| internal_display_info.id(), touch_data); |
| |
| EXPECT_FALSE( |
| touch_device_manager() |
| ->GetCalibrationData(internal_touchscreen, internal_display_info.id()) |
| .IsEmpty()); |
| |
| std::vector<ui::TouchDeviceTransform> transforms; |
| transforms.push_back(CreateTouchDeviceTransform( |
| internal_display_info.id(), internal_touchscreen.id, |
| GetTouchTransform(internal_display_info, internal_display_info, |
| internal_touchscreen))); |
| device_manager->ConfigureTouchDevices(transforms); |
| |
| EXPECT_EQ(kDisplayId1, |
| device_manager->GetTargetDisplayForTouchDevice(kTouchId1)); |
| |
| float x, y; |
| // In pillarboxing, there is (1-1600*(1920/1400)/2560)/2 = 7.14% of the |
| // width on both the left & region region of the screen is blank. |
| // When touch events coming at X range [0, 1920), the mapping should be |
| // [0, ~137] ---> < 0 |
| // [~137, ~1782] ---> [0, 1920) |
| // [~1782, 1920] ---> >= 1920 |
| x = 137.0; |
| y = 0.0; |
| device_manager->ApplyTouchTransformer(kTouchId1, &x, &y); |
| EXPECT_NEAR(0, x, 0.5); |
| EXPECT_NEAR(0, y, 0.5); |
| |
| x = 1782.0; |
| y = 0.0; |
| device_manager->ApplyTouchTransformer(kTouchId1, &x, &y); |
| EXPECT_NEAR(1920, x, 0.5); |
| EXPECT_NEAR(0, y, 0.5); |
| } |
| |
| } // namespace test |
| } // namespace display |