1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chromeos/display/output_configurator.h"
12 #include "base/basictypes.h"
13 #include "base/compiler_specific.h"
14 #include "base/message_loop/message_loop.h"
15 #include "base/strings/stringprintf.h"
16 #include "testing/gtest/include/gtest/gtest.h"
22 // Strings returned by TestDelegate::GetActionsAndClear() to describe various
23 // actions that were performed.
24 const char kInitXRandR[] = "init";
25 const char kUpdateXRandR[] = "update";
26 const char kGrab[] = "grab";
27 const char kUngrab[] = "ungrab";
28 const char kSync[] = "sync";
29 const char kForceDPMS[] = "dpms";
30 const char kProjectingOn[] = "projecting";
31 const char kProjectingOff[] = "not_projecting";
33 // String returned by TestDelegate::GetActionsAndClear() if no actions were
35 const char kNoActions[] = "";
37 // Returns a string describing a TestDelegate::SetBackgroundColor() call.
38 std::string GetBackgroundAction(uint32 color_argb) {
39 return base::StringPrintf("background(0x%x)", color_argb);
42 // Returns a string describing a TestDelegate::AddOutputMode() call.
43 std::string GetAddOutputModeAction(RROutput output, RRMode mode) {
44 return base::StringPrintf("add_mode(output=%lu,mode=%lu)", output, mode);
47 // Returns a string describing a TestDelegate::ConfigureCrtc() call.
48 std::string GetCrtcAction(RRCrtc crtc,
53 return base::StringPrintf("crtc(crtc=%lu,x=%d,y=%d,mode=%lu,output=%lu)",
54 crtc, x, y, mode, output);
57 // Returns a string describing a TestDelegate::CreateFramebuffer() call.
58 std::string GetFramebufferAction(int width,
62 return base::StringPrintf(
63 "framebuffer(width=%d,height=%d,crtc1=%lu,crtc2=%lu)",
64 width, height, crtc1, crtc2);
67 // Returns a string describing a TestDelegate::ConfigureCTM() call.
68 std::string GetCTMAction(
70 const OutputConfigurator::CoordinateTransformation& ctm) {
71 return base::StringPrintf("ctm(id=%d,transform=(%f,%f,%f,%f))", device_id,
72 ctm.x_scale, ctm.x_offset, ctm.y_scale, ctm.y_offset);
75 // Returns a string describing a TestDelegate::SetHDCPState() call.
76 std::string GetSetHDCPStateAction(RROutput id, HDCPState state) {
77 return base::StringPrintf("set_hdcp(id=%lu,state=%d)", id, state);
80 // Joins a sequence of strings describing actions (e.g. kScreenDim) such
81 // that they can be compared against a string returned by
82 // TestDelegate::GetActionsAndClear(). The list of actions must be
83 // terminated by a NULL pointer.
84 std::string JoinActions(const char* action, ...) {
88 va_start(arg_list, action);
93 action = va_arg(arg_list, const char*);
99 class TestDelegate : public OutputConfigurator::Delegate {
101 static const int kXRandREventBase = 10;
104 : configure_crtc_result_(true),
105 hdcp_state_(HDCP_STATE_UNDESIRED) {}
106 virtual ~TestDelegate() {}
108 const std::vector<OutputConfigurator::OutputSnapshot>& outputs() const {
112 const std::vector<OutputConfigurator::OutputSnapshot>& outputs) {
116 void set_configure_crtc_result(bool result) {
117 configure_crtc_result_ = result;
120 void set_hdcp_state(HDCPState state) { hdcp_state_ = state; }
122 // Returns a comma-separated string describing the actions that were
123 // requested since the previous call to GetActionsAndClear() (i.e.
124 // results are non-repeatable).
125 std::string GetActionsAndClear() {
126 std::string actions = actions_;
131 // OutputConfigurator::Delegate overrides:
132 virtual void InitXRandRExtension(int* event_base) OVERRIDE {
133 AppendAction(kInitXRandR);
134 *event_base = kXRandREventBase;
136 virtual void UpdateXRandRConfiguration(
137 const base::NativeEvent& event) OVERRIDE { AppendAction(kUpdateXRandR); }
138 virtual void GrabServer() OVERRIDE { AppendAction(kGrab); }
139 virtual void UngrabServer() OVERRIDE { AppendAction(kUngrab); }
140 virtual void SyncWithServer() OVERRIDE { AppendAction(kSync); }
141 virtual void SetBackgroundColor(uint32 color_argb) OVERRIDE {
142 AppendAction(GetBackgroundAction(color_argb));
144 virtual void ForceDPMSOn() OVERRIDE { AppendAction(kForceDPMS); }
145 virtual std::vector<OutputConfigurator::OutputSnapshot> GetOutputs()
149 virtual void AddOutputMode(RROutput output, RRMode mode) OVERRIDE {
150 AppendAction(GetAddOutputModeAction(output, mode));
152 virtual bool ConfigureCrtc(RRCrtc crtc,
157 AppendAction(GetCrtcAction(crtc, x, y, mode, output));
158 return configure_crtc_result_;
160 virtual void CreateFrameBuffer(
163 const std::vector<OutputConfigurator::OutputSnapshot>& outputs) OVERRIDE {
165 GetFramebufferAction(width,
167 outputs.size() >= 1 ? outputs[0].crtc : 0,
168 outputs.size() >= 2 ? outputs[1].crtc : 0));
170 virtual void ConfigureCTM(
172 const OutputConfigurator::CoordinateTransformation& ctm) OVERRIDE {
173 AppendAction(GetCTMAction(touch_device_id, ctm));
175 virtual void SendProjectingStateToPowerManager(bool projecting) OVERRIDE {
176 AppendAction(projecting ? kProjectingOn : kProjectingOff);
179 virtual bool GetHDCPState(RROutput id, HDCPState* state) OVERRIDE {
180 *state = hdcp_state_;
184 virtual bool SetHDCPState(RROutput id, HDCPState state) OVERRIDE {
185 AppendAction(GetSetHDCPStateAction(id, state));
191 ModeDetails() : width(0), height(0), interlaced(false) {}
192 ModeDetails(int width, int height, bool interlaced)
195 interlaced(interlaced) {}
202 void AppendAction(const std::string& action) {
203 if (!actions_.empty())
208 std::map<RRMode, ModeDetails> modes_;
210 // Outputs to be returned by GetOutputs().
211 std::vector<OutputConfigurator::OutputSnapshot> outputs_;
213 std::string actions_;
215 // Return value returned by ConfigureCrtc().
216 bool configure_crtc_result_;
218 // Result value of GetHDCPState().
219 HDCPState hdcp_state_;
221 DISALLOW_COPY_AND_ASSIGN(TestDelegate);
224 class TestObserver : public OutputConfigurator::Observer {
226 explicit TestObserver(OutputConfigurator* configurator)
227 : configurator_(configurator) {
229 configurator_->AddObserver(this);
231 virtual ~TestObserver() {
232 configurator_->RemoveObserver(this);
235 int num_changes() const { return num_changes_; }
236 int num_failures() const { return num_failures_; }
237 const std::vector<OutputConfigurator::OutputSnapshot>& latest_outputs()
239 return latest_outputs_;
241 OutputState latest_failed_state() const { return latest_failed_state_; }
246 latest_outputs_.clear();
247 latest_failed_state_ = STATE_INVALID;
250 // OutputConfigurator::Observer overrides:
251 virtual void OnDisplayModeChanged(
252 const std::vector<OutputConfigurator::OutputSnapshot>& outputs) OVERRIDE {
254 latest_outputs_ = outputs;
257 virtual void OnDisplayModeChangeFailed(OutputState failed_new_state)
260 latest_failed_state_ = failed_new_state;
264 OutputConfigurator* configurator_; // Not owned.
266 // Number of times that OnDisplayMode*() has been called.
270 // Parameters most recently passed to OnDisplayMode*().
271 std::vector<OutputConfigurator::OutputSnapshot> latest_outputs_;
272 OutputState latest_failed_state_;
274 DISALLOW_COPY_AND_ASSIGN(TestObserver);
277 class TestStateController : public OutputConfigurator::StateController {
279 TestStateController() : state_(STATE_DUAL_EXTENDED) {}
280 virtual ~TestStateController() {}
282 void set_state(OutputState state) { state_ = state; }
284 // OutputConfigurator::StateController overrides:
285 virtual OutputState GetStateForDisplayIds(
286 const std::vector<int64>& outputs) const OVERRIDE { return state_; }
287 virtual bool GetResolutionForDisplayId(
290 int *height) const OVERRIDE {
297 DISALLOW_COPY_AND_ASSIGN(TestStateController);
300 class TestMirroringController
301 : public OutputConfigurator::SoftwareMirroringController {
303 TestMirroringController() : software_mirroring_enabled_(false) {}
304 virtual ~TestMirroringController() {}
306 virtual void SetSoftwareMirroring(bool enabled) OVERRIDE {
307 software_mirroring_enabled_ = enabled;
310 bool software_mirroring_enabled() const {
311 return software_mirroring_enabled_;
315 bool software_mirroring_enabled_;
317 DISALLOW_COPY_AND_ASSIGN(TestMirroringController);
320 class OutputConfiguratorTest : public testing::Test {
322 // Predefined modes that can be used by outputs.
323 static const RRMode kSmallModeId;
324 static const int kSmallModeWidth;
325 static const int kSmallModeHeight;
327 static const RRMode kBigModeId;
328 static const int kBigModeWidth;
329 static const int kBigModeHeight;
331 OutputConfiguratorTest()
332 : observer_(&configurator_),
333 test_api_(&configurator_, TestDelegate::kXRandREventBase) {}
334 virtual ~OutputConfiguratorTest() {}
336 virtual void SetUp() OVERRIDE {
337 delegate_ = new TestDelegate();
338 configurator_.SetDelegateForTesting(
339 scoped_ptr<OutputConfigurator::Delegate>(delegate_));
340 configurator_.set_state_controller(&state_controller_);
341 configurator_.set_mirroring_controller(&mirroring_controller_);
343 OutputConfigurator::ModeInfo small_mode_info;
344 small_mode_info.width = kSmallModeWidth;
345 small_mode_info.height = kSmallModeHeight;
347 OutputConfigurator::ModeInfo big_mode_info;
348 big_mode_info.width = kBigModeWidth;
349 big_mode_info.height = kBigModeHeight;
351 OutputConfigurator::OutputSnapshot* o = &outputs_[0];
354 o->current_mode = kSmallModeId;
355 o->native_mode = kSmallModeId;
356 o->is_internal = true;
357 o->type = OUTPUT_TYPE_INTERNAL;
358 o->is_aspect_preserving_scaling = true;
359 o->mode_infos[kSmallModeId] = small_mode_info;
360 o->has_display_id = true;
367 o->current_mode = kBigModeId;
368 o->native_mode = kBigModeId;
369 o->is_internal = false;
370 o->type = OUTPUT_TYPE_HDMI;
371 o->is_aspect_preserving_scaling = true;
372 o->mode_infos[kSmallModeId] = small_mode_info;
373 o->mode_infos[kBigModeId] = big_mode_info;
374 o->has_display_id = true;
378 UpdateOutputs(2, false);
382 // Configures |delegate_| to return the first |num_outputs| entries from
383 // |outputs_|. If |send_events| is true, also sends screen-change and
384 // output-change events to |configurator_| and triggers the configure
385 // timeout if one was scheduled.
386 void UpdateOutputs(size_t num_outputs, bool send_events) {
387 ASSERT_LE(num_outputs, arraysize(outputs_));
388 std::vector<OutputConfigurator::OutputSnapshot> outputs;
389 for (size_t i = 0; i < num_outputs; ++i)
390 outputs.push_back(outputs_[i]);
391 delegate_->set_outputs(outputs);
394 test_api_.SendScreenChangeEvent();
395 for (size_t i = 0; i < arraysize(outputs_); ++i) {
396 const OutputConfigurator::OutputSnapshot output = outputs_[i];
397 bool connected = i < num_outputs;
398 test_api_.SendOutputChangeEvent(
399 output.output, output.crtc, output.current_mode, connected);
401 test_api_.TriggerConfigureTimeout();
405 // Initializes |configurator_| with a single internal display.
406 void InitWithSingleOutput() {
407 UpdateOutputs(1, false);
408 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
409 configurator_.Init(false);
410 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
411 configurator_.Start(0);
412 EXPECT_EQ(JoinActions(kGrab, kInitXRandR,
413 GetFramebufferAction(kSmallModeWidth,
414 kSmallModeHeight, outputs_[0].crtc, 0).c_str(),
415 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
416 outputs_[0].output).c_str(),
417 kForceDPMS, kUngrab, kProjectingOff, NULL),
418 delegate_->GetActionsAndClear());
421 base::MessageLoop message_loop_;
422 TestStateController state_controller_;
423 TestMirroringController mirroring_controller_;
424 OutputConfigurator configurator_;
425 TestObserver observer_;
426 TestDelegate* delegate_; // not owned
427 OutputConfigurator::TestApi test_api_;
429 OutputConfigurator::OutputSnapshot outputs_[2];
432 DISALLOW_COPY_AND_ASSIGN(OutputConfiguratorTest);
435 const RRMode OutputConfiguratorTest::kSmallModeId = 20;
436 const int OutputConfiguratorTest::kSmallModeWidth = 1366;
437 const int OutputConfiguratorTest::kSmallModeHeight = 768;
439 const RRMode OutputConfiguratorTest::kBigModeId = 21;
440 const int OutputConfiguratorTest::kBigModeWidth = 2560;
441 const int OutputConfiguratorTest::kBigModeHeight = 1600;
445 TEST_F(OutputConfiguratorTest, FindOutputModeMatchingSize) {
446 OutputConfigurator::OutputSnapshot output;
448 // Fields are width, height, interlaced, refresh rate.
449 output.mode_infos[11] = OutputConfigurator::ModeInfo(1920, 1200, false, 60.0);
451 output.mode_infos[12] = OutputConfigurator::ModeInfo(1920, 1080, false, 30.0);
452 output.mode_infos[13] = OutputConfigurator::ModeInfo(1920, 1080, false, 50.0);
453 output.mode_infos[14] = OutputConfigurator::ModeInfo(1920, 1080, false, 40.0);
454 output.mode_infos[15] = OutputConfigurator::ModeInfo(1920, 1080, false, 0.0);
455 // Interlaced vs non-interlaced.
456 output.mode_infos[16] = OutputConfigurator::ModeInfo(1280, 720, true, 60.0);
457 output.mode_infos[17] = OutputConfigurator::ModeInfo(1280, 720, false, 40.0);
459 output.mode_infos[18] = OutputConfigurator::ModeInfo(1024, 768, true, 0.0);
460 output.mode_infos[19] = OutputConfigurator::ModeInfo(1024, 768, true, 40.0);
461 output.mode_infos[20] = OutputConfigurator::ModeInfo(1024, 768, true, 60.0);
463 output.mode_infos[21] = OutputConfigurator::ModeInfo(1024, 600, true, 60.0);
464 output.mode_infos[22] = OutputConfigurator::ModeInfo(1024, 600, false, 40.0);
465 output.mode_infos[23] = OutputConfigurator::ModeInfo(1024, 600, false, 50.0);
466 // Just one interlaced mode.
467 output.mode_infos[24] = OutputConfigurator::ModeInfo(640, 480, true, 60.0);
468 // Refresh rate not available.
469 output.mode_infos[25] = OutputConfigurator::ModeInfo(320, 200, false, 0.0);
471 EXPECT_EQ(11u, OutputConfigurator::FindOutputModeMatchingSize(output,
474 // Should pick highest refresh rate.
475 EXPECT_EQ(13u, OutputConfigurator::FindOutputModeMatchingSize(output,
478 // Should pick non-interlaced mode.
479 EXPECT_EQ(17u, OutputConfigurator::FindOutputModeMatchingSize(output,
482 // Interlaced only. Should pick one with the highest refresh rate in
484 EXPECT_EQ(20u, OutputConfigurator::FindOutputModeMatchingSize(output,
487 // Mixed: Should pick one with the highest refresh rate in
489 EXPECT_EQ(23u, OutputConfigurator::FindOutputModeMatchingSize(output,
492 // Just one interlaced mode.
493 EXPECT_EQ(24u, OutputConfigurator::FindOutputModeMatchingSize(output,
496 // Refresh rate not available.
497 EXPECT_EQ(25u, OutputConfigurator::FindOutputModeMatchingSize(output,
501 EXPECT_EQ(0u, OutputConfigurator::FindOutputModeMatchingSize(output,
505 TEST_F(OutputConfiguratorTest, ConnectSecondOutput) {
506 InitWithSingleOutput();
508 // Connect a second output and check that the configurator enters
511 state_controller_.set_state(STATE_DUAL_EXTENDED);
512 UpdateOutputs(2, true);
513 const int kDualHeight =
514 kSmallModeHeight + OutputConfigurator::kVerticalGap + kBigModeHeight;
515 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
516 GetFramebufferAction(kBigModeWidth, kDualHeight,
517 outputs_[0].crtc, outputs_[1].crtc).c_str(),
518 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
519 outputs_[0].output).c_str(),
520 GetCrtcAction(outputs_[1].crtc, 0,
521 kSmallModeHeight + OutputConfigurator::kVerticalGap,
522 kBigModeId, outputs_[1].output).c_str(),
523 kUngrab, kProjectingOn, NULL),
524 delegate_->GetActionsAndClear());
525 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
526 EXPECT_EQ(1, observer_.num_changes());
529 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
530 EXPECT_EQ(JoinActions(kGrab,
531 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
532 outputs_[0].crtc, outputs_[1].crtc).c_str(),
533 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
534 outputs_[0].output).c_str(),
535 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
536 outputs_[1].output).c_str(),
538 delegate_->GetActionsAndClear());
539 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
540 EXPECT_EQ(1, observer_.num_changes());
542 // Disconnect the second output.
544 UpdateOutputs(1, true);
545 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
546 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
547 outputs_[0].crtc, 0).c_str(),
548 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
549 outputs_[0].output).c_str(),
550 kUngrab, kProjectingOff, NULL),
551 delegate_->GetActionsAndClear());
552 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
553 EXPECT_EQ(1, observer_.num_changes());
555 // Get rid of shared modes to force software mirroring.
556 outputs_[1].mode_infos.erase(kSmallModeId);
557 state_controller_.set_state(STATE_DUAL_EXTENDED);
558 UpdateOutputs(2, true);
559 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
560 GetFramebufferAction(kBigModeWidth, kDualHeight,
561 outputs_[0].crtc, outputs_[1].crtc).c_str(),
562 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
563 outputs_[0].output).c_str(),
564 GetCrtcAction(outputs_[1].crtc, 0,
565 kSmallModeHeight + OutputConfigurator::kVerticalGap,
566 kBigModeId, outputs_[1].output).c_str(),
567 kUngrab, kProjectingOn, NULL),
568 delegate_->GetActionsAndClear());
569 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
572 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
573 EXPECT_EQ(JoinActions(kGrab, kUngrab, NULL), delegate_->GetActionsAndClear());
574 EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
575 EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
576 EXPECT_EQ(1, observer_.num_changes());
578 // Setting STATE_DUAL_MIRROR should try to reconfigure.
580 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_EXTENDED));
581 EXPECT_EQ(JoinActions(NULL), delegate_->GetActionsAndClear());
582 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
583 EXPECT_EQ(1, observer_.num_changes());
585 // Set back to software mirror mode.
587 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
588 EXPECT_EQ(JoinActions(kGrab, kUngrab, NULL),
589 delegate_->GetActionsAndClear());
590 EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
591 EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
592 EXPECT_EQ(1, observer_.num_changes());
594 // Disconnect the second output.
596 UpdateOutputs(1, true);
597 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
598 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
599 outputs_[0].crtc, 0).c_str(),
600 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
601 outputs_[0].output).c_str(),
602 kUngrab, kProjectingOff, NULL),
603 delegate_->GetActionsAndClear());
604 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
605 EXPECT_EQ(1, observer_.num_changes());
608 TEST_F(OutputConfiguratorTest, SetDisplayPower) {
609 InitWithSingleOutput();
611 state_controller_.set_state(STATE_DUAL_MIRROR);
613 UpdateOutputs(2, true);
614 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
615 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
616 outputs_[0].crtc, outputs_[1].crtc).c_str(),
617 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
618 outputs_[0].output).c_str(),
619 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
620 outputs_[1].output).c_str(),
621 kUngrab, kProjectingOn, NULL),
622 delegate_->GetActionsAndClear());
623 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
624 EXPECT_EQ(1, observer_.num_changes());
626 // Turning off the internal display should switch the external display to
629 configurator_.SetDisplayPower(DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON,
630 OutputConfigurator::kSetDisplayPowerNoFlags);
631 EXPECT_EQ(JoinActions(kGrab,
632 GetFramebufferAction(kBigModeWidth, kBigModeHeight,
633 outputs_[0].crtc, outputs_[1].crtc).c_str(),
634 GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
635 outputs_[0].output).c_str(),
636 GetCrtcAction(outputs_[1].crtc, 0, 0, kBigModeId,
637 outputs_[1].output).c_str(),
638 kForceDPMS, kUngrab, NULL),
639 delegate_->GetActionsAndClear());
640 EXPECT_EQ(STATE_SINGLE, configurator_.output_state());
641 EXPECT_EQ(1, observer_.num_changes());
643 // When all displays are turned off, the framebuffer should switch back
644 // to the mirrored size.
646 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF,
647 OutputConfigurator::kSetDisplayPowerNoFlags);
648 EXPECT_EQ(JoinActions(kGrab,
649 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
650 outputs_[0].crtc, outputs_[1].crtc).c_str(),
651 GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
652 outputs_[0].output).c_str(),
653 GetCrtcAction(outputs_[1].crtc, 0, 0, 0,
654 outputs_[1].output).c_str(),
656 delegate_->GetActionsAndClear());
657 EXPECT_EQ(STATE_DUAL_MIRROR, configurator_.output_state());
658 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
659 EXPECT_EQ(1, observer_.num_changes());
661 // Turn all displays on and check that mirroring is still used.
663 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_ON,
664 OutputConfigurator::kSetDisplayPowerNoFlags);
665 EXPECT_EQ(JoinActions(kGrab,
666 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
667 outputs_[0].crtc, outputs_[1].crtc).c_str(),
668 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
669 outputs_[0].output).c_str(),
670 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
671 outputs_[1].output).c_str(),
672 kForceDPMS, kUngrab, NULL),
673 delegate_->GetActionsAndClear());
674 EXPECT_EQ(STATE_DUAL_MIRROR, configurator_.output_state());
675 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
676 EXPECT_EQ(1, observer_.num_changes());
678 // Get rid of shared modes to force software mirroring.
679 outputs_[1].mode_infos.erase(kSmallModeId);
680 state_controller_.set_state(STATE_DUAL_MIRROR);
682 UpdateOutputs(2, true);
683 const int kDualHeight =
684 kSmallModeHeight + OutputConfigurator::kVerticalGap + kBigModeHeight;
685 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
686 GetFramebufferAction(kBigModeWidth, kDualHeight,
687 outputs_[0].crtc, outputs_[1].crtc).c_str(),
688 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
689 outputs_[0].output).c_str(),
690 GetCrtcAction(outputs_[1].crtc, 0,
691 kSmallModeHeight + OutputConfigurator::kVerticalGap,
692 kBigModeId, outputs_[1].output).c_str(),
693 kUngrab, kProjectingOn, NULL),
694 delegate_->GetActionsAndClear());
695 EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
696 EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
697 EXPECT_EQ(1, observer_.num_changes());
699 // Turning off the internal display should switch the external display to
702 configurator_.SetDisplayPower(DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON,
703 OutputConfigurator::kSetDisplayPowerNoFlags);
704 EXPECT_EQ(JoinActions(kGrab,
705 GetFramebufferAction(kBigModeWidth, kBigModeHeight,
706 outputs_[0].crtc, outputs_[1].crtc).c_str(),
707 GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
708 outputs_[0].output).c_str(),
709 GetCrtcAction(outputs_[1].crtc, 0, 0, kBigModeId,
710 outputs_[1].output).c_str(),
711 kForceDPMS, kUngrab, NULL),
712 delegate_->GetActionsAndClear());
713 EXPECT_EQ(STATE_SINGLE, configurator_.output_state());
714 EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
715 EXPECT_EQ(1, observer_.num_changes());
717 // When all displays are turned off, the framebuffer should switch back
718 // to the extended + software mirroring.
720 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF,
721 OutputConfigurator::kSetDisplayPowerNoFlags);
722 EXPECT_EQ(JoinActions(kGrab,
723 GetFramebufferAction(kBigModeWidth, kDualHeight,
724 outputs_[0].crtc, outputs_[1].crtc).c_str(),
725 GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
726 outputs_[0].output).c_str(),
727 GetCrtcAction(outputs_[1].crtc, 0,
728 kSmallModeHeight + OutputConfigurator::kVerticalGap,
729 0, outputs_[1].output).c_str(),
731 delegate_->GetActionsAndClear());
732 EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
733 EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
734 EXPECT_EQ(1, observer_.num_changes());
736 // Turn all displays on and check that mirroring is still used.
738 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_ON,
739 OutputConfigurator::kSetDisplayPowerNoFlags);
740 EXPECT_EQ(JoinActions(kGrab,
741 GetFramebufferAction(kBigModeWidth, kDualHeight,
742 outputs_[0].crtc, outputs_[1].crtc).c_str(),
743 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
744 outputs_[0].output).c_str(),
745 GetCrtcAction(outputs_[1].crtc, 0,
746 kSmallModeHeight + OutputConfigurator::kVerticalGap,
747 kBigModeId, outputs_[1].output).c_str(),
748 kForceDPMS, kUngrab, NULL),
749 delegate_->GetActionsAndClear());
750 EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
751 EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
752 EXPECT_EQ(1, observer_.num_changes());
755 TEST_F(OutputConfiguratorTest, SuspendAndResume) {
756 InitWithSingleOutput();
758 // No preparation is needed before suspending when the display is already
759 // on. The configurator should still reprobe on resume in case a display
760 // was connected while suspended.
761 configurator_.SuspendDisplays();
762 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
763 configurator_.ResumeDisplays();
764 EXPECT_EQ(JoinActions(kGrab,
765 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
766 outputs_[0].crtc, 0).c_str(),
767 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
768 outputs_[0].output).c_str(),
769 kForceDPMS, kUngrab, NULL),
770 delegate_->GetActionsAndClear());
772 // Now turn the display off before suspending and check that the
773 // configurator turns it back on and syncs with the server.
774 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF,
775 OutputConfigurator::kSetDisplayPowerNoFlags);
776 EXPECT_EQ(JoinActions(kGrab,
777 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
778 outputs_[0].crtc, 0).c_str(),
779 GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
780 outputs_[0].output).c_str(),
782 delegate_->GetActionsAndClear());
784 configurator_.SuspendDisplays();
785 EXPECT_EQ(JoinActions(kGrab,
786 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
787 outputs_[0].crtc, 0).c_str(),
788 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
789 outputs_[0].output).c_str(),
790 kForceDPMS, kUngrab, kSync, NULL),
791 delegate_->GetActionsAndClear());
793 configurator_.ResumeDisplays();
794 EXPECT_EQ(JoinActions(kGrab,
795 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
796 outputs_[0].crtc, 0).c_str(),
797 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
798 outputs_[0].output).c_str(),
799 kForceDPMS, kUngrab, NULL),
800 delegate_->GetActionsAndClear());
802 // If a second, external display is connected, the displays shouldn't be
803 // powered back on before suspending.
804 state_controller_.set_state(STATE_DUAL_MIRROR);
805 UpdateOutputs(2, true);
806 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
807 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
808 outputs_[0].crtc, outputs_[1].crtc).c_str(),
809 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
810 outputs_[0].output).c_str(),
811 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
812 outputs_[1].output).c_str(),
813 kUngrab, kProjectingOn, NULL),
814 delegate_->GetActionsAndClear());
816 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF,
817 OutputConfigurator::kSetDisplayPowerNoFlags);
818 EXPECT_EQ(JoinActions(kGrab,
819 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
820 outputs_[0].crtc, outputs_[1].crtc).c_str(),
821 GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
822 outputs_[0].output).c_str(),
823 GetCrtcAction(outputs_[1].crtc, 0, 0, 0,
824 outputs_[1].output).c_str(),
826 delegate_->GetActionsAndClear());
828 configurator_.SuspendDisplays();
829 EXPECT_EQ(JoinActions(kGrab, kUngrab, kSync, NULL),
830 delegate_->GetActionsAndClear());
832 // If a display is disconnected while suspended, the configurator should
833 // pick up the change.
834 UpdateOutputs(1, false);
835 configurator_.ResumeDisplays();
836 EXPECT_EQ(JoinActions(kGrab,
837 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
838 outputs_[0].crtc, 0).c_str(),
839 GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
840 outputs_[0].output).c_str(),
842 delegate_->GetActionsAndClear());
845 TEST_F(OutputConfiguratorTest, Headless) {
846 UpdateOutputs(0, false);
847 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
848 configurator_.Init(false);
849 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
850 configurator_.Start(0);
851 EXPECT_EQ(JoinActions(kGrab, kInitXRandR, kForceDPMS, kUngrab,
852 kProjectingOff, NULL),
853 delegate_->GetActionsAndClear());
855 // Not much should happen when the display power state is changed while
856 // no displays are connected.
857 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF,
858 OutputConfigurator::kSetDisplayPowerNoFlags);
859 EXPECT_EQ(JoinActions(kGrab, kUngrab, NULL), delegate_->GetActionsAndClear());
860 configurator_.SetDisplayPower(DISPLAY_POWER_ALL_ON,
861 OutputConfigurator::kSetDisplayPowerNoFlags);
862 EXPECT_EQ(JoinActions(kGrab, kForceDPMS, kUngrab, NULL),
863 delegate_->GetActionsAndClear());
865 // Connect an external display and check that it's configured correctly.
866 outputs_[0] = outputs_[1];
867 UpdateOutputs(1, true);
868 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
869 GetFramebufferAction(kBigModeWidth, kBigModeHeight,
870 outputs_[0].crtc, 0).c_str(),
871 GetCrtcAction(outputs_[0].crtc, 0, 0, kBigModeId,
872 outputs_[0].output).c_str(),
873 kUngrab, kProjectingOff, NULL),
874 delegate_->GetActionsAndClear());
877 TEST_F(OutputConfiguratorTest, StartWithTwoOutputs) {
878 UpdateOutputs(2, false);
879 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
880 configurator_.Init(false);
881 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
883 state_controller_.set_state(STATE_DUAL_MIRROR);
884 configurator_.Start(0);
885 EXPECT_EQ(JoinActions(kGrab, kInitXRandR,
886 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
887 outputs_[0].crtc, outputs_[1].crtc).c_str(),
888 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
889 outputs_[0].output).c_str(),
890 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
891 outputs_[1].output).c_str(),
892 kForceDPMS, kUngrab, kProjectingOn, NULL),
893 delegate_->GetActionsAndClear());
896 TEST_F(OutputConfiguratorTest, InvalidOutputStates) {
897 UpdateOutputs(0, false);
898 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
899 configurator_.Init(false);
900 configurator_.Start(0);
902 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_HEADLESS));
903 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_SINGLE));
904 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
905 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_DUAL_EXTENDED));
906 EXPECT_EQ(1, observer_.num_changes());
907 EXPECT_EQ(3, observer_.num_failures());
909 UpdateOutputs(1, true);
911 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_HEADLESS));
912 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_SINGLE));
913 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
914 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_DUAL_EXTENDED));
915 EXPECT_EQ(1, observer_.num_changes());
916 EXPECT_EQ(3, observer_.num_failures());
918 state_controller_.set_state(STATE_DUAL_EXTENDED);
919 UpdateOutputs(2, true);
921 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_HEADLESS));
922 EXPECT_FALSE(configurator_.SetDisplayMode(STATE_SINGLE));
923 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
924 EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_EXTENDED));
925 EXPECT_EQ(2, observer_.num_changes());
926 EXPECT_EQ(2, observer_.num_failures());
929 TEST_F(OutputConfiguratorTest, GetOutputStateForDisplaysWithoutId) {
930 outputs_[0].has_display_id = false;
931 UpdateOutputs(2, false);
932 configurator_.Init(false);
933 state_controller_.set_state(STATE_DUAL_MIRROR);
934 configurator_.Start(0);
935 EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
938 TEST_F(OutputConfiguratorTest, GetOutputStateForDisplaysWithId) {
939 outputs_[0].has_display_id = true;
940 UpdateOutputs(2, false);
941 configurator_.Init(false);
942 state_controller_.set_state(STATE_DUAL_MIRROR);
943 configurator_.Start(0);
944 EXPECT_EQ(STATE_DUAL_MIRROR, configurator_.output_state());
947 TEST_F(OutputConfiguratorTest, AvoidUnnecessaryProbes) {
948 InitWithSingleOutput();
950 // X sends several events just after the configurator starts. Check that
951 // the output change events don't trigger an additional probe, which can
952 // block the UI thread.
953 test_api_.SendScreenChangeEvent();
954 EXPECT_EQ(kUpdateXRandR, delegate_->GetActionsAndClear());
956 test_api_.SendOutputChangeEvent(
957 outputs_[0].output, outputs_[0].crtc, outputs_[0].current_mode, true);
958 test_api_.SendOutputChangeEvent(
959 outputs_[1].output, outputs_[1].crtc, outputs_[1].current_mode, false);
960 EXPECT_FALSE(test_api_.TriggerConfigureTimeout());
961 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
963 // Send an event stating that the second output is connected and check
964 // that it gets updated.
965 state_controller_.set_state(STATE_DUAL_MIRROR);
966 UpdateOutputs(2, false);
967 test_api_.SendOutputChangeEvent(
968 outputs_[1].output, outputs_[1].crtc, outputs_[1].current_mode, true);
969 EXPECT_TRUE(test_api_.TriggerConfigureTimeout());
970 EXPECT_EQ(JoinActions(kGrab,
971 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
972 outputs_[0].crtc, outputs_[1].crtc).c_str(),
973 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
974 outputs_[0].output).c_str(),
975 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
976 outputs_[1].output).c_str(),
977 kUngrab, kProjectingOn, NULL),
978 delegate_->GetActionsAndClear());
980 // An event about the second output changing modes should trigger another
982 test_api_.SendOutputChangeEvent(
983 outputs_[1].output, outputs_[1].crtc, outputs_[1].native_mode, true);
984 EXPECT_TRUE(test_api_.TriggerConfigureTimeout());
985 EXPECT_EQ(JoinActions(kGrab,
986 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
987 outputs_[0].crtc, outputs_[1].crtc).c_str(),
988 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
989 outputs_[0].output).c_str(),
990 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
991 outputs_[1].output).c_str(),
992 kUngrab, kProjectingOn, NULL),
993 delegate_->GetActionsAndClear());
995 // Disconnect the second output.
996 UpdateOutputs(1, true);
997 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
998 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
999 outputs_[0].crtc, 0).c_str(),
1000 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
1001 outputs_[0].output).c_str(),
1002 kUngrab, kProjectingOff, NULL),
1003 delegate_->GetActionsAndClear());
1005 // An additional event about the second output being disconnected should
1007 test_api_.SendOutputChangeEvent(
1008 outputs_[1].output, outputs_[1].crtc, outputs_[1].current_mode, false);
1009 EXPECT_FALSE(test_api_.TriggerConfigureTimeout());
1010 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
1012 // Tell the delegate to report failure, which should result in the
1013 // second output sticking with its native mode.
1014 delegate_->set_configure_crtc_result(false);
1015 UpdateOutputs(2, true);
1016 EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
1017 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
1018 outputs_[0].crtc, outputs_[1].crtc).c_str(),
1019 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
1020 outputs_[0].output).c_str(),
1021 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
1022 outputs_[1].output).c_str(),
1023 kUngrab, kProjectingOn, NULL),
1024 delegate_->GetActionsAndClear());
1026 // An change event reporting a mode change on the second output should
1027 // trigger another reconfigure.
1028 delegate_->set_configure_crtc_result(true);
1029 test_api_.SendOutputChangeEvent(
1030 outputs_[1].output, outputs_[1].crtc, outputs_[1].mirror_mode, true);
1031 EXPECT_TRUE(test_api_.TriggerConfigureTimeout());
1032 EXPECT_EQ(JoinActions(kGrab,
1033 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
1034 outputs_[0].crtc, outputs_[1].crtc).c_str(),
1035 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
1036 outputs_[0].output).c_str(),
1037 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
1038 outputs_[1].output).c_str(),
1039 kUngrab, kProjectingOn, NULL),
1040 delegate_->GetActionsAndClear());
1043 TEST_F(OutputConfiguratorTest, UpdateCachedOutputsEvenAfterFailure) {
1044 InitWithSingleOutput();
1045 const std::vector<OutputConfigurator::OutputSnapshot>* cached =
1046 &test_api_.cached_outputs();
1047 ASSERT_EQ(static_cast<size_t>(1), cached->size());
1048 EXPECT_EQ(outputs_[0].current_mode, (*cached)[0].current_mode);
1050 // After connecting a second output, check that it shows up in
1051 // |cached_outputs_| even if an invalid state is requested.
1052 state_controller_.set_state(STATE_SINGLE);
1053 UpdateOutputs(2, true);
1054 cached = &test_api_.cached_outputs();
1055 ASSERT_EQ(static_cast<size_t>(2), cached->size());
1056 EXPECT_EQ(outputs_[0].current_mode, (*cached)[0].current_mode);
1057 EXPECT_EQ(outputs_[1].current_mode, (*cached)[1].current_mode);
1060 TEST_F(OutputConfiguratorTest, PanelFitting) {
1061 // Configure the internal display to support only the big mode and the
1062 // external display to support only the small mode.
1063 outputs_[0].current_mode = kBigModeId;
1064 outputs_[0].native_mode = kBigModeId;
1065 outputs_[0].mode_infos.clear();
1066 outputs_[0].mode_infos[kBigModeId] = OutputConfigurator::ModeInfo(
1067 kBigModeWidth, kBigModeHeight, false, 60.0);
1069 outputs_[1].current_mode = kSmallModeId;
1070 outputs_[1].native_mode = kSmallModeId;
1071 outputs_[1].mode_infos.clear();
1072 outputs_[1].mode_infos[kSmallModeId] = OutputConfigurator::ModeInfo(
1073 kSmallModeWidth, kSmallModeHeight, false, 60.0);
1075 // The small mode should be added to the internal output when requesting
1077 UpdateOutputs(2, false);
1078 state_controller_.set_state(STATE_DUAL_MIRROR);
1079 configurator_.Init(true /* is_panel_fitting_enabled */);
1080 configurator_.Start(0);
1081 EXPECT_EQ(STATE_DUAL_MIRROR, configurator_.output_state());
1082 EXPECT_EQ(JoinActions(kGrab, kInitXRandR,
1083 GetAddOutputModeAction(
1084 outputs_[0].output, kSmallModeId).c_str(),
1085 GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
1086 outputs_[0].crtc, outputs_[1].crtc).c_str(),
1087 GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
1088 outputs_[0].output).c_str(),
1089 GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
1090 outputs_[1].output).c_str(),
1091 kForceDPMS, kUngrab, kProjectingOn, NULL),
1092 delegate_->GetActionsAndClear());
1094 // Both outputs should be using the small mode.
1095 ASSERT_EQ(1, observer_.num_changes());
1096 ASSERT_EQ(static_cast<size_t>(2), observer_.latest_outputs().size());
1097 EXPECT_EQ(kSmallModeId, observer_.latest_outputs()[0].mirror_mode);
1098 EXPECT_EQ(kSmallModeId, observer_.latest_outputs()[0].current_mode);
1099 EXPECT_EQ(kSmallModeId, observer_.latest_outputs()[1].mirror_mode);
1100 EXPECT_EQ(kSmallModeId, observer_.latest_outputs()[1].current_mode);
1102 // Also check that the newly-added small mode is present in the internal
1103 // snapshot that was passed to the observer (http://crbug.com/289159).
1104 const OutputConfigurator::ModeInfo* info = OutputConfigurator::GetModeInfo(
1105 observer_.latest_outputs()[0], kSmallModeId);
1107 EXPECT_EQ(kSmallModeWidth, info->width);
1108 EXPECT_EQ(kSmallModeHeight, info->height);
1111 TEST_F(OutputConfiguratorTest, OutputProtection) {
1112 configurator_.Init(false);
1113 configurator_.Start(0);
1114 EXPECT_NE(kNoActions, delegate_->GetActionsAndClear());
1116 OutputConfigurator::OutputProtectionClientId id =
1117 configurator_.RegisterOutputProtectionClient();
1121 UpdateOutputs(1, true);
1122 EXPECT_NE(kNoActions, delegate_->GetActionsAndClear());
1123 uint32_t link_mask = 0;
1124 uint32_t protection_mask = 0;
1125 EXPECT_TRUE(configurator_.QueryOutputProtectionStatus(id,
1126 outputs_[0].display_id,
1129 EXPECT_EQ(static_cast<uint32_t>(OUTPUT_TYPE_INTERNAL), link_mask);
1130 EXPECT_EQ(static_cast<uint32_t>(OUTPUT_PROTECTION_METHOD_NONE),
1132 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
1135 UpdateOutputs(2, true);
1136 EXPECT_NE(kNoActions, delegate_->GetActionsAndClear());
1137 EXPECT_TRUE(configurator_.QueryOutputProtectionStatus(id,
1138 outputs_[1].display_id,
1141 EXPECT_EQ(static_cast<uint32_t>(OUTPUT_TYPE_HDMI),
1143 EXPECT_EQ(static_cast<uint32_t>(OUTPUT_PROTECTION_METHOD_NONE),
1145 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
1148 configurator_.EnableOutputProtection(id,
1149 outputs_[1].display_id,
1150 OUTPUT_PROTECTION_METHOD_HDCP));
1151 EXPECT_EQ(GetSetHDCPStateAction(outputs_[1].output, HDCP_STATE_DESIRED),
1152 delegate_->GetActionsAndClear());
1154 // Enable protection.
1155 delegate_->set_hdcp_state(HDCP_STATE_ENABLED);
1156 EXPECT_TRUE(configurator_.QueryOutputProtectionStatus(id,
1157 outputs_[1].display_id,
1160 EXPECT_EQ(static_cast<uint32_t>(OUTPUT_TYPE_HDMI), link_mask);
1161 EXPECT_EQ(static_cast<uint32_t>(OUTPUT_PROTECTION_METHOD_HDCP),
1163 EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
1165 // Protections should be disabled after unregister.
1166 configurator_.UnregisterOutputProtectionClient(id);
1167 EXPECT_EQ(GetSetHDCPStateAction(outputs_[1].output, HDCP_STATE_UNDESIRED),
1168 delegate_->GetActionsAndClear());
1171 TEST_F(OutputConfiguratorTest, OutputProtectionTwoClients) {
1172 OutputConfigurator::OutputProtectionClientId client1 =
1173 configurator_.RegisterOutputProtectionClient();
1174 OutputConfigurator::OutputProtectionClientId client2 =
1175 configurator_.RegisterOutputProtectionClient();
1176 EXPECT_NE(client1, client2);
1178 configurator_.Init(false);
1179 configurator_.Start(0);
1180 UpdateOutputs(2, true);
1181 EXPECT_NE(kNoActions, delegate_->GetActionsAndClear());
1183 // Clients never know state enableness for methods that they didn't request.
1185 configurator_.EnableOutputProtection(client1,
1186 outputs_[1].display_id,
1187 OUTPUT_PROTECTION_METHOD_HDCP));
1188 EXPECT_EQ(GetSetHDCPStateAction(outputs_[1].output,
1189 HDCP_STATE_DESIRED).c_str(),
1190 delegate_->GetActionsAndClear());
1191 delegate_->set_hdcp_state(HDCP_STATE_ENABLED);
1193 uint32_t link_mask = 0;
1194 uint32_t protection_mask = 0;
1195 EXPECT_TRUE(configurator_.QueryOutputProtectionStatus(client1,
1196 outputs_[1].display_id,
1199 EXPECT_EQ(static_cast<uint32_t>(OUTPUT_TYPE_HDMI), link_mask);
1200 EXPECT_EQ(OUTPUT_PROTECTION_METHOD_HDCP, protection_mask);
1202 EXPECT_TRUE(configurator_.QueryOutputProtectionStatus(client2,
1203 outputs_[1].display_id,
1206 EXPECT_EQ(static_cast<uint32_t>(OUTPUT_TYPE_HDMI), link_mask);
1207 EXPECT_EQ(OUTPUT_PROTECTION_METHOD_NONE, protection_mask);
1209 // Protections will be disabled only if no more clients request them.
1211 configurator_.EnableOutputProtection(client2,
1212 outputs_[1].display_id,
1213 OUTPUT_PROTECTION_METHOD_NONE));
1214 EXPECT_EQ(GetSetHDCPStateAction(outputs_[1].output,
1215 HDCP_STATE_DESIRED).c_str(),
1216 delegate_->GetActionsAndClear());
1218 configurator_.EnableOutputProtection(client1,
1219 outputs_[1].display_id,
1220 OUTPUT_PROTECTION_METHOD_NONE));
1221 EXPECT_EQ(GetSetHDCPStateAction(outputs_[1].output,
1222 HDCP_STATE_UNDESIRED).c_str(),
1223 delegate_->GetActionsAndClear());
1226 } // namespace chromeos