fixup! Fix for Geolocation webTCT failures
[platform/framework/web/chromium-efl.git] / ash / display / cros_display_config_unittest.cc
1 // Copyright 2018 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ash/display/cros_display_config.h"
6
7 #include "ash/constants/ash_features.h"
8 #include "ash/display/display_alignment_controller.h"
9 #include "ash/display/display_highlight_controller.h"
10 #include "ash/display/screen_orientation_controller.h"
11 #include "ash/display/screen_orientation_controller_test_api.h"
12 #include "ash/display/touch_calibrator_controller.h"
13 #include "ash/shell.h"
14 #include "ash/test/ash_test_base.h"
15 #include "ash/touch/ash_touch_transform_controller.h"
16 #include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h"
17 #include "base/command_line.h"
18 #include "base/containers/contains.h"
19 #include "base/functional/bind.h"
20 #include "base/memory/raw_ptr.h"
21 #include "base/strings/string_number_conversions.h"
22 #include "base/test/scoped_feature_list.h"
23 #include "chromeos/crosapi/mojom/cros_display_config.mojom.h"
24 #include "mojo/public/cpp/bindings/associated_receiver.h"
25 #include "mojo/public/cpp/bindings/associated_remote.h"
26 #include "ui/display/display_switches.h"
27 #include "ui/display/manager/display_manager.h"
28 #include "ui/display/manager/test/touch_transform_controller_test_api.h"
29 #include "ui/display/manager/touch_transform_setter.h"
30 #include "ui/display/test/display_manager_test_api.h"
31 #include "ui/events/devices/device_data_manager_test_api.h"
32 #include "ui/events/devices/touch_device_transform.h"
33 #include "ui/events/devices/touchscreen_device.h"
34
35 namespace ash {
36
37 namespace {
38
39 void SetResult(crosapi::mojom::DisplayConfigResult* result_ptr,
40                base::OnceClosure callback,
41                crosapi::mojom::DisplayConfigResult result) {
42   *result_ptr = result;
43   std::move(callback).Run();
44 }
45
46 void InitExternalTouchDevices(int64_t display_id) {
47   ui::TouchscreenDevice touchdevice(123, ui::InputDeviceType::INPUT_DEVICE_USB,
48                                     std::string("test external touch device"),
49                                     gfx::Size(1000, 1000), 1);
50   ui::DeviceDataManagerTestApi().SetTouchscreenDevices({touchdevice});
51
52   std::vector<ui::TouchDeviceTransform> transforms;
53   ui::TouchDeviceTransform touch_device_transform;
54   touch_device_transform.display_id = display_id;
55   touch_device_transform.device_id = touchdevice.id;
56   transforms.push_back(touch_device_transform);
57   display::test::TouchTransformControllerTestApi(
58       ash::Shell::Get()->touch_transformer_controller())
59       .touch_transform_setter()
60       ->ConfigureTouchDevices(transforms);
61 }
62
63 class TestObserver : public crosapi::mojom::CrosDisplayConfigObserver {
64  public:
65   TestObserver() = default;
66
67   TestObserver(const TestObserver&) = delete;
68   TestObserver& operator=(const TestObserver&) = delete;
69
70   // crosapi::mojom::CrosDisplayConfigObserver:
71   void OnDisplayConfigChanged() override { display_changes_++; }
72
73   int display_changes() const { return display_changes_; }
74   void reset_display_changes() { display_changes_ = 0; }
75
76  private:
77   int display_changes_ = 0;
78 };
79
80 }  // namespace
81
82 class CrosDisplayConfigTest : public AshTestBase {
83  public:
84   CrosDisplayConfigTest() = default;
85
86   CrosDisplayConfigTest(const CrosDisplayConfigTest&) = delete;
87   CrosDisplayConfigTest& operator=(const CrosDisplayConfigTest&) = delete;
88
89   ~CrosDisplayConfigTest() override = default;
90
91   void SetUp() override {
92     scoped_feature_list_.InitAndEnableFeature(features::kDisplayAlignAssist);
93
94     base::CommandLine::ForCurrentProcess()->AppendSwitch(
95         switches::kUseFirstDisplayAsInternal);
96     AshTestBase::SetUp();
97     CHECK(display::Screen::GetScreen());
98     cros_display_config_ = Shell::Get()->cros_display_config();
99   }
100
101   crosapi::mojom::DisplayLayoutInfoPtr GetDisplayLayoutInfo() {
102     crosapi::mojom::DisplayLayoutInfoPtr display_layout_info;
103     base::RunLoop run_loop;
104     cros_display_config_->GetDisplayLayoutInfo(base::BindOnce(
105         [](crosapi::mojom::DisplayLayoutInfoPtr* result_ptr,
106            base::OnceClosure callback,
107            crosapi::mojom::DisplayLayoutInfoPtr result) {
108           *result_ptr = std::move(result);
109           std::move(callback).Run();
110         },
111         &display_layout_info, run_loop.QuitClosure()));
112     run_loop.Run();
113     return display_layout_info;
114   }
115
116   crosapi::mojom::DisplayConfigResult SetDisplayLayoutInfo(
117       crosapi::mojom::DisplayLayoutInfoPtr display_layout_info) {
118     crosapi::mojom::DisplayConfigResult result;
119     base::RunLoop run_loop;
120     cros_display_config_->SetDisplayLayoutInfo(
121         std::move(display_layout_info),
122         base::BindOnce(&SetResult, &result, run_loop.QuitClosure()));
123     run_loop.Run();
124     return result;
125   }
126
127   std::vector<crosapi::mojom::DisplayUnitInfoPtr> GetDisplayUnitInfoList() {
128     std::vector<crosapi::mojom::DisplayUnitInfoPtr> display_info_list;
129     base::RunLoop run_loop;
130     cros_display_config_->GetDisplayUnitInfoList(
131         /*single_unified=*/false,
132         base::BindOnce(
133             [](std::vector<crosapi::mojom::DisplayUnitInfoPtr>* result_ptr,
134                base::OnceClosure callback,
135                std::vector<crosapi::mojom::DisplayUnitInfoPtr> result) {
136               *result_ptr = std::move(result);
137               std::move(callback).Run();
138             },
139             &display_info_list, run_loop.QuitClosure()));
140     run_loop.Run();
141     return display_info_list;
142   }
143
144   crosapi::mojom::DisplayConfigResult SetDisplayProperties(
145       const std::string& id,
146       crosapi::mojom::DisplayConfigPropertiesPtr properties) {
147     crosapi::mojom::DisplayConfigResult result;
148     base::RunLoop run_loop;
149     cros_display_config_->SetDisplayProperties(
150         id, std::move(properties), crosapi::mojom::DisplayConfigSource::kUser,
151         base::BindOnce(&SetResult, &result, run_loop.QuitClosure()));
152     run_loop.Run();
153     return result;
154   }
155
156   bool OverscanCalibration(int64_t id,
157                            crosapi::mojom::DisplayConfigOperation op,
158                            const absl::optional<gfx::Insets>& delta) {
159     crosapi::mojom::DisplayConfigResult result;
160     base::RunLoop run_loop;
161     cros_display_config()->OverscanCalibration(
162         base::NumberToString(id), op, delta,
163         base::BindOnce(&SetResult, &result, run_loop.QuitClosure()));
164     run_loop.Run();
165     return result == crosapi::mojom::DisplayConfigResult::kSuccess;
166   }
167
168   bool DisplayExists(int64_t display_id) {
169     const display::Display& display =
170         display_manager()->GetDisplayForId(display_id);
171     return display.id() != display::kInvalidDisplayId;
172   }
173
174   crosapi::mojom::TouchCalibrationPtr GetDefaultCalibration() {
175     auto calibration = crosapi::mojom::TouchCalibration::New();
176     for (int i = 0; i < 4; ++i)
177       calibration->pairs.emplace_back(
178           crosapi::mojom::TouchCalibrationPair::New());
179     return calibration;
180   }
181
182   bool StartTouchCalibration(const std::string& display_id) {
183     return CallTouchCalibration(
184         display_id, crosapi::mojom::DisplayConfigOperation::kStart, nullptr);
185   }
186
187   bool CompleteCustomTouchCalibration(
188       const std::string& display_id,
189       crosapi::mojom::TouchCalibrationPtr calibration) {
190     return CallTouchCalibration(
191         display_id, crosapi::mojom::DisplayConfigOperation::kComplete,
192         std::move(calibration));
193   }
194
195   bool CallTouchCalibration(const std::string& id,
196                             crosapi::mojom::DisplayConfigOperation op,
197                             crosapi::mojom::TouchCalibrationPtr calibration) {
198     crosapi::mojom::DisplayConfigResult result;
199     base::RunLoop run_loop;
200     cros_display_config_->TouchCalibration(
201         id, op, std::move(calibration),
202         base::BindOnce(&SetResult, &result, run_loop.QuitClosure()));
203     run_loop.Run();
204     return result == crosapi::mojom::DisplayConfigResult::kSuccess;
205   }
206
207   bool IsTouchCalibrationActive() {
208     TouchCalibratorController* touch_calibrator =
209         cros_display_config_->touch_calibrator_for_test();
210     return touch_calibrator && touch_calibrator->IsCalibrating();
211   }
212
213   void HighlightDisplay(int64_t id) {
214     cros_display_config_->HighlightDisplay(id);
215   }
216
217   void DragDisplayDelta(int64_t id, int32_t delta_x, int32_t delta_y) {
218     cros_display_config_->DragDisplayDelta(id, delta_x, delta_y);
219   }
220
221   bool PreviewIndicatorsExist() {
222     return !Shell::Get()
223                 ->display_alignment_controller()
224                 ->GetActiveIndicatorsForTesting()
225                 .empty();
226   }
227
228   CrosDisplayConfig* cros_display_config() { return cros_display_config_; }
229
230  private:
231   raw_ptr<CrosDisplayConfig, DanglingUntriaged | ExperimentalAsh>
232       cros_display_config_ = nullptr;
233
234   base::test::ScopedFeatureList scoped_feature_list_;
235 };
236
237 TEST_F(CrosDisplayConfigTest, OnDisplayConfigChanged) {
238   TestObserver observer;
239   mojo::AssociatedRemote<crosapi::mojom::CrosDisplayConfigObserver>
240       observer_remote;
241   mojo::AssociatedReceiver<crosapi::mojom::CrosDisplayConfigObserver> receiver(
242       &observer, observer_remote.BindNewEndpointAndPassDedicatedReceiver());
243   cros_display_config()->AddObserver(observer_remote.Unbind());
244   base::RunLoop().RunUntilIdle();
245
246   // Adding one display should trigger one notification.
247   UpdateDisplay("500x400");
248   base::RunLoop().RunUntilIdle();
249   EXPECT_EQ(1, observer.display_changes());
250   observer.reset_display_changes();
251
252   // Adding two displays should trigger two notification.
253   UpdateDisplay("500x400,500x400");
254   base::RunLoop().RunUntilIdle();
255   EXPECT_EQ(2, observer.display_changes());
256 }
257
258 TEST_F(CrosDisplayConfigTest, GetDisplayLayoutInfo) {
259   UpdateDisplay("500x400,500x400,500x400");
260   std::vector<display::Display> displays =
261       display::Screen::GetScreen()->GetAllDisplays();
262   ASSERT_EQ(3u, displays.size());
263
264   crosapi::mojom::DisplayLayoutInfoPtr display_layout_info =
265       GetDisplayLayoutInfo();
266
267   ASSERT_TRUE(display_layout_info);
268   const std::vector<crosapi::mojom::DisplayLayoutPtr>& layouts =
269       *display_layout_info->layouts;
270   ASSERT_EQ(2u, layouts.size());
271
272   EXPECT_EQ(base::NumberToString(displays[1].id()), layouts[0]->id);
273   EXPECT_EQ(base::NumberToString(displays[0].id()), layouts[0]->parent_id);
274   EXPECT_EQ(crosapi::mojom::DisplayLayoutPosition::kRight,
275             layouts[0]->position);
276   EXPECT_EQ(0, layouts[0]->offset);
277
278   EXPECT_EQ(base::NumberToString(displays[2].id()), layouts[1]->id);
279   EXPECT_EQ(layouts[0]->id, layouts[1]->parent_id);
280   EXPECT_EQ(crosapi::mojom::DisplayLayoutPosition::kRight,
281             layouts[1]->position);
282   EXPECT_EQ(0, layouts[1]->offset);
283 }
284
285 TEST_F(CrosDisplayConfigTest, FailToSetLayoutUnifiedWithOneDisplay) {
286   UpdateDisplay("500x400");
287   EXPECT_FALSE(display_manager()->IsInUnifiedMode());
288
289   // Enable unified desktop and expect to fail due to not enough connected
290   // displays.
291   auto properties = crosapi::mojom::DisplayLayoutInfo::New();
292   properties->layout_mode = crosapi::mojom::DisplayLayoutMode::kUnified;
293   crosapi::mojom::DisplayConfigResult result =
294       SetDisplayLayoutInfo(std::move(properties));
295   EXPECT_EQ(crosapi::mojom::DisplayConfigResult::kSingleDisplayError, result);
296   EXPECT_FALSE(display_manager()->IsInUnifiedMode());
297 }
298
299 TEST_F(CrosDisplayConfigTest, SetLayoutUnified) {
300   UpdateDisplay("500x400,500x400");
301   EXPECT_FALSE(display_manager()->IsInUnifiedMode());
302
303   // Enable unified desktop. Enables unified mode.
304   cros_display_config()->SetUnifiedDesktopEnabled(true);
305   base::RunLoop().RunUntilIdle();
306   EXPECT_TRUE(display_manager()->IsInUnifiedMode());
307
308   // Disable unified mode.
309   auto properties = crosapi::mojom::DisplayLayoutInfo::New();
310   properties->layout_mode = crosapi::mojom::DisplayLayoutMode::kNormal;
311   crosapi::mojom::DisplayConfigResult result =
312       SetDisplayLayoutInfo(std::move(properties));
313   EXPECT_EQ(crosapi::mojom::DisplayConfigResult::kSuccess, result);
314   EXPECT_FALSE(display_manager()->IsInUnifiedMode());
315
316   // Enable unified mode.
317   properties = crosapi::mojom::DisplayLayoutInfo::New();
318   properties->layout_mode = crosapi::mojom::DisplayLayoutMode::kUnified;
319   result = SetDisplayLayoutInfo(std::move(properties));
320   EXPECT_EQ(crosapi::mojom::DisplayConfigResult::kSuccess, result);
321   EXPECT_TRUE(display_manager()->IsInUnifiedMode());
322
323   // Restore extended mode.
324   cros_display_config()->SetUnifiedDesktopEnabled(false);
325   EXPECT_FALSE(display_manager()->IsInUnifiedMode());
326 }
327
328 TEST_F(CrosDisplayConfigTest, FailToSetLayoutMirroredDefaultWithOneDisplay) {
329   UpdateDisplay("500x400");
330   EXPECT_FALSE(display_manager()->IsInMirrorMode());
331
332   // Enable default mirror mode and expect to fail due to not enough connected
333   // displays.
334   auto properties = crosapi::mojom::DisplayLayoutInfo::New();
335   properties->layout_mode = crosapi::mojom::DisplayLayoutMode::kMirrored;
336   crosapi::mojom::DisplayConfigResult result =
337       SetDisplayLayoutInfo(std::move(properties));
338   EXPECT_EQ(crosapi::mojom::DisplayConfigResult::kSingleDisplayError, result);
339   EXPECT_FALSE(display_manager()->IsInMirrorMode());
340
341   display::DisplayIdList id_list =
342       display_manager()->GetMirroringDestinationDisplayIdList();
343   ASSERT_TRUE(id_list.empty());
344 }
345
346 TEST_F(CrosDisplayConfigTest, SetLayoutMirroredDefault) {
347   UpdateDisplay("500x400,500x400,500x400");
348
349   auto properties = crosapi::mojom::DisplayLayoutInfo::New();
350   properties->layout_mode = crosapi::mojom::DisplayLayoutMode::kMirrored;
351   crosapi::mojom::DisplayConfigResult result =
352       SetDisplayLayoutInfo(std::move(properties));
353   EXPECT_EQ(crosapi::mojom::DisplayConfigResult::kSuccess, result);
354   EXPECT_TRUE(display_manager()->IsInMirrorMode());
355   display::DisplayIdList id_list =
356       display_manager()->GetMirroringDestinationDisplayIdList();
357   ASSERT_EQ(2u, id_list.size());
358
359   properties = crosapi::mojom::DisplayLayoutInfo::New();
360   properties->layout_mode = crosapi::mojom::DisplayLayoutMode::kNormal;
361   result = SetDisplayLayoutInfo(std::move(properties));
362   EXPECT_EQ(crosapi::mojom::DisplayConfigResult::kSuccess, result);
363   EXPECT_FALSE(display_manager()->IsInMirrorMode());
364 }
365
366 TEST_F(CrosDisplayConfigTest, FailToSetLayoutMirroredMixedWithOneDisplay) {
367   UpdateDisplay("500x400");
368   EXPECT_FALSE(display_manager()->IsInMirrorMode());
369
370   std::vector<display::Display> displays =
371       display::Screen::GetScreen()->GetAllDisplays();
372   ASSERT_EQ(1u, displays.size());
373
374   // Enable mixed mirror mode and expect to fail due to not enough connected
375   // displays.
376   auto properties = crosapi::mojom::DisplayLayoutInfo::New();
377   properties->layout_mode = crosapi::mojom::DisplayLayoutMode::kMirrored;
378   properties->mirror_source_id = base::NumberToString(displays[0].id());
379   properties->mirror_destination_ids =
380       absl::make_optional<std::vector<std::string>>();
381
382   crosapi::mojom::DisplayConfigResult result =
383       SetDisplayLayoutInfo(std::move(properties));
384   EXPECT_EQ(crosapi::mojom::DisplayConfigResult::kSingleDisplayError, result);
385   EXPECT_FALSE(display_manager()->IsInMirrorMode());
386
387   display::DisplayIdList id_list =
388       display_manager()->GetMirroringDestinationDisplayIdList();
389   ASSERT_TRUE(id_list.empty());
390 }
391
392 TEST_F(CrosDisplayConfigTest, SetLayoutMirroredMixed) {
393   UpdateDisplay("500x400,500x400,500x400,500x400");
394
395   std::vector<display::Display> displays =
396       display::Screen::GetScreen()->GetAllDisplays();
397   ASSERT_EQ(4u, displays.size());
398
399   auto properties = crosapi::mojom::DisplayLayoutInfo::New();
400   properties->layout_mode = crosapi::mojom::DisplayLayoutMode::kMirrored;
401   properties->mirror_source_id = base::NumberToString(displays[0].id());
402   properties->mirror_destination_ids =
403       absl::make_optional<std::vector<std::string>>(
404           {base::NumberToString(displays[1].id()),
405            base::NumberToString(displays[3].id())});
406   crosapi::mojom::DisplayConfigResult result =
407       SetDisplayLayoutInfo(std::move(properties));
408   EXPECT_EQ(crosapi::mojom::DisplayConfigResult::kSuccess, result);
409   EXPECT_TRUE(display_manager()->IsInMirrorMode());
410   display::DisplayIdList id_list =
411       display_manager()->GetMirroringDestinationDisplayIdList();
412   ASSERT_EQ(2u, id_list.size());
413   EXPECT_TRUE(base::Contains(id_list, displays[1].id()));
414   EXPECT_TRUE(base::Contains(id_list, displays[3].id()));
415 }
416
417 TEST_F(CrosDisplayConfigTest, GetDisplayUnitInfoListBasic) {
418   UpdateDisplay("500x600,400x520");
419   std::vector<crosapi::mojom::DisplayUnitInfoPtr> result =
420       GetDisplayUnitInfoList();
421   ASSERT_EQ(2u, result.size());
422
423   int64_t display_id;
424   ASSERT_TRUE(base::StringToInt64(result[0]->id, &display_id));
425   ASSERT_TRUE(DisplayExists(display_id));
426   const crosapi::mojom::DisplayUnitInfo& info_0 = *result[0];
427   EXPECT_TRUE(info_0.is_primary);
428   EXPECT_TRUE(info_0.is_internal);
429   EXPECT_TRUE(info_0.is_enabled);
430   EXPECT_FALSE(info_0.is_auto_rotation_allowed);
431   EXPECT_FALSE(info_0.has_touch_support);
432   EXPECT_FALSE(info_0.has_accelerometer_support);
433   EXPECT_EQ(96, info_0.dpi_x);
434   EXPECT_EQ(96, info_0.dpi_y);
435   EXPECT_EQ(crosapi::mojom::DisplayRotationOptions::kZeroDegrees,
436             info_0.rotation_options);
437   EXPECT_EQ(gfx::Rect(0, 0, 500, 600), info_0.bounds);
438   EXPECT_EQ(gfx::Insets(), info_0.overscan);
439
440   ASSERT_TRUE(base::StringToInt64(result[1]->id, &display_id));
441   ASSERT_TRUE(DisplayExists(display_id));
442   const crosapi::mojom::DisplayUnitInfo& info_1 = *result[1];
443   EXPECT_EQ(display_manager()->GetDisplayNameForId(display_id), info_1.name);
444   // Second display is left of the primary display whose width 500.
445   EXPECT_EQ(gfx::Rect(500, 0, 400, 520), info_1.bounds);
446   EXPECT_EQ(gfx::Insets(), info_1.overscan);
447   EXPECT_EQ(crosapi::mojom::DisplayRotationOptions::kZeroDegrees,
448             info_1.rotation_options);
449   EXPECT_FALSE(info_1.is_primary);
450   EXPECT_FALSE(info_1.is_internal);
451   EXPECT_TRUE(info_1.is_enabled);
452   EXPECT_EQ(96, info_1.dpi_x);
453   EXPECT_EQ(96, info_1.dpi_y);
454 }
455
456 TEST_F(CrosDisplayConfigTest, GetDisplayUnitInfoListZoomFactor) {
457   UpdateDisplay("1024x512,1024x512");
458   std::vector<crosapi::mojom::DisplayUnitInfoPtr> result =
459       GetDisplayUnitInfoList();
460   ASSERT_EQ(2u, result.size());
461
462   const crosapi::mojom::DisplayUnitInfo& info_0 = *result[0];
463   EXPECT_EQ(1.0, info_0.display_zoom_factor);
464   const std::vector<double>& zoom_factors =
465       info_0.available_display_zoom_factors;
466   EXPECT_EQ(9u, zoom_factors.size());
467   EXPECT_FLOAT_EQ(0.90f, zoom_factors[0]);
468   EXPECT_FLOAT_EQ(0.95f, zoom_factors[1]);
469   EXPECT_FLOAT_EQ(1.f, zoom_factors[2]);
470   EXPECT_FLOAT_EQ(1.05f, zoom_factors[3]);
471   EXPECT_FLOAT_EQ(1.10f, zoom_factors[4]);
472   EXPECT_FLOAT_EQ(1.15f, zoom_factors[5]);
473   EXPECT_FLOAT_EQ(1.20f, zoom_factors[6]);
474   EXPECT_FLOAT_EQ(1.25f, zoom_factors[7]);
475   EXPECT_FLOAT_EQ(1.30f, zoom_factors[8]);
476 }
477
478 TEST_F(CrosDisplayConfigTest, SetDisplayPropertiesPrimary) {
479   UpdateDisplay("1200x600,600x1000");
480   int64_t primary_id = display::Screen::GetScreen()->GetPrimaryDisplay().id();
481   int64_t secondary_id = display::test::DisplayManagerTestApi(display_manager())
482                              .GetSecondaryDisplay()
483                              .id();
484   ASSERT_NE(primary_id, secondary_id);
485
486   auto properties = crosapi::mojom::DisplayConfigProperties::New();
487   properties->set_primary = true;
488   crosapi::mojom::DisplayConfigResult result = SetDisplayProperties(
489       base::NumberToString(secondary_id), std::move(properties));
490   EXPECT_EQ(crosapi::mojom::DisplayConfigResult::kSuccess, result);
491
492   // secondary display should now be primary.
493   primary_id = display::Screen::GetScreen()->GetPrimaryDisplay().id();
494   EXPECT_EQ(primary_id, secondary_id);
495 }
496
497 TEST_F(CrosDisplayConfigTest, SetDisplayPropertiesOverscan) {
498   UpdateDisplay("1200x600,600x1000*2");
499   const display::Display& secondary =
500       display::test::DisplayManagerTestApi(display_manager())
501           .GetSecondaryDisplay();
502
503   auto properties = crosapi::mojom::DisplayConfigProperties::New();
504   properties->overscan = gfx::Insets::TLBR(199, 20, 51, 130);
505   crosapi::mojom::DisplayConfigResult result = SetDisplayProperties(
506       base::NumberToString(secondary.id()), std::move(properties));
507   EXPECT_EQ(crosapi::mojom::DisplayConfigResult::kSuccess, result);
508   EXPECT_EQ(gfx::Rect(1200, 0, 150, 250), secondary.bounds());
509   const gfx::Insets overscan =
510       display_manager()->GetOverscanInsets(secondary.id());
511   EXPECT_EQ(199, overscan.top());
512   EXPECT_EQ(20, overscan.left());
513   EXPECT_EQ(51, overscan.bottom());
514   EXPECT_EQ(130, overscan.right());
515 }
516
517 TEST_F(CrosDisplayConfigTest, SetDisplayPropertiesRotation) {
518   UpdateDisplay("1200x600,600x1000*2");
519   const display::Display& secondary =
520       display::test::DisplayManagerTestApi(display_manager())
521           .GetSecondaryDisplay();
522
523   crosapi::mojom::DisplayConfigResult result;
524
525   auto properties = crosapi::mojom::DisplayConfigProperties::New();
526   properties->rotation = crosapi::mojom::DisplayRotation::New(
527       crosapi::mojom::DisplayRotationOptions::k90Degrees);
528   result = SetDisplayProperties(base::NumberToString(secondary.id()),
529                                 std::move(properties));
530   EXPECT_EQ(crosapi::mojom::DisplayConfigResult::kSuccess, result);
531   EXPECT_EQ(gfx::Rect(1200, 0, 500, 300), secondary.bounds());
532   EXPECT_EQ(display::Display::ROTATE_90, secondary.rotation());
533
534   properties = crosapi::mojom::DisplayConfigProperties::New();
535   properties->rotation = crosapi::mojom::DisplayRotation::New(
536       crosapi::mojom::DisplayRotationOptions::k270Degrees);
537   result = SetDisplayProperties(base::NumberToString(secondary.id()),
538                                 std::move(properties));
539   EXPECT_EQ(crosapi::mojom::DisplayConfigResult::kSuccess, result);
540   EXPECT_EQ(gfx::Rect(1200, 0, 500, 300), secondary.bounds());
541   EXPECT_EQ(display::Display::ROTATE_270, secondary.rotation());
542
543   // Test setting primary and rotating.
544   properties = crosapi::mojom::DisplayConfigProperties::New();
545   properties->set_primary = true;
546   properties->rotation = crosapi::mojom::DisplayRotation::New(
547       crosapi::mojom::DisplayRotationOptions::k180Degrees);
548   result = SetDisplayProperties(base::NumberToString(secondary.id()),
549                                 std::move(properties));
550   EXPECT_EQ(crosapi::mojom::DisplayConfigResult::kSuccess, result);
551   const display::Display& primary =
552       display::Screen::GetScreen()->GetPrimaryDisplay();
553   EXPECT_EQ(secondary.id(), primary.id());
554   EXPECT_EQ(gfx::Rect(0, 0, 300, 500), primary.bounds());
555   EXPECT_EQ(display::Display::ROTATE_180, primary.rotation());
556 }
557
558 TEST_F(CrosDisplayConfigTest, SetDisplayPropertiesBoundsOrigin) {
559   UpdateDisplay("1200x600,520x400");
560   const display::Display& secondary =
561       display::test::DisplayManagerTestApi(display_manager())
562           .GetSecondaryDisplay();
563
564   crosapi::mojom::DisplayConfigResult result;
565
566   auto properties = crosapi::mojom::DisplayConfigProperties::New();
567   properties->bounds_origin = gfx::Point({-520, 50});
568   result = SetDisplayProperties(base::NumberToString(secondary.id()),
569                                 std::move(properties));
570   EXPECT_EQ(crosapi::mojom::DisplayConfigResult::kSuccess, result);
571   EXPECT_EQ(gfx::Rect(-520, 50, 520, 400), secondary.bounds());
572
573   properties = crosapi::mojom::DisplayConfigProperties::New();
574   properties->bounds_origin = gfx::Point({1200, 100});
575   result = SetDisplayProperties(base::NumberToString(secondary.id()),
576                                 std::move(properties));
577   EXPECT_EQ(crosapi::mojom::DisplayConfigResult::kSuccess, result);
578   EXPECT_EQ(gfx::Rect(1200, 100, 520, 400), secondary.bounds());
579
580   properties = crosapi::mojom::DisplayConfigProperties::New();
581   properties->bounds_origin = gfx::Point({1100, -400});
582   result = SetDisplayProperties(base::NumberToString(secondary.id()),
583                                 std::move(properties));
584   EXPECT_EQ(crosapi::mojom::DisplayConfigResult::kSuccess, result);
585   EXPECT_EQ(gfx::Rect(1100, -400, 520, 400), secondary.bounds());
586
587   properties = crosapi::mojom::DisplayConfigProperties::New();
588   properties->bounds_origin = gfx::Point({-350, 600});
589   result = SetDisplayProperties(base::NumberToString(secondary.id()),
590                                 std::move(properties));
591   EXPECT_EQ(crosapi::mojom::DisplayConfigResult::kSuccess, result);
592   EXPECT_EQ(gfx::Rect(-350, 600, 520, 400), secondary.bounds());
593 }
594
595 TEST_F(CrosDisplayConfigTest, SetDisplayPropertiesDisplayZoomFactor) {
596   static std::string configs[] = {
597       "1200x600, 1600x1000#1600x1000",  // landscape
598       "600x1200, 1000x1600#1000x1600",  // portrait
599   };
600   for (auto config : configs) {
601     SCOPED_TRACE(config);
602     UpdateDisplay(config);
603     display::DisplayIdList display_id_list =
604         display_manager()->GetConnectedDisplayIdList();
605
606     const float zoom_factor_1 = 1.23f;
607     const float zoom_factor_2 = 2.34f;
608
609     display_manager()->UpdateZoomFactor(display_id_list[0], zoom_factor_2);
610     display_manager()->UpdateZoomFactor(display_id_list[1], zoom_factor_1);
611
612     EXPECT_EQ(
613         zoom_factor_2,
614         display_manager()->GetDisplayInfo(display_id_list[0]).zoom_factor());
615     EXPECT_EQ(
616         zoom_factor_1,
617         display_manager()->GetDisplayInfo(display_id_list[1]).zoom_factor());
618
619     // Set zoom factor for display 0, should not affect display 1.
620     auto properties = crosapi::mojom::DisplayConfigProperties::New();
621     properties->display_zoom_factor = zoom_factor_1;
622     crosapi::mojom::DisplayConfigResult result = SetDisplayProperties(
623         base::NumberToString(display_id_list[0]), std::move(properties));
624     EXPECT_EQ(crosapi::mojom::DisplayConfigResult::kSuccess, result);
625     EXPECT_EQ(
626         zoom_factor_1,
627         display_manager()->GetDisplayInfo(display_id_list[0]).zoom_factor());
628     EXPECT_EQ(
629         zoom_factor_1,
630         display_manager()->GetDisplayInfo(display_id_list[1]).zoom_factor());
631
632     // Set zoom factor for display 1.
633     properties = crosapi::mojom::DisplayConfigProperties::New();
634     properties->display_zoom_factor = zoom_factor_2;
635     result = SetDisplayProperties(base::NumberToString(display_id_list[1]),
636                                   std::move(properties));
637     EXPECT_EQ(crosapi::mojom::DisplayConfigResult::kSuccess, result);
638     EXPECT_EQ(
639         zoom_factor_1,
640         display_manager()->GetDisplayInfo(display_id_list[0]).zoom_factor());
641     EXPECT_EQ(
642         zoom_factor_2,
643         display_manager()->GetDisplayInfo(display_id_list[1]).zoom_factor());
644
645     // Invalid zoom factor should fail.
646     const float invalid_zoom_factor = 0.01f;
647     properties = crosapi::mojom::DisplayConfigProperties::New();
648     properties->display_zoom_factor = invalid_zoom_factor;
649     result = SetDisplayProperties(base::NumberToString(display_id_list[1]),
650                                   std::move(properties));
651     EXPECT_EQ(
652         crosapi::mojom::DisplayConfigResult::kPropertyValueOutOfRangeError,
653         result);
654     EXPECT_EQ(
655         zoom_factor_2,
656         display_manager()->GetDisplayInfo(display_id_list[1]).zoom_factor());
657   }
658 }
659
660 TEST_F(CrosDisplayConfigTest, SetDisplayMode) {
661   UpdateDisplay("1024x512,1024x512");
662   std::vector<crosapi::mojom::DisplayUnitInfoPtr> result =
663       GetDisplayUnitInfoList();
664   ASSERT_EQ(2u, result.size());
665   // Internal display has just one mode.
666   EXPECT_EQ(0, result[0]->selected_display_mode_index);
667   ASSERT_EQ(1u, result[0]->available_display_modes.size());
668
669   auto properties = crosapi::mojom::DisplayConfigProperties::New();
670   auto display_mode = result[0]->available_display_modes[0].Clone();
671   properties->display_mode = std::move(display_mode);
672   ASSERT_EQ(crosapi::mojom::DisplayConfigResult::kSuccess,
673             SetDisplayProperties(result[0]->id, std::move(properties)));
674
675   result = GetDisplayUnitInfoList();
676   ASSERT_EQ(2u, result.size());
677   EXPECT_EQ(0, result[0]->selected_display_mode_index);
678 }
679
680 TEST_F(CrosDisplayConfigTest, OverscanCalibration) {
681   UpdateDisplay("1200x600");
682   int64_t id = display::Screen::GetScreen()->GetPrimaryDisplay().id();
683   ASSERT_NE(display::kInvalidDisplayId, id);
684
685   // Test that kAdjust succeeds after kComplete call.
686   EXPECT_TRUE(OverscanCalibration(
687       id, crosapi::mojom::DisplayConfigOperation::kStart, absl::nullopt));
688   EXPECT_EQ(gfx::Insets(), display_manager()->GetOverscanInsets(id));
689
690   gfx::Insets insets(10);
691   EXPECT_TRUE(OverscanCalibration(
692       id, crosapi::mojom::DisplayConfigOperation::kAdjust, insets));
693   // Adjust has no effect until Complete.
694   EXPECT_EQ(gfx::Insets(), display_manager()->GetOverscanInsets(id));
695
696   EXPECT_TRUE(OverscanCalibration(
697       id, crosapi::mojom::DisplayConfigOperation::kComplete, absl::nullopt));
698   gfx::Insets overscan = display_manager()->GetOverscanInsets(id);
699   EXPECT_EQ(insets, overscan)
700       << "Overscan: " << overscan.ToString() << " != " << insets.ToString();
701
702   // Test that kReset clears restores previous insets.
703
704   // Start clears any overscan values.
705   EXPECT_TRUE(OverscanCalibration(
706       id, crosapi::mojom::DisplayConfigOperation::kStart, absl::nullopt));
707   EXPECT_EQ(gfx::Insets(), display_manager()->GetOverscanInsets(id));
708
709   // Reset + Complete restores previously set insets.
710   EXPECT_TRUE(OverscanCalibration(
711       id, crosapi::mojom::DisplayConfigOperation::kReset, absl::nullopt));
712   EXPECT_EQ(gfx::Insets(), display_manager()->GetOverscanInsets(id));
713   EXPECT_TRUE(OverscanCalibration(
714       id, crosapi::mojom::DisplayConfigOperation::kComplete, absl::nullopt));
715   EXPECT_EQ(insets, display_manager()->GetOverscanInsets(id));
716
717   // Additional complete call should fail.
718   EXPECT_FALSE(OverscanCalibration(
719       id, crosapi::mojom::DisplayConfigOperation::kComplete, absl::nullopt));
720 }
721
722 TEST_F(CrosDisplayConfigTest, CustomTouchCalibrationInternal) {
723   UpdateDisplay("1200x600,600x1000*2");
724   const int64_t internal_display_id =
725       display::test::DisplayManagerTestApi(display_manager())
726           .SetFirstDisplayAsInternalDisplay();
727
728   InitExternalTouchDevices(internal_display_id);
729
730   EXPECT_FALSE(
731       StartTouchCalibration(base::NumberToString(internal_display_id)));
732   EXPECT_FALSE(IsTouchCalibrationActive());
733 }
734
735 TEST_F(CrosDisplayConfigTest, CustomTouchCalibrationWithoutStart) {
736   UpdateDisplay("1200x600,600x1000*2");
737   EXPECT_FALSE(IsTouchCalibrationActive());
738 }
739
740 TEST_F(CrosDisplayConfigTest, CustomTouchCalibrationNonTouchDisplay) {
741   UpdateDisplay("1200x600,600x1000*2");
742
743   const int64_t internal_display_id =
744       display::test::DisplayManagerTestApi(display_manager())
745           .SetFirstDisplayAsInternalDisplay();
746
747   display::DisplayIdList display_id_list =
748       display_manager()->GetConnectedDisplayIdList();
749
750   // Pick the non internal display Id.
751   const int64_t display_id = display_id_list[0] == internal_display_id
752                                  ? display_id_list[1]
753                                  : display_id_list[0];
754
755   ui::DeviceDataManagerTestApi().SetTouchscreenDevices({});
756   std::string id = base::NumberToString(display_id);
757
758   // Since no external touch devices are present, the calibration should fail.
759   EXPECT_FALSE(StartTouchCalibration(id));
760
761   // If an external touch device is present, the calibration should proceed.
762   InitExternalTouchDevices(display_id);
763   EXPECT_TRUE(StartTouchCalibration(id));
764   EXPECT_TRUE(IsTouchCalibrationActive());
765 }
766
767 TEST_F(CrosDisplayConfigTest, CustomTouchCalibrationInvalidPoints) {
768   UpdateDisplay("1200x600,600x1000*2");
769
770   const int64_t internal_display_id =
771       display::test::DisplayManagerTestApi(display_manager())
772           .SetFirstDisplayAsInternalDisplay();
773
774   display::DisplayIdList display_id_list =
775       display_manager()->GetConnectedDisplayIdList();
776
777   // Pick the non internal display Id.
778   const int64_t display_id = display_id_list[0] == internal_display_id
779                                  ? display_id_list[1]
780                                  : display_id_list[0];
781
782   InitExternalTouchDevices(display_id);
783
784   std::string id = base::NumberToString(display_id);
785
786   EXPECT_TRUE(StartTouchCalibration(id));
787   crosapi::mojom::TouchCalibrationPtr calibration = GetDefaultCalibration();
788   calibration->pairs[0]->display_point.set_x(-1);
789   EXPECT_FALSE(CompleteCustomTouchCalibration(id, std::move(calibration)));
790
791   EXPECT_TRUE(StartTouchCalibration(id));
792   calibration = GetDefaultCalibration();
793   calibration->bounds.set_width(1);
794   calibration->pairs[0]->display_point.set_x(2);
795   EXPECT_FALSE(CompleteCustomTouchCalibration(id, std::move(calibration)));
796 }
797
798 TEST_F(CrosDisplayConfigTest, CustomTouchCalibrationSuccess) {
799   UpdateDisplay("1200x600,600x1000*2");
800
801   const int64_t internal_display_id =
802       display::test::DisplayManagerTestApi(display_manager())
803           .SetFirstDisplayAsInternalDisplay();
804
805   display::DisplayIdList display_id_list =
806       display_manager()->GetConnectedDisplayIdList();
807
808   // Pick the non internal display Id.
809   const int64_t display_id = display_id_list[0] == internal_display_id
810                                  ? display_id_list[1]
811                                  : display_id_list[0];
812
813   InitExternalTouchDevices(display_id);
814
815   std::string id = base::NumberToString(display_id);
816
817   EXPECT_TRUE(StartTouchCalibration(id));
818   EXPECT_TRUE(IsTouchCalibrationActive());
819   crosapi::mojom::TouchCalibrationPtr calibration = GetDefaultCalibration();
820   EXPECT_TRUE(CompleteCustomTouchCalibration(id, std::move(calibration)));
821 }
822
823 TEST_F(CrosDisplayConfigTest, TabletModeAutoRotationInternalOnly) {
824   UpdateDisplay("500x600,400x520");
825
826   auto* screen_orientation_controller =
827       Shell::Get()->screen_orientation_controller();
828   EXPECT_FALSE(screen_orientation_controller->user_rotation_locked());
829
830   TabletModeControllerTestApi tablet_mode_controller_test_api;
831   ScreenOrientationControllerTestApi screen_orientation_controller_test_api(
832       screen_orientation_controller);
833   tablet_mode_controller_test_api.EnterTabletMode();
834   EXPECT_TRUE(tablet_mode_controller_test_api.IsInPhysicalTabletState());
835   EXPECT_TRUE(screen_orientation_controller_test_api.IsAutoRotationAllowed());
836   EXPECT_TRUE(tablet_mode_controller_test_api.IsTabletModeStarted());
837
838   std::vector<crosapi::mojom::DisplayUnitInfoPtr> result =
839       GetDisplayUnitInfoList();
840   ASSERT_EQ(2u, result.size());
841
842   int64_t display_id;
843   ASSERT_TRUE(base::StringToInt64(result[0]->id, &display_id));
844   ASSERT_TRUE(DisplayExists(display_id));
845   const crosapi::mojom::DisplayUnitInfo& info_0 = *result[0];
846   EXPECT_TRUE(info_0.is_internal);
847   EXPECT_TRUE(info_0.is_auto_rotation_allowed);
848
849   ASSERT_TRUE(base::StringToInt64(result[1]->id, &display_id));
850   ASSERT_TRUE(DisplayExists(display_id));
851   const crosapi::mojom::DisplayUnitInfo& info_1 = *result[1];
852   EXPECT_FALSE(info_1.is_internal);
853   EXPECT_FALSE(info_1.is_auto_rotation_allowed);
854 }
855
856 TEST_F(CrosDisplayConfigTest, TabletModeAutoRotation) {
857   TestObserver observer;
858   mojo::AssociatedRemote<crosapi::mojom::CrosDisplayConfigObserver>
859       observer_remote;
860   mojo::AssociatedReceiver<crosapi::mojom::CrosDisplayConfigObserver> receiver(
861       &observer, observer_remote.BindNewEndpointAndPassDedicatedReceiver());
862   cros_display_config()->AddObserver(observer_remote.Unbind());
863   base::RunLoop().RunUntilIdle();
864
865   display::test::DisplayManagerTestApi(display_manager())
866       .SetFirstDisplayAsInternalDisplay();
867
868   // Setting the rotation to kAutoRotate from outside the physical tablet state
869   // is treated as a request to set the rotation to 0.
870   const display::Display& display =
871       display_manager()->GetPrimaryDisplayCandidate();
872   auto properties = crosapi::mojom::DisplayConfigProperties::New();
873   properties->rotation = crosapi::mojom::DisplayRotation::New(
874       crosapi::mojom::DisplayRotationOptions::kAutoRotate);
875   auto result = SetDisplayProperties(base::NumberToString(display.id()),
876                                      std::move(properties));
877   EXPECT_EQ(crosapi::mojom::DisplayConfigResult::kSuccess, result);
878   auto* screen_orientation_controller =
879       Shell::Get()->screen_orientation_controller();
880   EXPECT_FALSE(screen_orientation_controller->user_rotation_locked());
881   EXPECT_EQ(display::Display::ROTATE_0, display.rotation());
882
883   TabletModeControllerTestApi tablet_mode_controller_test_api;
884   ScreenOrientationControllerTestApi screen_orientation_controller_test_api(
885       screen_orientation_controller);
886   tablet_mode_controller_test_api.EnterTabletMode();
887   EXPECT_TRUE(tablet_mode_controller_test_api.IsInPhysicalTabletState());
888   EXPECT_TRUE(screen_orientation_controller_test_api.IsAutoRotationAllowed());
889   EXPECT_TRUE(tablet_mode_controller_test_api.IsTabletModeStarted());
890
891   // Clear out any pending observer calls.
892   base::RunLoop().RunUntilIdle();
893   observer.reset_display_changes();
894
895   properties = crosapi::mojom::DisplayConfigProperties::New();
896   properties->rotation = crosapi::mojom::DisplayRotation::New(
897       crosapi::mojom::DisplayRotationOptions::k90Degrees);
898   result = SetDisplayProperties(base::NumberToString(display.id()),
899                                 std::move(properties));
900   EXPECT_EQ(crosapi::mojom::DisplayConfigResult::kSuccess, result);
901   EXPECT_TRUE(screen_orientation_controller->user_rotation_locked());
902   EXPECT_EQ(display::Display::ROTATE_90, display.rotation());
903   // OnDisplayConfigChanged() will be called twice, once as a result of the
904   // user rotation lock change, and another due to the actual display rotation
905   // change.
906   base::RunLoop().RunUntilIdle();
907   EXPECT_EQ(2, observer.display_changes());
908
909   // Hooking up an external mouse device, should exit UI tablet mode, but the
910   // device is still in a tablet physical state, the API should still be valid
911   // for use.
912   tablet_mode_controller_test_api.AttachExternalMouse();
913   EXPECT_TRUE(tablet_mode_controller_test_api.IsInPhysicalTabletState());
914   EXPECT_TRUE(screen_orientation_controller_test_api.IsAutoRotationAllowed());
915   EXPECT_FALSE(tablet_mode_controller_test_api.IsTabletModeStarted());
916
917   // Clear out any pending observer calls.
918   base::RunLoop().RunUntilIdle();
919   observer.reset_display_changes();
920
921   properties = crosapi::mojom::DisplayConfigProperties::New();
922   properties->rotation = crosapi::mojom::DisplayRotation::New(
923       crosapi::mojom::DisplayRotationOptions::kAutoRotate);
924   result = SetDisplayProperties(base::NumberToString(display.id()),
925                                 std::move(properties));
926   EXPECT_EQ(crosapi::mojom::DisplayConfigResult::kSuccess, result);
927   EXPECT_FALSE(screen_orientation_controller->user_rotation_locked());
928   // Unlocking auto-rotate doesn't actually change the display rotation. It
929   // simply allows it to auto-rotate in response to accelerometer updates.
930   EXPECT_EQ(display::Display::ROTATE_90, display.rotation());
931   // This time, OnDisplayConfigChanged() will be called only once as a result of
932   // the user rotation lock change.
933   base::RunLoop().RunUntilIdle();
934   EXPECT_EQ(1, observer.display_changes());
935
936   // Once the device is no longer in a physical tablet state, the rotation is
937   // restored.
938   tablet_mode_controller_test_api.LeaveTabletMode();
939   EXPECT_FALSE(tablet_mode_controller_test_api.IsInPhysicalTabletState());
940   EXPECT_FALSE(screen_orientation_controller_test_api.IsAutoRotationAllowed());
941   EXPECT_FALSE(tablet_mode_controller_test_api.IsTabletModeStarted());
942   EXPECT_EQ(display::Display::ROTATE_0, display.rotation());
943 }
944
945 TEST_F(CrosDisplayConfigTest, HighlightDisplayValid) {
946   UpdateDisplay("500x400,500x400");
947
948   const display::Display& display = display_manager()->GetDisplayAt(0);
949   const int64_t display_id = display.id();
950
951   HighlightDisplay(display_id);
952
953   views::Widget* widget =
954       Shell::Get()->display_highlight_controller()->GetWidgetForTesting();
955   ASSERT_NE(widget, nullptr);
956   EXPECT_EQ(widget->GetNativeWindow()->GetRootWindow(),
957             Shell::GetRootWindowForDisplayId(display_id));
958 }
959
960 TEST_F(CrosDisplayConfigTest, HighlightDisplayInvalid) {
961   UpdateDisplay("500x400,500x400");
962
963   HighlightDisplay(display::kInvalidDisplayId);
964
965   EXPECT_EQ(Shell::Get()->display_highlight_controller()->GetWidgetForTesting(),
966             nullptr);
967 }
968
969 TEST_F(CrosDisplayConfigTest, DragDisplayDelta) {
970   UpdateDisplay("500x400,500x400");
971
972   const auto& display = display_manager()->GetDisplayAt(0);
973
974   EXPECT_FALSE(PreviewIndicatorsExist());
975
976   DragDisplayDelta(display.id(), 0, 16);
977
978   EXPECT_TRUE(PreviewIndicatorsExist());
979 }
980
981 }  // namespace ash