1a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "ui/display/chromeos/display_configurator.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include <stdint.h>
8effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
9f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include <cmath>
10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <cstdarg>
11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <map>
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
13c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include <vector>
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/compiler_specific.h"
1623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "base/format_macros.h"
1723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "base/memory/scoped_vector.h"
189ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
19868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
2123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)#include "ui/display/chromeos/test/test_display_snapshot.h"
221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "ui/display/types/display_mode.h"
231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "ui/display/types/native_display_delegate.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
25a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)namespace ui {
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace {
28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Strings returned by TestNativeDisplayDelegate::GetActionsAndClear() to
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// describe various actions that were performed.
31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const char kInitXRandR[] = "init";
32c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const char kGrab[] = "grab";
33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const char kUngrab[] = "ungrab";
34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const char kSync[] = "sync";
35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const char kForceDPMS[] = "dpms";
36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// String returned by TestNativeDisplayDelegate::GetActionsAndClear() if no
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// actions were requested.
39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const char kNoActions[] = "";
40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
4123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)std::string DisplaySnapshotToString(const DisplaySnapshot& output) {
4223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  return base::StringPrintf("id=%" PRId64, output.display_id());
4323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)}
4423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Returns a string describing a TestNativeDisplayDelegate::SetBackgroundColor()
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// call.
47effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochstd::string GetBackgroundAction(uint32_t color_argb) {
48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return base::StringPrintf("background(0x%x)", color_argb);
49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Returns a string describing a TestNativeDisplayDelegate::AddOutputMode()
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// call.
5323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)std::string GetAddOutputModeAction(const DisplaySnapshot& output,
5423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                                   const DisplayMode* mode) {
5523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  return base::StringPrintf("add_mode(output=%" PRId64 ",mode=%s)",
5623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                            output.display_id(),
5723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                            mode->ToString().c_str());
58d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
59d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
60a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Returns a string describing a TestNativeDisplayDelegate::Configure()
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// call.
6223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)std::string GetCrtcAction(const DisplaySnapshot& output,
6323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                          const DisplayMode* mode,
6423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                          const gfx::Point& origin) {
6523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  return base::StringPrintf("crtc(display=[%s],x=%d,y=%d,mode=[%s])",
6623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                            DisplaySnapshotToString(output).c_str(),
6723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                            origin.x(),
6823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                            origin.y(),
6923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                            mode ? mode->ToString().c_str() : "NULL");
70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Returns a string describing a TestNativeDisplayDelegate::CreateFramebuffer()
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// call.
7423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)std::string GetFramebufferAction(const gfx::Size& size,
7523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                                 const DisplaySnapshot* out1,
7623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                                 const DisplaySnapshot* out2) {
77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return base::StringPrintf(
7823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      "framebuffer(width=%d,height=%d,display1=%s,display2=%s)",
7923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      size.width(),
8023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      size.height(),
8123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      out1 ? DisplaySnapshotToString(*out1).c_str() : "NULL",
8223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      out2 ? DisplaySnapshotToString(*out2).c_str() : "NULL");
83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Returns a string describing a TestNativeDisplayDelegate::SetHDCPState() call.
8623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)std::string GetSetHDCPStateAction(const DisplaySnapshot& output,
8723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                                  HDCPState state) {
8823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  return base::StringPrintf(
8923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      "set_hdcp(id=%" PRId64 ",state=%d)", output.display_id(), state);
904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Joins a sequence of strings describing actions (e.g. kScreenDim) such
93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// that they can be compared against a string returned by
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// ActionLogger::GetActionsAndClear().  The list of actions must be
95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// terminated by a NULL pointer.
96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)std::string JoinActions(const char* action, ...) {
97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string actions;
98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  va_list arg_list;
100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  va_start(arg_list, action);
101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  while (action) {
102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if (!actions.empty())
103c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      actions += ",";
104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    actions += action;
105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    action = va_arg(arg_list, const char*);
106c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  va_end(arg_list);
108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return actions;
109c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
110c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class ActionLogger {
112c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) public:
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ActionLogger() {}
114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void AppendAction(const std::string& action) {
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (!actions_.empty())
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      actions_ += ",";
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    actions_ += action;
1193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
1203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Returns a comma-separated string describing the actions that were
122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // requested since the previous call to GetActionsAndClear() (i.e.
123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // results are non-repeatable).
124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string GetActionsAndClear() {
125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    std::string actions = actions_;
126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    actions_.clear();
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return actions;
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private:
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string actions_;
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(ActionLogger);
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
136a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)class TestNativeDisplayDelegate : public NativeDisplayDelegate {
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public:
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Ownership of |log| remains with the caller.
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  explicit TestNativeDisplayDelegate(ActionLogger* log)
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      : max_configurable_pixels_(0),
141a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        hdcp_state_(HDCP_STATE_UNDESIRED),
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        log_(log) {}
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual ~TestNativeDisplayDelegate() {}
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
14523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  const std::vector<DisplaySnapshot*>& outputs() const { return outputs_; }
14623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  void set_outputs(const std::vector<DisplaySnapshot*>& outputs) {
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    outputs_ = outputs;
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void set_max_configurable_pixels(int pixels) {
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    max_configurable_pixels_ = pixels;
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
154a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  void set_hdcp_state(HDCPState state) { hdcp_state_ = state; }
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
156c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // DisplayConfigurator::Delegate overrides:
157a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  virtual void Initialize() OVERRIDE { log_->AppendAction(kInitXRandR); }
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual void GrabServer() OVERRIDE { log_->AppendAction(kGrab); }
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual void UngrabServer() OVERRIDE { log_->AppendAction(kUngrab); }
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual void SyncWithServer() OVERRIDE { log_->AppendAction(kSync); }
161effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  virtual void SetBackgroundColor(uint32_t color_argb) OVERRIDE {
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    log_->AppendAction(GetBackgroundAction(color_argb));
163c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  virtual void ForceDPMSOn() OVERRIDE { log_->AppendAction(kForceDPMS); }
165c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  virtual std::vector<DisplaySnapshot*> GetDisplays() OVERRIDE {
166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return outputs_;
167c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
16823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  virtual void AddMode(const DisplaySnapshot& output,
16923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                       const DisplayMode* mode) OVERRIDE {
17023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    log_->AppendAction(GetAddOutputModeAction(output, mode));
171d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  }
17223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  virtual bool Configure(const DisplaySnapshot& output,
17323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                         const DisplayMode* mode,
17423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                         const gfx::Point& origin) OVERRIDE {
17523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    log_->AppendAction(GetCrtcAction(output, mode, origin));
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (max_configurable_pixels_ == 0)
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return true;
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
18023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    if (!mode)
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return false;
1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
18323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return mode->size().GetArea() <= max_configurable_pixels_;
184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
18523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  virtual void CreateFrameBuffer(const gfx::Size& size) OVERRIDE {
1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    log_->AppendAction(
18723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        GetFramebufferAction(size,
18823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                             outputs_.size() >= 1 ? outputs_[0] : NULL,
18923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                             outputs_.size() >= 2 ? outputs_[1] : NULL));
190c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
19123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  virtual bool GetHDCPState(const DisplaySnapshot& output,
192a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                            HDCPState* state) OVERRIDE {
1934e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    *state = hdcp_state_;
1944e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return true;
1954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
1964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
19723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  virtual bool SetHDCPState(const DisplaySnapshot& output,
198a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                            HDCPState state) OVERRIDE {
19923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    log_->AppendAction(GetSetHDCPStateAction(output, state));
2004e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    return true;
2014e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  }
2024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
203effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  virtual std::vector<ui::ColorCalibrationProfile>
204c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  GetAvailableColorCalibrationProfiles(const DisplaySnapshot& output) OVERRIDE {
205effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    return std::vector<ui::ColorCalibrationProfile>();
206effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  }
207effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch
20823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  virtual bool SetColorCalibrationProfile(
20923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      const DisplaySnapshot& output,
21023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      ui::ColorCalibrationProfile new_profile) OVERRIDE {
21123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    return false;
21223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  }
21323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
214a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  virtual void AddObserver(NativeDisplayObserver* observer) OVERRIDE {}
215a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
216a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  virtual void RemoveObserver(NativeDisplayObserver* observer) OVERRIDE {}
217a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
218c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) private:
219c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // Outputs to be returned by GetDisplays().
22023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  std::vector<DisplaySnapshot*> outputs_;
221c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // |max_configurable_pixels_| represents the maximum number of pixels that
223a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // Configure will support.  Tests can use this to force Configure
2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // to fail if attempting to set a resolution that is higher than what
2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // a device might support under a given circumstance.
226a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  // A value of 0 means that no limit is enforced and Configure will
2275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // return success regardless of the resolution.
228a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  int max_configurable_pixels_;
2293551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Result value of GetHDCPState().
231a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  HDCPState hdcp_state_;
2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ActionLogger* log_;  // Not owned.
2344e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(TestNativeDisplayDelegate);
236c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)};
237c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
238c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochclass TestObserver : public DisplayConfigurator::Observer {
2393551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) public:
240c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  explicit TestObserver(DisplayConfigurator* configurator)
2413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      : configurator_(configurator) {
2423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    Reset();
2433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    configurator_->AddObserver(this);
2443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
245a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  virtual ~TestObserver() { configurator_->RemoveObserver(this); }
2463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  int num_changes() const { return num_changes_; }
2483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  int num_failures() const { return num_failures_; }
249c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  const DisplayConfigurator::DisplayStateList& latest_outputs() const {
2503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return latest_outputs_;
2513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
252c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  MultipleDisplayState latest_failed_state() const {
253c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return latest_failed_state_;
254c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
2553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2563551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  void Reset() {
2573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    num_changes_ = 0;
2583551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    num_failures_ = 0;
2593551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    latest_outputs_.clear();
260c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    latest_failed_state_ = MULTIPLE_DISPLAY_STATE_INVALID;
2613551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
2623551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
263c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // DisplayConfigurator::Observer overrides:
2643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  virtual void OnDisplayModeChanged(
265c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      const DisplayConfigurator::DisplayStateList& outputs) OVERRIDE {
2663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    num_changes_++;
2673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    latest_outputs_ = outputs;
2683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
2693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
270c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  virtual void OnDisplayModeChangeFailed(MultipleDisplayState failed_new_state)
2713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)      OVERRIDE {
2723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    num_failures_++;
2733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    latest_failed_state_ = failed_new_state;
2743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  }
2753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2763551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) private:
277c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  DisplayConfigurator* configurator_;  // Not owned.
2783551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Number of times that OnDisplayMode*() has been called.
2803551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  int num_changes_;
2813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  int num_failures_;
2823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // Parameters most recently passed to OnDisplayMode*().
284c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  DisplayConfigurator::DisplayStateList latest_outputs_;
285c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  MultipleDisplayState latest_failed_state_;
2863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
2873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(TestObserver);
2883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)};
2893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
290c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochclass TestStateController : public DisplayConfigurator::StateController {
291c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) public:
292c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  TestStateController() : state_(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED) {}
293c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  virtual ~TestStateController() {}
294c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
295c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  void set_state(MultipleDisplayState state) { state_ = state; }
296c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
297c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // DisplayConfigurator::StateController overrides:
298c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  virtual MultipleDisplayState GetStateForDisplayIds(
299effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch      const std::vector<int64_t>& outputs) const OVERRIDE {
3005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return state_;
3015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
302effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch  virtual bool GetResolutionForDisplayId(int64_t display_id,
30323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                                         gfx::Size* size) const OVERRIDE {
304a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    return false;
305a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  }
306c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
307c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) private:
308c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  MultipleDisplayState state_;
309c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
310c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(TestStateController);
311c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)};
312c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
31390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)class TestMirroringController
314c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    : public DisplayConfigurator::SoftwareMirroringController {
31590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) public:
31690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  TestMirroringController() : software_mirroring_enabled_(false) {}
31790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual ~TestMirroringController() {}
31890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
31990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual void SetSoftwareMirroring(bool enabled) OVERRIDE {
32090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    software_mirroring_enabled_ = enabled;
32190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
32290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
323cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  virtual bool SoftwareMirroringEnabled() const OVERRIDE {
32490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return software_mirroring_enabled_;
32590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
32690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
32790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) private:
32890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  bool software_mirroring_enabled_;
32990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
33090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(TestMirroringController);
33190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)};
33290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
333c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochclass DisplayConfiguratorTest : public testing::Test {
334c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) public:
335c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  DisplayConfiguratorTest()
33623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      : small_mode_(gfx::Size(1366, 768), false, 60.0f),
33723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        big_mode_(gfx::Size(2560, 1600), false, 60.0f),
33823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        observer_(&configurator_),
33923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)        test_api_(&configurator_) {}
340c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  virtual ~DisplayConfiguratorTest() {}
341c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
342c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  virtual void SetUp() OVERRIDE {
3435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    log_.reset(new ActionLogger());
3445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    native_display_delegate_ = new TestNativeDisplayDelegate(log_.get());
3461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    configurator_.SetDelegateForTesting(
3471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        scoped_ptr<NativeDisplayDelegate>(native_display_delegate_));
3485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
349c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    configurator_.set_state_controller(&state_controller_);
35090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    configurator_.set_mirroring_controller(&mirroring_controller_);
351c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
35223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    std::vector<const DisplayMode*> modes;
35323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    modes.push_back(&small_mode_);
35423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
35523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    TestDisplaySnapshot* o = &outputs_[0];
35623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    o->set_current_mode(&small_mode_);
35723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    o->set_native_mode(&small_mode_);
35823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    o->set_modes(modes);
359c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    o->set_type(DISPLAY_CONNECTION_TYPE_INTERNAL);
36023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    o->set_is_aspect_preserving_scaling(true);
36123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    o->set_display_id(123);
36223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    o->set_has_proper_display_id(true);
363c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
364c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    o = &outputs_[1];
36523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    o->set_current_mode(&big_mode_);
36623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    o->set_native_mode(&big_mode_);
36723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    modes.push_back(&big_mode_);
36823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    o->set_modes(modes);
369c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    o->set_type(DISPLAY_CONNECTION_TYPE_HDMI);
37023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    o->set_is_aspect_preserving_scaling(true);
37123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    o->set_display_id(456);
37223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    o->set_has_proper_display_id(true);
373c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
3743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    UpdateOutputs(2, false);
375c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
376c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
37723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // Predefined modes that can be used by outputs.
37823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  const DisplayMode small_mode_;
37923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  const DisplayMode big_mode_;
38023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
381c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) protected:
3825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Configures |native_display_delegate_| to return the first |num_outputs|
3835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // entries from
3843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // |outputs_|. If |send_events| is true, also sends screen-change and
3853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // output-change events to |configurator_| and triggers the configure
3863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // timeout if one was scheduled.
3873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  void UpdateOutputs(size_t num_outputs, bool send_events) {
388c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    ASSERT_LE(num_outputs, arraysize(outputs_));
38923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    std::vector<DisplaySnapshot*> outputs;
390c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    for (size_t i = 0; i < num_outputs; ++i)
39123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      outputs.push_back(&outputs_[i]);
3925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    native_display_delegate_->set_outputs(outputs);
3933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    if (send_events) {
395a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      configurator_.OnConfigurationChanged();
3966e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      EXPECT_TRUE(test_api_.TriggerConfigureTimeout());
3973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    }
398c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
399c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
400c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Initializes |configurator_| with a single internal display.
4013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  void InitWithSingleOutput() {
4023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    UpdateOutputs(1, false);
4035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_EQ(kNoActions, log_->GetActionsAndClear());
404a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)    configurator_.Init(false);
4055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_EQ(kNoActions, log_->GetActionsAndClear());
406a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    configurator_.ForceInitialConfigure(0);
4075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_EQ(
4085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        JoinActions(
4095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            kGrab,
4105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            kInitXRandR,
41123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)            GetFramebufferAction(small_mode_.size(), &outputs_[0], NULL)
4125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                .c_str(),
41323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)            GetCrtcAction(outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(),
4145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            kForceDPMS,
4155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            kUngrab,
4165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            NULL),
4175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        log_->GetActionsAndClear());
418c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
419c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
420c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  base::MessageLoop message_loop_;
421c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  TestStateController state_controller_;
42290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  TestMirroringController mirroring_controller_;
423c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  DisplayConfigurator configurator_;
4243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  TestObserver observer_;
4255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<ActionLogger> log_;
4265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  TestNativeDisplayDelegate* native_display_delegate_;  // not owned
427c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  DisplayConfigurator::TestApi test_api_;
428c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
42923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  TestDisplaySnapshot outputs_[2];
430c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
431c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) private:
432c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  DISALLOW_COPY_AND_ASSIGN(DisplayConfiguratorTest);
433c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)};
434c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
435c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}  // namespace
4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
437c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochTEST_F(DisplayConfiguratorTest, FindDisplayModeMatchingSize) {
43823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  ScopedVector<const DisplayMode> modes;
439d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
440d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Fields are width, height, interlaced, refresh rate.
44123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  modes.push_back(new DisplayMode(gfx::Size(1920, 1200), false, 60.0));
442d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Different rates.
44323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  modes.push_back(new DisplayMode(gfx::Size(1920, 1080), false, 30.0));
44423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  modes.push_back(new DisplayMode(gfx::Size(1920, 1080), false, 50.0));
44523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  modes.push_back(new DisplayMode(gfx::Size(1920, 1080), false, 40.0));
44623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  modes.push_back(new DisplayMode(gfx::Size(1920, 1080), false, 0.0));
447d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Interlaced vs non-interlaced.
44823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  modes.push_back(new DisplayMode(gfx::Size(1280, 720), true, 60.0));
44923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  modes.push_back(new DisplayMode(gfx::Size(1280, 720), false, 40.0));
450d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Interlaced only.
45123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  modes.push_back(new DisplayMode(gfx::Size(1024, 768), true, 0.0));
45223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  modes.push_back(new DisplayMode(gfx::Size(1024, 768), true, 40.0));
45323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  modes.push_back(new DisplayMode(gfx::Size(1024, 768), true, 60.0));
454d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Mixed.
45523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  modes.push_back(new DisplayMode(gfx::Size(1024, 600), true, 60.0));
45623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  modes.push_back(new DisplayMode(gfx::Size(1024, 600), false, 40.0));
45723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  modes.push_back(new DisplayMode(gfx::Size(1024, 600), false, 50.0));
458d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Just one interlaced mode.
45923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  modes.push_back(new DisplayMode(gfx::Size(640, 480), true, 60.0));
460d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Refresh rate not available.
46123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  modes.push_back(new DisplayMode(gfx::Size(320, 200), false, 0.0));
462d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
46323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  TestDisplaySnapshot output;
46423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  output.set_modes(modes.get());
46523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
46623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  EXPECT_EQ(modes[0],
467c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch            DisplayConfigurator::FindDisplayModeMatchingSize(
46823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                output, gfx::Size(1920, 1200)));
469d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
470d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Should pick highest refresh rate.
47123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  EXPECT_EQ(modes[2],
472c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch            DisplayConfigurator::FindDisplayModeMatchingSize(
47323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                output, gfx::Size(1920, 1080)));
474d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
475d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Should pick non-interlaced mode.
47623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  EXPECT_EQ(modes[6],
477c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch            DisplayConfigurator::FindDisplayModeMatchingSize(
47823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                output, gfx::Size(1280, 720)));
479d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
480d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Interlaced only. Should pick one with the highest refresh rate in
481d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // interlaced mode.
48223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  EXPECT_EQ(modes[9],
483c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch            DisplayConfigurator::FindDisplayModeMatchingSize(
48423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                output, gfx::Size(1024, 768)));
485d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
486d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Mixed: Should pick one with the highest refresh rate in
487d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // interlaced mode.
48823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  EXPECT_EQ(modes[12],
489c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch            DisplayConfigurator::FindDisplayModeMatchingSize(
49023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                output, gfx::Size(1024, 600)));
491d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
492d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Just one interlaced mode.
49323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  EXPECT_EQ(modes[13],
494c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch            DisplayConfigurator::FindDisplayModeMatchingSize(
49523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                output, gfx::Size(640, 480)));
496d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
497d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Refresh rate not available.
49823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  EXPECT_EQ(modes[14],
499c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch            DisplayConfigurator::FindDisplayModeMatchingSize(
50023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                output, gfx::Size(320, 200)));
501d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
502d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // No mode found.
50323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  EXPECT_EQ(NULL,
504c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch            DisplayConfigurator::FindDisplayModeMatchingSize(
50523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                output, gfx::Size(1440, 900)));
506d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
507d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
508c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochTEST_F(DisplayConfiguratorTest, ConnectSecondOutput) {
509c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  InitWithSingleOutput();
510c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
511c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Connect a second output and check that the configurator enters
512c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // extended mode.
5133551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  observer_.Reset();
514c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  state_controller_.set_state(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED);
5153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  UpdateOutputs(2, true);
51623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  const int kDualHeight = small_mode_.size().height() +
517c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                          DisplayConfigurator::kVerticalGap +
51823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                          big_mode_.size().height();
5195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
5205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      JoinActions(
5215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kGrab,
52223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetFramebufferAction(gfx::Size(big_mode_.size().width(), kDualHeight),
52323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                               &outputs_[0],
52423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                               &outputs_[1]).c_str(),
52523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetCrtcAction(outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(),
52623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetCrtcAction(outputs_[1],
52723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                        &big_mode_,
52823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                        gfx::Point(0,
52923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                                   small_mode_.size().height() +
530c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                       DisplayConfigurator::kVerticalGap))
5315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              .c_str(),
5325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kUngrab,
5335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          NULL),
5345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      log_->GetActionsAndClear());
535cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_FALSE(mirroring_controller_.SoftwareMirroringEnabled());
5363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  EXPECT_EQ(1, observer_.num_changes());
537c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
5383551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  observer_.Reset();
539c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_TRUE(configurator_.SetDisplayMode(MULTIPLE_DISPLAY_STATE_DUAL_MIRROR));
5405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
5415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      JoinActions(
5425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kGrab,
54323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetFramebufferAction(small_mode_.size(), &outputs_[0], &outputs_[1])
54423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)              .c_str(),
54523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetCrtcAction(outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(),
54623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetCrtcAction(outputs_[1], &small_mode_, gfx::Point(0, 0)).c_str(),
5475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kUngrab,
5485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          NULL),
5495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      log_->GetActionsAndClear());
550cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_FALSE(mirroring_controller_.SoftwareMirroringEnabled());
5513551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  EXPECT_EQ(1, observer_.num_changes());
55290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
55390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Disconnect the second output.
5543551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  observer_.Reset();
5553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  UpdateOutputs(1, true);
5565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
5575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      JoinActions(
5585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kGrab,
55923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetFramebufferAction(small_mode_.size(), &outputs_[0], NULL).c_str(),
56023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetCrtcAction(outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(),
5615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kUngrab,
5625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          NULL),
5635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      log_->GetActionsAndClear());
564cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_FALSE(mirroring_controller_.SoftwareMirroringEnabled());
5653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  EXPECT_EQ(1, observer_.num_changes());
56690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
567d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Get rid of shared modes to force software mirroring.
56823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  outputs_[1].set_modes(std::vector<const DisplayMode*>(1, &big_mode_));
569c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  state_controller_.set_state(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED);
5703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  UpdateOutputs(2, true);
5715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
5725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      JoinActions(
5735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kGrab,
57423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetFramebufferAction(gfx::Size(big_mode_.size().width(), kDualHeight),
57523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                               &outputs_[0],
57623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                               &outputs_[1]).c_str(),
57723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetCrtcAction(outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(),
57823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetCrtcAction(outputs_[1],
57923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                        &big_mode_,
58023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                        gfx::Point(0,
58123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                                   small_mode_.size().height() +
582c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                       DisplayConfigurator::kVerticalGap))
5835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              .c_str(),
5845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kUngrab,
5855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          NULL),
5865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      log_->GetActionsAndClear());
587cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_FALSE(mirroring_controller_.SoftwareMirroringEnabled());
58890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  observer_.Reset();
590c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_TRUE(configurator_.SetDisplayMode(MULTIPLE_DISPLAY_STATE_DUAL_MIRROR));
5915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(JoinActions(kGrab, kUngrab, NULL), log_->GetActionsAndClear());
592c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED,
593c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch            configurator_.display_state());
594cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_TRUE(mirroring_controller_.SoftwareMirroringEnabled());
5953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  EXPECT_EQ(1, observer_.num_changes());
596c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
597c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // Setting MULTIPLE_DISPLAY_STATE_DUAL_MIRROR should try to reconfigure.
5983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  observer_.Reset();
599c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_TRUE(
600c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      configurator_.SetDisplayMode(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED));
6015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(JoinActions(NULL), log_->GetActionsAndClear());
602cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_FALSE(mirroring_controller_.SoftwareMirroringEnabled());
6033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  EXPECT_EQ(1, observer_.num_changes());
604868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
605868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Set back to software mirror mode.
6063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  observer_.Reset();
607c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_TRUE(configurator_.SetDisplayMode(MULTIPLE_DISPLAY_STATE_DUAL_MIRROR));
6085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(JoinActions(kGrab, kUngrab, NULL), log_->GetActionsAndClear());
609c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED,
610c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch            configurator_.display_state());
611cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_TRUE(mirroring_controller_.SoftwareMirroringEnabled());
6123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  EXPECT_EQ(1, observer_.num_changes());
613868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
614c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Disconnect the second output.
6153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  observer_.Reset();
6163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  UpdateOutputs(1, true);
6175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
6185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      JoinActions(
6195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kGrab,
62023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetFramebufferAction(small_mode_.size(), &outputs_[0], NULL).c_str(),
62123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetCrtcAction(outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(),
6225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kUngrab,
6235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          NULL),
6245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      log_->GetActionsAndClear());
625cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_FALSE(mirroring_controller_.SoftwareMirroringEnabled());
6263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  EXPECT_EQ(1, observer_.num_changes());
627c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
628c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
629c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochTEST_F(DisplayConfiguratorTest, SetDisplayPower) {
630c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  InitWithSingleOutput();
631c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
632c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  state_controller_.set_state(MULTIPLE_DISPLAY_STATE_DUAL_MIRROR);
6333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  observer_.Reset();
6343551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  UpdateOutputs(2, true);
6355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
6365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      JoinActions(
6375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kGrab,
63823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetFramebufferAction(small_mode_.size(), &outputs_[0], &outputs_[1])
63923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)              .c_str(),
64023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetCrtcAction(outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(),
64123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetCrtcAction(outputs_[1], &small_mode_, gfx::Point(0, 0)).c_str(),
6425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kUngrab,
6435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          NULL),
6445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      log_->GetActionsAndClear());
645cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_FALSE(mirroring_controller_.SoftwareMirroringEnabled());
6463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  EXPECT_EQ(1, observer_.num_changes());
647c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
648c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Turning off the internal display should switch the external display to
649c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // its native mode.
6503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  observer_.Reset();
651a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  configurator_.SetDisplayPower(
652a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON,
653c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      DisplayConfigurator::kSetDisplayPowerNoFlags);
6545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
6555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      JoinActions(
6565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kGrab,
65723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetFramebufferAction(big_mode_.size(), &outputs_[0], &outputs_[1])
6585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              .c_str(),
65923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetCrtcAction(outputs_[0], NULL, gfx::Point(0, 0)).c_str(),
66023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetCrtcAction(outputs_[1], &big_mode_, gfx::Point(0, 0)).c_str(),
6615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kForceDPMS,
6625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kUngrab,
6635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          NULL),
6645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      log_->GetActionsAndClear());
665c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(MULTIPLE_DISPLAY_STATE_SINGLE, configurator_.display_state());
6663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  EXPECT_EQ(1, observer_.num_changes());
667c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
668c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // When all displays are turned off, the framebuffer should switch back
669c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // to the mirrored size.
6703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  observer_.Reset();
671a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  configurator_.SetDisplayPower(chromeos::DISPLAY_POWER_ALL_OFF,
672c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                DisplayConfigurator::kSetDisplayPowerNoFlags);
6735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
67423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      JoinActions(kGrab,
67523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                  GetFramebufferAction(
67623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                      small_mode_.size(), &outputs_[0], &outputs_[1]).c_str(),
67723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                  GetCrtcAction(outputs_[0], NULL, gfx::Point(0, 0)).c_str(),
67823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                  GetCrtcAction(outputs_[1], NULL, gfx::Point(0, 0)).c_str(),
67923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                  kUngrab,
68023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                  NULL),
6815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      log_->GetActionsAndClear());
682c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(MULTIPLE_DISPLAY_STATE_DUAL_MIRROR, configurator_.display_state());
683cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_FALSE(mirroring_controller_.SoftwareMirroringEnabled());
6843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  EXPECT_EQ(1, observer_.num_changes());
685c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
686c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Turn all displays on and check that mirroring is still used.
6873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  observer_.Reset();
688a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  configurator_.SetDisplayPower(chromeos::DISPLAY_POWER_ALL_ON,
689c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                DisplayConfigurator::kSetDisplayPowerNoFlags);
6905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
6915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      JoinActions(
6925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kGrab,
69323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetFramebufferAction(small_mode_.size(), &outputs_[0], &outputs_[1])
69423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)              .c_str(),
69523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetCrtcAction(outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(),
69623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetCrtcAction(outputs_[1], &small_mode_, gfx::Point(0, 0)).c_str(),
6975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kForceDPMS,
6985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kUngrab,
6995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          NULL),
7005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      log_->GetActionsAndClear());
701c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(MULTIPLE_DISPLAY_STATE_DUAL_MIRROR, configurator_.display_state());
702cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_FALSE(mirroring_controller_.SoftwareMirroringEnabled());
7033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  EXPECT_EQ(1, observer_.num_changes());
70490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
705d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Get rid of shared modes to force software mirroring.
70623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  outputs_[1].set_modes(std::vector<const DisplayMode*>(1, &big_mode_));
707c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  state_controller_.set_state(MULTIPLE_DISPLAY_STATE_DUAL_MIRROR);
7083551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  observer_.Reset();
7093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  UpdateOutputs(2, true);
71023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  const int kDualHeight = small_mode_.size().height() +
711c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                          DisplayConfigurator::kVerticalGap +
71223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                          big_mode_.size().height();
7135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
7145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      JoinActions(
7155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kGrab,
71623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetFramebufferAction(gfx::Size(big_mode_.size().width(), kDualHeight),
71723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                               &outputs_[0],
71823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                               &outputs_[1]).c_str(),
71923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetCrtcAction(outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(),
72023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetCrtcAction(outputs_[1],
72123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                        &big_mode_,
72223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                        gfx::Point(0,
72323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                                   small_mode_.size().height() +
724c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                       DisplayConfigurator::kVerticalGap))
7255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              .c_str(),
7265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kUngrab,
7275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          NULL),
7285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      log_->GetActionsAndClear());
729c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED,
730c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch            configurator_.display_state());
731cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_TRUE(mirroring_controller_.SoftwareMirroringEnabled());
7323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  EXPECT_EQ(1, observer_.num_changes());
73390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
73490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Turning off the internal display should switch the external display to
73590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // its native mode.
7363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  observer_.Reset();
737a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  configurator_.SetDisplayPower(
738a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON,
739c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      DisplayConfigurator::kSetDisplayPowerNoFlags);
7405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
7415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      JoinActions(
7425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kGrab,
74323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetFramebufferAction(big_mode_.size(), &outputs_[0], &outputs_[1])
7445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              .c_str(),
74523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetCrtcAction(outputs_[0], NULL, gfx::Point(0, 0)).c_str(),
74623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetCrtcAction(outputs_[1], &big_mode_, gfx::Point(0, 0)).c_str(),
7475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kForceDPMS,
7485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kUngrab,
7495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          NULL),
7505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      log_->GetActionsAndClear());
751c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(MULTIPLE_DISPLAY_STATE_SINGLE, configurator_.display_state());
752cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_FALSE(mirroring_controller_.SoftwareMirroringEnabled());
7533551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  EXPECT_EQ(1, observer_.num_changes());
75490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
75590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // When all displays are turned off, the framebuffer should switch back
75690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // to the extended + software mirroring.
7573551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  observer_.Reset();
758a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  configurator_.SetDisplayPower(chromeos::DISPLAY_POWER_ALL_OFF,
759c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                DisplayConfigurator::kSetDisplayPowerNoFlags);
7605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
7615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      JoinActions(
7625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kGrab,
76323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetFramebufferAction(gfx::Size(big_mode_.size().width(), kDualHeight),
76423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                               &outputs_[0],
76523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                               &outputs_[1]).c_str(),
76623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetCrtcAction(outputs_[0], NULL, gfx::Point(0, 0)).c_str(),
76723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetCrtcAction(outputs_[1],
76823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                        NULL,
76923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                        gfx::Point(0,
77023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                                   small_mode_.size().height() +
771c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                       DisplayConfigurator::kVerticalGap))
7725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              .c_str(),
7735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kUngrab,
7745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          NULL),
7755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      log_->GetActionsAndClear());
776c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED,
777c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch            configurator_.display_state());
778cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_TRUE(mirroring_controller_.SoftwareMirroringEnabled());
7793551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  EXPECT_EQ(1, observer_.num_changes());
78090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
78190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Turn all displays on and check that mirroring is still used.
7823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  observer_.Reset();
783a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  configurator_.SetDisplayPower(chromeos::DISPLAY_POWER_ALL_ON,
784c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                DisplayConfigurator::kSetDisplayPowerNoFlags);
7855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
7865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      JoinActions(
7875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kGrab,
78823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetFramebufferAction(gfx::Size(big_mode_.size().width(), kDualHeight),
78923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                               &outputs_[0],
79023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                               &outputs_[1]).c_str(),
79123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetCrtcAction(outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(),
79223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetCrtcAction(outputs_[1],
79323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                        &big_mode_,
79423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                        gfx::Point(0,
79523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                                   small_mode_.size().height() +
796c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                       DisplayConfigurator::kVerticalGap))
7975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              .c_str(),
7985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kForceDPMS,
7995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kUngrab,
8005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          NULL),
8015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      log_->GetActionsAndClear());
802c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED,
803c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch            configurator_.display_state());
804cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  EXPECT_TRUE(mirroring_controller_.SoftwareMirroringEnabled());
8053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  EXPECT_EQ(1, observer_.num_changes());
806c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
807c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
808c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochTEST_F(DisplayConfiguratorTest, SuspendAndResume) {
809c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  InitWithSingleOutput();
810c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
811c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // No preparation is needed before suspending when the display is already
812c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // on.  The configurator should still reprobe on resume in case a display
813c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // was connected while suspended.
814c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  configurator_.SuspendDisplays();
8155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(kNoActions, log_->GetActionsAndClear());
816c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  configurator_.ResumeDisplays();
8176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  EXPECT_TRUE(test_api_.TriggerConfigureTimeout());
8185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
8195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      JoinActions(
8205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kGrab,
82123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetFramebufferAction(small_mode_.size(), &outputs_[0], NULL).c_str(),
82223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetCrtcAction(outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(),
8235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kForceDPMS,
8245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kUngrab,
8255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          NULL),
8265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      log_->GetActionsAndClear());
827c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
828c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Now turn the display off before suspending and check that the
829c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // configurator turns it back on and syncs with the server.
830a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  configurator_.SetDisplayPower(chromeos::DISPLAY_POWER_ALL_OFF,
831c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                DisplayConfigurator::kSetDisplayPowerNoFlags);
8325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
8335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      JoinActions(
8345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kGrab,
83523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetFramebufferAction(small_mode_.size(), &outputs_[0], NULL).c_str(),
83623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetCrtcAction(outputs_[0], NULL, gfx::Point(0, 0)).c_str(),
8375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kUngrab,
8385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          NULL),
8395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      log_->GetActionsAndClear());
840c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
841c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  configurator_.SuspendDisplays();
8425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
8435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      JoinActions(
8445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kGrab,
84523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetFramebufferAction(small_mode_.size(), &outputs_[0], NULL).c_str(),
84623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetCrtcAction(outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(),
8475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kForceDPMS,
8485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kUngrab,
8495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kSync,
8505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          NULL),
8515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      log_->GetActionsAndClear());
852c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
853c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  configurator_.ResumeDisplays();
8546e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  EXPECT_TRUE(test_api_.TriggerConfigureTimeout());
8555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
8565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      JoinActions(
8575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kGrab,
85823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetFramebufferAction(small_mode_.size(), &outputs_[0], NULL).c_str(),
85923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetCrtcAction(outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(),
8605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kForceDPMS,
8615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kUngrab,
8625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          NULL),
8635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      log_->GetActionsAndClear());
864c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
865c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // If a second, external display is connected, the displays shouldn't be
866c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // powered back on before suspending.
867c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  state_controller_.set_state(MULTIPLE_DISPLAY_STATE_DUAL_MIRROR);
8683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  UpdateOutputs(2, true);
8695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
8705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      JoinActions(
8715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kGrab,
87223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetFramebufferAction(small_mode_.size(), &outputs_[0], &outputs_[1])
87323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)              .c_str(),
87423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetCrtcAction(outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(),
87523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetCrtcAction(outputs_[1], &small_mode_, gfx::Point(0, 0)).c_str(),
8765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kUngrab,
8775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          NULL),
8785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      log_->GetActionsAndClear());
879c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
880a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  configurator_.SetDisplayPower(chromeos::DISPLAY_POWER_ALL_OFF,
881c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                DisplayConfigurator::kSetDisplayPowerNoFlags);
8825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
88323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      JoinActions(kGrab,
88423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                  GetFramebufferAction(
88523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                      small_mode_.size(), &outputs_[0], &outputs_[1]).c_str(),
88623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                  GetCrtcAction(outputs_[0], NULL, gfx::Point(0, 0)).c_str(),
88723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                  GetCrtcAction(outputs_[1], NULL, gfx::Point(0, 0)).c_str(),
88823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                  kUngrab,
88923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                  NULL),
8905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      log_->GetActionsAndClear());
891c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
892c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  configurator_.SuspendDisplays();
893c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EXPECT_EQ(JoinActions(kGrab, kUngrab, kSync, NULL),
8945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            log_->GetActionsAndClear());
895c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
8963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  // If a display is disconnected while suspended, the configurator should
897c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // pick up the change.
8983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  UpdateOutputs(1, false);
899c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  configurator_.ResumeDisplays();
9006e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  EXPECT_TRUE(test_api_.TriggerConfigureTimeout());
9015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
9025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      JoinActions(
9035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kGrab,
90423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetFramebufferAction(small_mode_.size(), &outputs_[0], NULL).c_str(),
90523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetCrtcAction(outputs_[0], NULL, gfx::Point(0, 0)).c_str(),
9065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kUngrab,
9075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          NULL),
9085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      log_->GetActionsAndClear());
909c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
910c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
911c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochTEST_F(DisplayConfiguratorTest, Headless) {
9123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  UpdateOutputs(0, false);
9135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(kNoActions, log_->GetActionsAndClear());
914a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  configurator_.Init(false);
9155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(kNoActions, log_->GetActionsAndClear());
916a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  configurator_.ForceInitialConfigure(0);
9175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(JoinActions(kGrab, kInitXRandR, kForceDPMS, kUngrab, NULL),
9185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            log_->GetActionsAndClear());
919c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
920c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Not much should happen when the display power state is changed while
921c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // no displays are connected.
922a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  configurator_.SetDisplayPower(chromeos::DISPLAY_POWER_ALL_OFF,
923c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                DisplayConfigurator::kSetDisplayPowerNoFlags);
9245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(JoinActions(kGrab, kUngrab, NULL), log_->GetActionsAndClear());
925a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  configurator_.SetDisplayPower(chromeos::DISPLAY_POWER_ALL_ON,
926c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                DisplayConfigurator::kSetDisplayPowerNoFlags);
927c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EXPECT_EQ(JoinActions(kGrab, kForceDPMS, kUngrab, NULL),
9285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            log_->GetActionsAndClear());
929c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
930c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Connect an external display and check that it's configured correctly.
93123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  outputs_[0].set_current_mode(outputs_[1].current_mode());
93223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  outputs_[0].set_native_mode(outputs_[1].native_mode());
93323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  outputs_[0].set_modes(outputs_[1].modes());
93423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  outputs_[0].set_type(outputs_[1].type());
93523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
9363551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  UpdateOutputs(1, true);
9375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
9385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      JoinActions(
9395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kGrab,
94023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetFramebufferAction(big_mode_.size(), &outputs_[0], NULL).c_str(),
94123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetCrtcAction(outputs_[0], &big_mode_, gfx::Point(0, 0)).c_str(),
9425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kUngrab,
9435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          NULL),
9445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      log_->GetActionsAndClear());
945c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
946c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
947c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochTEST_F(DisplayConfiguratorTest, StartWithTwoOutputs) {
9483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  UpdateOutputs(2, false);
9495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(kNoActions, log_->GetActionsAndClear());
950a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  configurator_.Init(false);
9515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(kNoActions, log_->GetActionsAndClear());
952c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
953c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  state_controller_.set_state(MULTIPLE_DISPLAY_STATE_DUAL_MIRROR);
954a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  configurator_.ForceInitialConfigure(0);
9555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
9565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      JoinActions(
9575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kGrab,
9585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kInitXRandR,
95923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetFramebufferAction(small_mode_.size(), &outputs_[0], &outputs_[1])
96023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)              .c_str(),
96123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetCrtcAction(outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(),
96223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetCrtcAction(outputs_[1], &small_mode_, gfx::Point(0, 0)).c_str(),
9635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kForceDPMS,
9645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kUngrab,
9655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          NULL),
9665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      log_->GetActionsAndClear());
967c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
968c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
969c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochTEST_F(DisplayConfiguratorTest, InvalidMultipleDisplayStates) {
9703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  UpdateOutputs(0, false);
9715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(kNoActions, log_->GetActionsAndClear());
972a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  configurator_.Init(false);
973a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  configurator_.ForceInitialConfigure(0);
9743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  observer_.Reset();
975c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_TRUE(configurator_.SetDisplayMode(MULTIPLE_DISPLAY_STATE_HEADLESS));
976c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_FALSE(configurator_.SetDisplayMode(MULTIPLE_DISPLAY_STATE_SINGLE));
977c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_FALSE(
978c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      configurator_.SetDisplayMode(MULTIPLE_DISPLAY_STATE_DUAL_MIRROR));
979c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_FALSE(
980c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      configurator_.SetDisplayMode(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED));
9813551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  EXPECT_EQ(1, observer_.num_changes());
9823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  EXPECT_EQ(3, observer_.num_failures());
983c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
9843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  UpdateOutputs(1, true);
9853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  observer_.Reset();
986c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_FALSE(configurator_.SetDisplayMode(MULTIPLE_DISPLAY_STATE_HEADLESS));
987c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_TRUE(configurator_.SetDisplayMode(MULTIPLE_DISPLAY_STATE_SINGLE));
988c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_FALSE(
989c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      configurator_.SetDisplayMode(MULTIPLE_DISPLAY_STATE_DUAL_MIRROR));
990c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_FALSE(
991c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      configurator_.SetDisplayMode(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED));
9923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  EXPECT_EQ(1, observer_.num_changes());
9933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  EXPECT_EQ(3, observer_.num_failures());
994c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
995c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  state_controller_.set_state(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED);
9963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  UpdateOutputs(2, true);
9973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  observer_.Reset();
998c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_FALSE(configurator_.SetDisplayMode(MULTIPLE_DISPLAY_STATE_HEADLESS));
999c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_FALSE(configurator_.SetDisplayMode(MULTIPLE_DISPLAY_STATE_SINGLE));
1000c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_TRUE(configurator_.SetDisplayMode(MULTIPLE_DISPLAY_STATE_DUAL_MIRROR));
1001c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_TRUE(
1002c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      configurator_.SetDisplayMode(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED));
10033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  EXPECT_EQ(2, observer_.num_changes());
10043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  EXPECT_EQ(2, observer_.num_failures());
1005c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}
1006c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1007c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochTEST_F(DisplayConfiguratorTest, GetMultipleDisplayStateForDisplaysWithoutId) {
100823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  outputs_[0].set_has_proper_display_id(false);
10093551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  UpdateOutputs(2, false);
1010a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  configurator_.Init(false);
1011c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  state_controller_.set_state(MULTIPLE_DISPLAY_STATE_DUAL_MIRROR);
1012a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  configurator_.ForceInitialConfigure(0);
1013c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED,
1014c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch            configurator_.display_state());
10153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
101690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1017c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochTEST_F(DisplayConfiguratorTest, GetMultipleDisplayStateForDisplaysWithId) {
101823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  outputs_[0].set_has_proper_display_id(true);
10193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  UpdateOutputs(2, false);
10203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  configurator_.Init(false);
1021c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  state_controller_.set_state(MULTIPLE_DISPLAY_STATE_DUAL_MIRROR);
1022a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  configurator_.ForceInitialConfigure(0);
1023c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(MULTIPLE_DISPLAY_STATE_DUAL_MIRROR, configurator_.display_state());
10243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
10253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1026c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochTEST_F(DisplayConfiguratorTest, UpdateCachedOutputsEvenAfterFailure) {
102768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  InitWithSingleOutput();
1028c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  const DisplayConfigurator::DisplayStateList* cached =
1029c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      &configurator_.cached_displays();
103068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  ASSERT_EQ(static_cast<size_t>(1), cached->size());
103123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  EXPECT_EQ(outputs_[0].current_mode(), (*cached)[0].display->current_mode());
103268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
103368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  // After connecting a second output, check that it shows up in
1034c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // |cached_displays_| even if an invalid state is requested.
1035c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  state_controller_.set_state(MULTIPLE_DISPLAY_STATE_SINGLE);
103668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  UpdateOutputs(2, true);
1037c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  cached = &configurator_.cached_displays();
103868043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  ASSERT_EQ(static_cast<size_t>(2), cached->size());
103923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  EXPECT_EQ(outputs_[0].current_mode(), (*cached)[0].display->current_mode());
104023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  EXPECT_EQ(outputs_[1].current_mode(), (*cached)[1].display->current_mode());
104168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)}
104268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)
1043c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochTEST_F(DisplayConfiguratorTest, PanelFitting) {
1044d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Configure the internal display to support only the big mode and the
1045d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // external display to support only the small mode.
104623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  outputs_[0].set_current_mode(&big_mode_);
104723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  outputs_[0].set_native_mode(&big_mode_);
104823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  outputs_[0].set_modes(std::vector<const DisplayMode*>(1, &big_mode_));
104923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)
105023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  outputs_[1].set_current_mode(&small_mode_);
105123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  outputs_[1].set_native_mode(&small_mode_);
105223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  outputs_[1].set_modes(std::vector<const DisplayMode*>(1, &small_mode_));
1053d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
1054d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // The small mode should be added to the internal output when requesting
1055d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // mirrored mode.
1056d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  UpdateOutputs(2, false);
1057c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  state_controller_.set_state(MULTIPLE_DISPLAY_STATE_DUAL_MIRROR);
1058d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  configurator_.Init(true /* is_panel_fitting_enabled */);
1059a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  configurator_.ForceInitialConfigure(0);
1060c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(MULTIPLE_DISPLAY_STATE_DUAL_MIRROR, configurator_.display_state());
10615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
10625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      JoinActions(
10635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kGrab,
10645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kInitXRandR,
106523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetAddOutputModeAction(outputs_[0], &small_mode_).c_str(),
106623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetFramebufferAction(small_mode_.size(), &outputs_[0], &outputs_[1])
106723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)              .c_str(),
106823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetCrtcAction(outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(),
106923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetCrtcAction(outputs_[1], &small_mode_, gfx::Point(0, 0)).c_str(),
10705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kForceDPMS,
10715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kUngrab,
10725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          NULL),
10735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      log_->GetActionsAndClear());
1074d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
1075d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Both outputs should be using the small mode.
1076d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  ASSERT_EQ(1, observer_.num_changes());
1077d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  ASSERT_EQ(static_cast<size_t>(2), observer_.latest_outputs().size());
107823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  EXPECT_EQ(&small_mode_, observer_.latest_outputs()[0].mirror_mode);
107923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  EXPECT_EQ(&small_mode_,
108023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)            observer_.latest_outputs()[0].display->current_mode());
108123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  EXPECT_EQ(&small_mode_, observer_.latest_outputs()[1].mirror_mode);
108223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  EXPECT_EQ(&small_mode_,
108323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)            observer_.latest_outputs()[1].display->current_mode());
1084d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
1085d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // Also check that the newly-added small mode is present in the internal
1086d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  // snapshot that was passed to the observer (http://crbug.com/289159).
1087c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  const DisplayConfigurator::DisplayState& state =
1088c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      observer_.latest_outputs()[0];
108923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  ASSERT_NE(state.display->modes().end(),
109023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)            std::find(state.display->modes().begin(),
109123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                      state.display->modes().end(),
109223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                      &small_mode_));
1093d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)}
1094d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)
1095c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochTEST_F(DisplayConfiguratorTest, ContentProtection) {
10964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  configurator_.Init(false);
1097a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  configurator_.ForceInitialConfigure(0);
10985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_NE(kNoActions, log_->GetActionsAndClear());
10994e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1100c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  DisplayConfigurator::ContentProtectionClientId id =
1101c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      configurator_.RegisterContentProtectionClient();
11024e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  EXPECT_NE(0u, id);
11034e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
11044e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // One output.
11054e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  UpdateOutputs(1, true);
11065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_NE(kNoActions, log_->GetActionsAndClear());
11074e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  uint32_t link_mask = 0;
11084e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  uint32_t protection_mask = 0;
1109c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_TRUE(configurator_.QueryContentProtectionStatus(
111023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      id, outputs_[0].display_id(), &link_mask, &protection_mask));
1111c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(static_cast<uint32_t>(DISPLAY_CONNECTION_TYPE_INTERNAL), link_mask);
1112c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(static_cast<uint32_t>(CONTENT_PROTECTION_METHOD_NONE),
11134e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            protection_mask);
11145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(kNoActions, log_->GetActionsAndClear());
11154e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
11164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Two outputs.
11174e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  UpdateOutputs(2, true);
11185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_NE(kNoActions, log_->GetActionsAndClear());
1119c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_TRUE(configurator_.QueryContentProtectionStatus(
112023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      id, outputs_[1].display_id(), &link_mask, &protection_mask));
1121c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(static_cast<uint32_t>(DISPLAY_CONNECTION_TYPE_HDMI), link_mask);
1122c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(static_cast<uint32_t>(CONTENT_PROTECTION_METHOD_NONE),
11234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            protection_mask);
11245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(kNoActions, log_->GetActionsAndClear());
11254e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1126c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_TRUE(configurator_.EnableContentProtection(
1127c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      id, outputs_[1].display_id(), CONTENT_PROTECTION_METHOD_HDCP));
112823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  EXPECT_EQ(GetSetHDCPStateAction(outputs_[1], HDCP_STATE_DESIRED),
11295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            log_->GetActionsAndClear());
11304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
11314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Enable protection.
1132a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  native_display_delegate_->set_hdcp_state(HDCP_STATE_ENABLED);
1133c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_TRUE(configurator_.QueryContentProtectionStatus(
113423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      id, outputs_[1].display_id(), &link_mask, &protection_mask));
1135c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(static_cast<uint32_t>(DISPLAY_CONNECTION_TYPE_HDMI), link_mask);
1136c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(static_cast<uint32_t>(CONTENT_PROTECTION_METHOD_HDCP),
11374e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)            protection_mask);
11385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(kNoActions, log_->GetActionsAndClear());
11390f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)
11400f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles)  // Protections should be disabled after unregister.
1141c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  configurator_.UnregisterContentProtectionClient(id);
114223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  EXPECT_EQ(GetSetHDCPStateAction(outputs_[1], HDCP_STATE_UNDESIRED),
11435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            log_->GetActionsAndClear());
11444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
11454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
1146c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochTEST_F(DisplayConfiguratorTest, ContentProtectionTwoClients) {
1147c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  DisplayConfigurator::ContentProtectionClientId client1 =
1148c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      configurator_.RegisterContentProtectionClient();
1149c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  DisplayConfigurator::ContentProtectionClientId client2 =
1150c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      configurator_.RegisterContentProtectionClient();
11514e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  EXPECT_NE(client1, client2);
11524e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
11534e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  configurator_.Init(false);
1154a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  configurator_.ForceInitialConfigure(0);
11554e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  UpdateOutputs(2, true);
11565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_NE(kNoActions, log_->GetActionsAndClear());
11574e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
11584e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Clients never know state enableness for methods that they didn't request.
1159c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_TRUE(configurator_.EnableContentProtection(
1160c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      client1, outputs_[1].display_id(), CONTENT_PROTECTION_METHOD_HDCP));
116123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  EXPECT_EQ(GetSetHDCPStateAction(outputs_[1], HDCP_STATE_DESIRED).c_str(),
116223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)            log_->GetActionsAndClear());
1163a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  native_display_delegate_->set_hdcp_state(HDCP_STATE_ENABLED);
11644e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
11654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  uint32_t link_mask = 0;
11664e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  uint32_t protection_mask = 0;
1167c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_TRUE(configurator_.QueryContentProtectionStatus(
116823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      client1, outputs_[1].display_id(), &link_mask, &protection_mask));
1169c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(static_cast<uint32_t>(DISPLAY_CONNECTION_TYPE_HDMI), link_mask);
1170c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(CONTENT_PROTECTION_METHOD_HDCP, protection_mask);
1171a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)
1172c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_TRUE(configurator_.QueryContentProtectionStatus(
117323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      client2, outputs_[1].display_id(), &link_mask, &protection_mask));
1174c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(static_cast<uint32_t>(DISPLAY_CONNECTION_TYPE_HDMI), link_mask);
1175c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(CONTENT_PROTECTION_METHOD_NONE, protection_mask);
11764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
11774e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)  // Protections will be disabled only if no more clients request them.
1178c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_TRUE(configurator_.EnableContentProtection(
1179c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      client2, outputs_[1].display_id(), CONTENT_PROTECTION_METHOD_NONE));
11801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  EXPECT_EQ(kNoActions, log_->GetActionsAndClear());
1181c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_TRUE(configurator_.EnableContentProtection(
1182c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      client1, outputs_[1].display_id(), CONTENT_PROTECTION_METHOD_NONE));
1183c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(GetSetHDCPStateAction(outputs_[1], HDCP_STATE_UNDESIRED).c_str(),
1184c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch            log_->GetActionsAndClear());
11854e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)}
11864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
11871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciTEST_F(DisplayConfiguratorTest, ContentProtectionTwoClientsEnable) {
11881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DisplayConfigurator::ContentProtectionClientId client1 =
11891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      configurator_.RegisterContentProtectionClient();
11901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  DisplayConfigurator::ContentProtectionClientId client2 =
11911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      configurator_.RegisterContentProtectionClient();
11921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  EXPECT_NE(client1, client2);
11931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
11941320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  configurator_.Init(false);
11951320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  configurator_.ForceInitialConfigure(0);
11961320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  UpdateOutputs(2, true);
11971320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  log_->GetActionsAndClear();
11981320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
11991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Only enable once if HDCP is enabling.
12001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  EXPECT_TRUE(configurator_.EnableContentProtection(
12011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      client1, outputs_[1].display_id(), CONTENT_PROTECTION_METHOD_HDCP));
12021320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  native_display_delegate_->set_hdcp_state(HDCP_STATE_DESIRED);
12031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  EXPECT_TRUE(configurator_.EnableContentProtection(
12041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      client2, outputs_[1].display_id(), CONTENT_PROTECTION_METHOD_HDCP));
12051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  EXPECT_EQ(GetSetHDCPStateAction(outputs_[1], HDCP_STATE_DESIRED).c_str(),
12061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            log_->GetActionsAndClear());
12071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  native_display_delegate_->set_hdcp_state(HDCP_STATE_ENABLED);
12081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
12091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Don't enable again if HDCP is already active.
12101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  EXPECT_TRUE(configurator_.EnableContentProtection(
12111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      client1, outputs_[1].display_id(), CONTENT_PROTECTION_METHOD_HDCP));
12121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  EXPECT_TRUE(configurator_.EnableContentProtection(
12131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      client2, outputs_[1].display_id(), CONTENT_PROTECTION_METHOD_HDCP));
12141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  EXPECT_EQ(kNoActions, log_->GetActionsAndClear());
12151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
12161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1217c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochTEST_F(DisplayConfiguratorTest, HandleConfigureCrtcFailure) {
12185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  InitWithSingleOutput();
12195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
122023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  ScopedVector<const DisplayMode> modes;
1221c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // The first mode is the mode we are requesting DisplayConfigurator to choose.
122223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // The test will be setup so that this mode will fail and it will have to
122323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  // choose the next best option.
122423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  modes.push_back(new DisplayMode(gfx::Size(2560, 1600), false, 60.0));
122523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  modes.push_back(new DisplayMode(gfx::Size(1024, 768), false, 60.0));
122623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  modes.push_back(new DisplayMode(gfx::Size(1280, 720), false, 60.0));
122723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  modes.push_back(new DisplayMode(gfx::Size(1920, 1080), false, 60.0));
122823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)  modes.push_back(new DisplayMode(gfx::Size(1920, 1080), false, 40.0));
12295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
12305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (unsigned int i = 0; i < arraysize(outputs_); i++) {
123123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    outputs_[i].set_modes(modes.get());
123223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    outputs_[i].set_current_mode(modes[0]);
123323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)    outputs_[i].set_native_mode(modes[0]);
12345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
12355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1236c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // First test simply fails in MULTIPLE_DISPLAY_STATE_SINGLE mode. This is
1237c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // probably unrealistic but we want to make sure any assumptions don't creep
1238c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // in.
12395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  native_display_delegate_->set_max_configurable_pixels(
124023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      modes[2]->size().GetArea());
1241c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  state_controller_.set_state(MULTIPLE_DISPLAY_STATE_SINGLE);
12425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  UpdateOutputs(1, true);
12435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
12445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
12455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      JoinActions(
12465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kGrab,
124723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetFramebufferAction(big_mode_.size(), &outputs_[0], NULL).c_str(),
124823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetCrtcAction(outputs_[0], modes[0], gfx::Point(0, 0)).c_str(),
124923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetCrtcAction(outputs_[0], modes[3], gfx::Point(0, 0)).c_str(),
125023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetCrtcAction(outputs_[0], modes[2], gfx::Point(0, 0)).c_str(),
12515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kUngrab,
12525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          NULL),
12535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      log_->GetActionsAndClear());
12545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
12555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // This test should attempt to configure a mirror mode that will not succeed
12565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // and should end up in extended mode.
12575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  native_display_delegate_->set_max_configurable_pixels(
125823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)      modes[3]->size().GetArea());
1259c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  state_controller_.set_state(MULTIPLE_DISPLAY_STATE_DUAL_MIRROR);
12605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  UpdateOutputs(2, true);
12615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
12625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
12635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      JoinActions(
12645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kGrab,
126523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetFramebufferAction(modes[0]->size(), &outputs_[0], &outputs_[1])
12665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              .c_str(),
126723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetCrtcAction(outputs_[0], modes[0], gfx::Point(0, 0)).c_str(),
12685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          // First mode tried is expected to fail and it will
12695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          // retry wil the 4th mode in the list.
127023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetCrtcAction(outputs_[0], modes[3], gfx::Point(0, 0)).c_str(),
12715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          // Then attempt to configure crtc1 with the first mode.
127223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetCrtcAction(outputs_[1], modes[0], gfx::Point(0, 0)).c_str(),
127323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetCrtcAction(outputs_[1], modes[3], gfx::Point(0, 0)).c_str(),
12745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          // Since it was requested to go into mirror mode
12755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          // and the configured modes were different, it
12765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          // should now try and setup a valid configurable
12775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          // extended mode.
127823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetFramebufferAction(
127923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)              gfx::Size(modes[0]->size().width(),
128023730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                        modes[0]->size().height() + modes[0]->size().height() +
1281c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                            DisplayConfigurator::kVerticalGap),
128223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)              &outputs_[0],
128323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)              &outputs_[1]).c_str(),
128423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetCrtcAction(outputs_[0], modes[0], gfx::Point(0, 0)).c_str(),
128523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetCrtcAction(outputs_[0], modes[3], gfx::Point(0, 0)).c_str(),
128623730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetCrtcAction(outputs_[1],
128723730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                        modes[0],
128823730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                        gfx::Point(0,
128923730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                                   modes[0]->size().height() +
1290c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                       DisplayConfigurator::kVerticalGap))
12915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              .c_str(),
129223730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)          GetCrtcAction(outputs_[1],
129323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                        modes[3],
129423730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                        gfx::Point(0,
129523730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles)                                   modes[0]->size().height() +
1296c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                       DisplayConfigurator::kVerticalGap))
12975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              .c_str(),
12985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          kUngrab,
12995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          NULL),
13005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      log_->GetActionsAndClear());
13015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
13025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
13031320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// Tests that power state requests are saved after failed configuration attempts
13041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// so they can be reused later: http://crosbug.com/p/31571
13051320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciTEST_F(DisplayConfiguratorTest, SaveDisplayPowerStateOnConfigFailure) {
13061320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Start out with two displays in extended mode.
13071320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  state_controller_.set_state(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED);
13081320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  configurator_.Init(false);
13091320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  configurator_.ForceInitialConfigure(0);
13101320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  log_->GetActionsAndClear();
13111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
13121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Turn off the internal display, simulating docked mode.
13131320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  EXPECT_TRUE(configurator_.SetDisplayPower(
13141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON,
13151320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      DisplayConfigurator::kSetDisplayPowerNoFlags));
13161320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  log_->GetActionsAndClear();
13171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
13181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Make all subsequent configuration requests fail and try to turn the
13191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // internal display back on.
13201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  native_display_delegate_->set_max_configurable_pixels(1);
13211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  EXPECT_FALSE(configurator_.SetDisplayPower(
13221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      chromeos::DISPLAY_POWER_ALL_ON,
13231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      DisplayConfigurator::kSetDisplayPowerNoFlags));
13241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  log_->GetActionsAndClear();
13251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
13261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // Simulate the external display getting disconnected and check that the
13271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // internal display is turned on (i.e. DISPLAY_POWER_ALL_ON is used) rather
13281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // than the earlier DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON state.
13291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  native_display_delegate_->set_max_configurable_pixels(0);
13301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  UpdateOutputs(1, true);
13311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  EXPECT_EQ(
13321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      JoinActions(
13331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          kGrab,
13341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          GetFramebufferAction(small_mode_.size(), &outputs_[0], NULL).c_str(),
13351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          GetCrtcAction(outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(),
13361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          kUngrab,
13371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          NULL),
13381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      log_->GetActionsAndClear());
13391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
13401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1341a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)}  // namespace ui
1342