普通文本  |  1790行  |  70 KB

// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/bind.h"
#include "base/prefs/pref_service.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/devtools/devtools_window.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/net/url_request_mock_util.h"
#include "chrome/browser/prefs/browser_prefs.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog.h"
#include "chrome/browser/ui/app_modal_dialogs/native_app_modal_dialog.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_iterator.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/panels/base_panel_browser_test.h"
#include "chrome/browser/ui/panels/docked_panel_collection.h"
#include "chrome/browser/ui/panels/native_panel.h"
#include "chrome/browser/ui/panels/panel.h"
#include "chrome/browser/ui/panels/panel_manager.h"
#include "chrome/browser/ui/panels/test_panel_active_state_observer.h"
#include "chrome/browser/web_applications/web_app.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/base/interactive_test_utils.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/native_web_keyboard_event.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/url_constants.h"
#include "content/public/test/browser_test_utils.h"
#include "content/test/net/url_request_mock_http_job.h"
#include "extensions/common/constants.h"
#include "net/base/net_util.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/event_utils.h"
#include "ui/gfx/screen.h"

using content::WebContents;

class PanelBrowserTest : public BasePanelBrowserTest {
 public:
  PanelBrowserTest() : BasePanelBrowserTest() {
  }

 protected:
  // Helper function for debugging.
  void PrintAllPanelBounds() {
    const std::vector<Panel*>& panels = PanelManager::GetInstance()->panels();
    DLOG(WARNING) << "PanelBounds:";
    for (size_t i = 0; i < panels.size(); ++i) {
      DLOG(WARNING) << "#=" << i
                    << ", ptr=" << panels[i]
                    << ", x=" << panels[i]->GetBounds().x()
                    << ", y=" << panels[i]->GetBounds().y()
                    << ", width=" << panels[i]->GetBounds().width()
                    << ", height" << panels[i]->GetBounds().height();
    }
  }

  std::vector<gfx::Rect> GetAllPanelBounds() {
    std::vector<Panel*> panels = PanelManager::GetInstance()->panels();
    std::vector<gfx::Rect> bounds;
    for (size_t i = 0; i < panels.size(); i++)
      bounds.push_back(panels[i]->GetBounds());
    return bounds;
  }

  std::vector<gfx::Rect> AddXDeltaToBounds(const std::vector<gfx::Rect>& bounds,
                                           const std::vector<int>& delta_x) {
    std::vector<gfx::Rect> new_bounds = bounds;
    for (size_t i = 0; i < bounds.size(); ++i)
      new_bounds[i].Offset(delta_x[i], 0);
    return new_bounds;
  }

  std::vector<Panel::ExpansionState> GetAllPanelExpansionStates() {
    std::vector<Panel*> panels = PanelManager::GetInstance()->panels();
    std::vector<Panel::ExpansionState> expansion_states;
    for (size_t i = 0; i < panels.size(); i++)
      expansion_states.push_back(panels[i]->expansion_state());
    return expansion_states;
  }

  std::vector<bool> GetAllPanelActiveStates() {
    std::vector<Panel*> panels = PanelManager::GetInstance()->panels();
    std::vector<bool> active_states;
    for (size_t i = 0; i < panels.size(); i++)
      active_states.push_back(panels[i]->IsActive());
    return active_states;
  }

  std::vector<bool> ProduceExpectedActiveStates(
      int expected_active_panel_index) {
    std::vector<Panel*> panels = PanelManager::GetInstance()->panels();
    std::vector<bool> active_states;
    for (int i = 0; i < static_cast<int>(panels.size()); i++)
      active_states.push_back(i == expected_active_panel_index);
    return active_states;
  }

  void WaitForPanelActiveStates(const std::vector<bool>& old_states,
                                const std::vector<bool>& new_states) {
    DCHECK(old_states.size() == new_states.size());
    std::vector<Panel*> panels = PanelManager::GetInstance()->panels();
    for (size_t i = 0; i < old_states.size(); i++) {
      if (old_states[i] != new_states[i]){
        WaitForPanelActiveState(
            panels[i], new_states[i] ? SHOW_AS_ACTIVE : SHOW_AS_INACTIVE);
      }
    }
  }

  void TestMinimizeRestore() {
    // This constant is used to generate a point 'sufficiently higher then
    // top edge of the panel'. On some platforms (Mac) we extend hover area
    // a bit above the minimized panel as well, so it takes significant
    // distance to 'move mouse out' of the hover-sensitive area.
    const int kFarEnoughFromHoverArea = 153;

    PanelManager* panel_manager = PanelManager::GetInstance();
    std::vector<Panel*> panels = panel_manager->panels();
    std::vector<gfx::Rect> test_begin_bounds = GetAllPanelBounds();
    std::vector<gfx::Rect> expected_bounds = test_begin_bounds;
    std::vector<Panel::ExpansionState> expected_expansion_states(
        panels.size(), Panel::EXPANDED);
    std::vector<NativePanelTesting*> native_panels_testing(panels.size());
    for (size_t i = 0; i < panels.size(); ++i) {
      native_panels_testing[i] = CreateNativePanelTesting(panels[i]);
    }

    // Verify titlebar click does not minimize.
    for (size_t index = 0; index < panels.size(); ++index) {
      // Press left mouse button.  Verify nothing changed.
      native_panels_testing[index]->PressLeftMouseButtonTitlebar(
          panels[index]->GetBounds().origin());
      EXPECT_EQ(expected_bounds, GetAllPanelBounds());
      EXPECT_EQ(expected_expansion_states, GetAllPanelExpansionStates());

      // Release mouse button.  Verify nothing changed.
      native_panels_testing[index]->ReleaseMouseButtonTitlebar();
      EXPECT_EQ(expected_bounds, GetAllPanelBounds());
      EXPECT_EQ(expected_expansion_states, GetAllPanelExpansionStates());
    }

    // Minimize all panels for next stage in test.
    for (size_t index = 0; index < panels.size(); ++index) {
      panels[index]->Minimize();
      expected_bounds[index].set_height(panel::kMinimizedPanelHeight);
      expected_bounds[index].set_y(
          test_begin_bounds[index].y() +
          test_begin_bounds[index].height() - panel::kMinimizedPanelHeight);
      expected_expansion_states[index] = Panel::MINIMIZED;
      EXPECT_EQ(expected_bounds, GetAllPanelBounds());
      EXPECT_EQ(expected_expansion_states, GetAllPanelExpansionStates());
    }

    // Setup bounds and expansion states for minimized and titlebar-only
    // states.
    std::vector<Panel::ExpansionState> titlebar_exposed_states(
        panels.size(), Panel::TITLE_ONLY);
    std::vector<gfx::Rect> minimized_bounds = expected_bounds;
    std::vector<Panel::ExpansionState> minimized_states(
        panels.size(), Panel::MINIMIZED);
    std::vector<gfx::Rect> titlebar_exposed_bounds = test_begin_bounds;
    for (size_t index = 0; index < panels.size(); ++index) {
      titlebar_exposed_bounds[index].set_height(
          panels[index]->native_panel()->TitleOnlyHeight());
      titlebar_exposed_bounds[index].set_y(
          test_begin_bounds[index].y() +
          test_begin_bounds[index].height() -
          panels[index]->native_panel()->TitleOnlyHeight());
    }

    // Test hover.  All panels are currently in minimized state.
    EXPECT_EQ(minimized_states, GetAllPanelExpansionStates());
    for (size_t index = 0; index < panels.size(); ++index) {
      // Hover mouse on minimized panel.
      // Verify titlebar is exposed on all panels.
      gfx::Point hover_point(panels[index]->GetBounds().origin());
      MoveMouseAndWaitForExpansionStateChange(panels[index], hover_point);
      EXPECT_EQ(titlebar_exposed_bounds, GetAllPanelBounds());
      EXPECT_EQ(titlebar_exposed_states, GetAllPanelExpansionStates());

      // Hover mouse above the panel. Verify all panels are minimized.
      hover_point.set_y(
          panels[index]->GetBounds().y() - kFarEnoughFromHoverArea);
      MoveMouseAndWaitForExpansionStateChange(panels[index], hover_point);
      EXPECT_EQ(minimized_bounds, GetAllPanelBounds());
      EXPECT_EQ(minimized_states, GetAllPanelExpansionStates());

      // Hover mouse below minimized panel.
      // Verify titlebar is exposed on all panels.
      hover_point.set_y(panels[index]->GetBounds().y() +
                        panels[index]->GetBounds().height() + 5);
      MoveMouseAndWaitForExpansionStateChange(panels[index], hover_point);
      EXPECT_EQ(titlebar_exposed_bounds, GetAllPanelBounds());
      EXPECT_EQ(titlebar_exposed_states, GetAllPanelExpansionStates());

      // Hover below titlebar exposed panel.  Verify nothing changed.
      hover_point.set_y(panels[index]->GetBounds().y() +
                        panels[index]->GetBounds().height() + 6);
      MoveMouse(hover_point);
      EXPECT_EQ(titlebar_exposed_bounds, GetAllPanelBounds());
      EXPECT_EQ(titlebar_exposed_states, GetAllPanelExpansionStates());

      // Hover mouse above panel.  Verify all panels are minimized.
      hover_point.set_y(
          panels[index]->GetBounds().y() - kFarEnoughFromHoverArea);
      MoveMouseAndWaitForExpansionStateChange(panels[index], hover_point);
      EXPECT_EQ(minimized_bounds, GetAllPanelBounds());
      EXPECT_EQ(minimized_states, GetAllPanelExpansionStates());
    }

    // Test restore.  All panels are currently in minimized state.
    for (size_t index = 0; index < panels.size(); ++index) {
      // Hover on the last panel.  This is to test the case of clicking on the
      // panel when it's in titlebar exposed state.
      if (index == panels.size() - 1)
        MoveMouse(minimized_bounds[index].origin());

      // Click minimized or title bar exposed panel as the case may be.
      // Verify panel is restored to its original size.
      native_panels_testing[index]->PressLeftMouseButtonTitlebar(
          panels[index]->GetBounds().origin());
      native_panels_testing[index]->ReleaseMouseButtonTitlebar();
      expected_bounds[index].set_height(
          test_begin_bounds[index].height());
      expected_bounds[index].set_y(test_begin_bounds[index].y());
      expected_expansion_states[index] = Panel::EXPANDED;
      EXPECT_EQ(expected_bounds, GetAllPanelBounds());
      EXPECT_EQ(expected_expansion_states, GetAllPanelExpansionStates());

      // Hover again on the last panel which is now restored, to reset the
      // titlebar exposed state.
      if (index == panels.size() - 1)
        MoveMouse(minimized_bounds[index].origin());
    }

    // The below could be separate tests, just adding a TODO here for tracking.
    // TODO(prasadt): Add test for dragging when in titlebar exposed state.
    // TODO(prasadt): Add test in presence of auto hiding task bar.

    for (size_t i = 0; i < panels.size(); ++i)
      delete native_panels_testing[i];
  }
};

IN_PROC_BROWSER_TEST_F(PanelBrowserTest, CheckDockedPanelProperties) {
  PanelManager* panel_manager = PanelManager::GetInstance();
  DockedPanelCollection* docked_collection = panel_manager->docked_collection();

  // Create 3 docked panels that are in expanded, title-only or minimized states
  // respectively.
  Panel* panel1 = CreatePanelWithBounds("1", gfx::Rect(0, 0, 100, 100));
  Panel* panel2 = CreatePanelWithBounds("2", gfx::Rect(0, 0, 100, 100));
  Panel* panel3 = CreatePanelWithBounds("3", gfx::Rect(0, 0, 100, 100));
  panel2->SetExpansionState(Panel::TITLE_ONLY);
  EXPECT_EQ(Panel::TITLE_ONLY, panel2->expansion_state());
  panel3->SetExpansionState(Panel::MINIMIZED);
  EXPECT_EQ(Panel::MINIMIZED, panel3->expansion_state());
  scoped_ptr<NativePanelTesting> panel1_testing(
      CreateNativePanelTesting(panel1));
  scoped_ptr<NativePanelTesting> panel2_testing(
      CreateNativePanelTesting(panel2));
  scoped_ptr<NativePanelTesting> panel3_testing(
      CreateNativePanelTesting(panel3));

  // Ensure that the layout message can get a chance to be processed so that
  // the button visibility can be updated.
  base::MessageLoop::current()->RunUntilIdle();

  EXPECT_EQ(3, panel_manager->num_panels());
  EXPECT_TRUE(docked_collection->HasPanel(panel1));
  EXPECT_TRUE(docked_collection->HasPanel(panel2));
  EXPECT_TRUE(docked_collection->HasPanel(panel3));

  EXPECT_EQ(Panel::EXPANDED, panel1->expansion_state());
  EXPECT_EQ(Panel::TITLE_ONLY, panel2->expansion_state());
  EXPECT_EQ(Panel::MINIMIZED, panel3->expansion_state());

  EXPECT_TRUE(panel1->IsAlwaysOnTop());
  EXPECT_TRUE(panel2->IsAlwaysOnTop());
  EXPECT_TRUE(panel3->IsAlwaysOnTop());

  EXPECT_TRUE(panel1_testing->IsButtonVisible(panel::CLOSE_BUTTON));
  EXPECT_TRUE(panel2_testing->IsButtonVisible(panel::CLOSE_BUTTON));
  EXPECT_TRUE(panel3_testing->IsButtonVisible(panel::CLOSE_BUTTON));

  EXPECT_TRUE(panel1_testing->IsButtonVisible(panel::MINIMIZE_BUTTON));
  EXPECT_FALSE(panel2_testing->IsButtonVisible(panel::MINIMIZE_BUTTON));
  EXPECT_FALSE(panel3_testing->IsButtonVisible(panel::MINIMIZE_BUTTON));

  EXPECT_FALSE(panel1_testing->IsButtonVisible(panel::RESTORE_BUTTON));
  EXPECT_TRUE(panel2_testing->IsButtonVisible(panel::RESTORE_BUTTON));
  EXPECT_TRUE(panel3_testing->IsButtonVisible(panel::RESTORE_BUTTON));

  // Expanded panel cannot be resized at the bottom.
  EXPECT_EQ(panel::RESIZABLE_EXCEPT_BOTTOM, panel1->CanResizeByMouse());
  EXPECT_EQ(panel::NOT_RESIZABLE, panel2->CanResizeByMouse());
  EXPECT_EQ(panel::NOT_RESIZABLE, panel3->CanResizeByMouse());

  EXPECT_EQ(panel::TOP_ROUNDED, panel1_testing->GetWindowCornerStyle());
  EXPECT_EQ(panel::TOP_ROUNDED, panel1_testing->GetWindowCornerStyle());
  EXPECT_EQ(panel::TOP_ROUNDED, panel3_testing->GetWindowCornerStyle());

  EXPECT_EQ(Panel::USE_PANEL_ATTENTION, panel1->attention_mode());
  EXPECT_EQ(Panel::USE_PANEL_ATTENTION, panel2->attention_mode());
  EXPECT_EQ(Panel::USE_PANEL_ATTENTION, panel3->attention_mode());

  panel_manager->CloseAll();
}

IN_PROC_BROWSER_TEST_F(PanelBrowserTest, CreatePanel) {
  PanelManager* panel_manager = PanelManager::GetInstance();
  EXPECT_EQ(0, panel_manager->num_panels()); // No panels initially.

  Panel* panel = CreatePanel("PanelTest");
  EXPECT_EQ(1, panel_manager->num_panels());

  gfx::Rect bounds = panel->GetBounds();
  EXPECT_GT(bounds.x(), 0);
  EXPECT_GT(bounds.y(), 0);
  EXPECT_GT(bounds.width(), 0);
  EXPECT_GT(bounds.height(), 0);

  EXPECT_EQ(bounds.right(),
            panel_manager->docked_collection()->StartingRightPosition());

  CloseWindowAndWait(panel);

  EXPECT_EQ(0, panel_manager->num_panels());
}

IN_PROC_BROWSER_TEST_F(PanelBrowserTest, CreateBigPanel) {
  gfx::Rect work_area = PanelManager::GetInstance()->
      display_settings_provider()->GetPrimaryWorkArea();
  Panel* panel = CreatePanelWithBounds("BigPanel", work_area);
  gfx::Rect bounds = panel->GetBounds();
  EXPECT_EQ(panel->max_size().width(), bounds.width());
  EXPECT_LT(bounds.width(), work_area.width());
  EXPECT_EQ(panel->max_size().height(), bounds.height());
  EXPECT_LT(bounds.height(), work_area.height());
  panel->Close();
}

class WaitForStableInitialSize : public TestPanelNotificationObserver {
 public:
  explicit WaitForStableInitialSize(Panel* panel)
      : TestPanelNotificationObserver(
          chrome::NOTIFICATION_PANEL_COLLECTION_UPDATED,
          content::NotificationService::AllSources()),
        panel_(panel) {}
  virtual ~WaitForStableInitialSize() {}

 protected:
  virtual bool AtExpectedState() OVERRIDE {
    return panel_->GetBounds().height() > panel_->TitleOnlyHeight();
  }
  Panel* panel_;
};

class WaitForAutoResizeWider : public TestPanelNotificationObserver {
 public:
  explicit WaitForAutoResizeWider(Panel* panel)
      : TestPanelNotificationObserver(
          chrome::NOTIFICATION_PANEL_COLLECTION_UPDATED,
          content::NotificationService::AllSources()),
        panel_(panel),
        initial_size_(panel->GetBounds().size()) {}
  virtual ~WaitForAutoResizeWider() {}

 protected:
  virtual bool AtExpectedState() OVERRIDE {
    return panel_->GetBounds().width() > initial_size_.width();
  }
  Panel* panel_;
  gfx::Size initial_size_;
};

class WaitForAutoResizeNarrower : public TestPanelNotificationObserver {
 public:
  explicit WaitForAutoResizeNarrower(Panel* panel)
      : TestPanelNotificationObserver(
          chrome::NOTIFICATION_PANEL_COLLECTION_UPDATED,
          content::NotificationService::AllSources()),
        panel_(panel),
        initial_size_(panel->GetBounds().size()) {}
  virtual ~WaitForAutoResizeNarrower() {}

 protected:
  virtual bool AtExpectedState() OVERRIDE {
    return panel_->GetBounds().width() < initial_size_.width();
  }
  Panel* panel_;
  gfx::Size initial_size_;
};

// crbug.com/160504
IN_PROC_BROWSER_TEST_F(PanelBrowserTest, DISABLED_AutoResize) {
  PanelManager* panel_manager = PanelManager::GetInstance();
  panel_manager->enable_auto_sizing(true);
  // Bigger space is needed by this test.
  mock_display_settings_provider()->SetPrimaryDisplay(
      gfx::Rect(0, 0, 1200, 900), gfx::Rect(0, 0, 1200, 900));

  // Create a test panel with web contents loaded.
  CreatePanelParams params("PanelTest1", gfx::Rect(), SHOW_AS_ACTIVE);
  GURL url(ui_test_utils::GetTestUrl(
      base::FilePath(kTestDir),
      base::FilePath(FILE_PATH_LITERAL("update-preferred-size.html"))));
  params.url = url;
  Panel* panel = CreatePanelWithParams(params);

  // Ensure panel has auto resized to original web content size.
  // The resize will update the docked panel collection.
  WaitForStableInitialSize initial_resize(panel);
  initial_resize.Wait();
  gfx::Rect initial_bounds = panel->GetBounds();

  // Expand the test page. The resize will update the docked panel collection.
  WaitForAutoResizeWider enlarge(panel);
  EXPECT_TRUE(content::ExecuteScript(
      panel->GetWebContents(), "changeSize(50);"));
  enlarge.Wait();
  gfx::Rect bounds_on_grow = panel->GetBounds();
  EXPECT_GT(bounds_on_grow.width(), initial_bounds.width());
  EXPECT_EQ(bounds_on_grow.height(), initial_bounds.height());

  // Shrink the test page. The resize will update the docked panel collection.
  WaitForAutoResizeNarrower shrink(panel);
  EXPECT_TRUE(content::ExecuteScript(
      panel->GetWebContents(), "changeSize(-30);"));
  shrink.Wait();
  gfx::Rect bounds_on_shrink = panel->GetBounds();
  EXPECT_LT(bounds_on_shrink.width(), bounds_on_grow.width());
  EXPECT_GT(bounds_on_shrink.width(), initial_bounds.width());
  EXPECT_EQ(bounds_on_shrink.height(), initial_bounds.height());

  // Verify resizing turns off auto-resizing and panel no longer auto-resizes.
  gfx::Rect previous_bounds = panel->GetBounds();
  // These should be identical because the panel is expanded.
  EXPECT_EQ(previous_bounds.size(), panel->GetRestoredBounds().size());
  gfx::Size new_size(previous_bounds.size());
  new_size.Enlarge(5, 5);
  gfx::Rect new_bounds(previous_bounds.origin(), new_size);
  panel->SetBounds(new_bounds);
  EXPECT_FALSE(panel->auto_resizable());
  EXPECT_EQ(new_bounds.size(), panel->GetBounds().size());
  EXPECT_EQ(new_bounds.size(), panel->GetRestoredBounds().size());

  // Turn back on auto-resize and verify that panel auto resizes.
  content::WindowedNotificationObserver auto_resize_enabled(
      chrome::NOTIFICATION_PANEL_COLLECTION_UPDATED,
      content::NotificationService::AllSources());
  panel->SetAutoResizable(true);
  auto_resize_enabled.Wait();
  gfx::Rect bounds_auto_resize_enabled = panel->GetBounds();
  EXPECT_EQ(bounds_on_shrink.width(), bounds_auto_resize_enabled.width());
  EXPECT_EQ(bounds_on_shrink.height(), bounds_auto_resize_enabled.height());

  panel->Close();
}

IN_PROC_BROWSER_TEST_F(PanelBrowserTest, ResizePanel) {
  PanelManager* panel_manager = PanelManager::GetInstance();
  panel_manager->enable_auto_sizing(true);

  Panel* panel = CreatePanel("TestPanel");
  EXPECT_TRUE(panel->auto_resizable());
  EXPECT_EQ(Panel::EXPANDED, panel->expansion_state());

  // Verify resizing turns off auto-resizing and that it works.
  gfx::Rect original_bounds = panel->GetBounds();
  // These should be identical because the panel is expanded.
  EXPECT_EQ(original_bounds.size(), panel->GetRestoredBounds().size());
  gfx::Size new_size(original_bounds.size());
  new_size.Enlarge(5, 5);
  gfx::Rect new_bounds(original_bounds.origin(), new_size);
  panel->SetBounds(new_bounds);
  EXPECT_FALSE(panel->auto_resizable());
  EXPECT_EQ(new_bounds.size(), panel->GetBounds().size());
  EXPECT_EQ(new_bounds.size(), panel->GetRestoredBounds().size());

  // Verify current height unaffected when panel is not expanded.
  panel->SetExpansionState(Panel::MINIMIZED);
  int original_height = panel->GetBounds().height();
  new_size.Enlarge(5, 5);
  new_bounds.set_size(new_size);
  panel->SetBounds(new_bounds);
  EXPECT_EQ(new_bounds.size().width(), panel->GetBounds().width());
  EXPECT_EQ(original_height, panel->GetBounds().height());
  EXPECT_EQ(new_bounds.size(), panel->GetRestoredBounds().size());

  panel->Close();
}

IN_PROC_BROWSER_TEST_F(PanelBrowserTest, AnimateBounds) {
  // Create a detached panel, instead of docked panel because it cannot be
  // moved to any location.
  Panel* panel = CreateDetachedPanel("1", gfx::Rect(200, 100, 100, 100));
  scoped_ptr<NativePanelTesting> panel_testing(
      CreateNativePanelTesting(panel));

  // Validates that no animation should be triggered when the panel is being
  // dragged.
  gfx::Point mouse_location(panel->GetBounds().origin());
  panel_testing->PressLeftMouseButtonTitlebar(mouse_location);
  panel_testing->DragTitlebar(mouse_location + gfx::Vector2d(-100, 5));
  EXPECT_FALSE(panel_testing->IsAnimatingBounds());
  panel_testing->FinishDragTitlebar();

  // Set bounds with animation.
  gfx::Rect bounds = gfx::Rect(10, 20, 150, 160);
  panel->SetPanelBounds(bounds);
  // There is no animation on Linux, by design.
#if !defined(OS_LINUX)
  EXPECT_TRUE(panel_testing->IsAnimatingBounds());
  WaitForBoundsAnimationFinished(panel);
#endif
  EXPECT_FALSE(panel_testing->IsAnimatingBounds());
  EXPECT_EQ(bounds, panel->GetBounds());

  // Set bounds without animation.
  bounds = gfx::Rect(30, 40, 200, 220);
  panel->SetPanelBoundsInstantly(bounds);
  EXPECT_FALSE(panel_testing->IsAnimatingBounds());
  EXPECT_EQ(bounds, panel->GetBounds());

  panel->Close();
}

IN_PROC_BROWSER_TEST_F(PanelBrowserTest, RestoredBounds) {
  Panel* panel = CreatePanelWithBounds("PanelTest", gfx::Rect(0, 0, 100, 100));
  EXPECT_EQ(Panel::EXPANDED, panel->expansion_state());
  EXPECT_EQ(panel->GetBounds(), panel->GetRestoredBounds());

  panel->SetExpansionState(Panel::MINIMIZED);
  EXPECT_EQ(Panel::MINIMIZED, panel->expansion_state());
  gfx::Rect bounds = panel->GetBounds();
  gfx::Rect restored = panel->GetRestoredBounds();
  EXPECT_EQ(bounds.x(), restored.x());
  EXPECT_GT(bounds.y(), restored.y());
  EXPECT_EQ(bounds.width(), restored.width());
  EXPECT_LT(bounds.height(), restored.height());

  panel->SetExpansionState(Panel::TITLE_ONLY);
  EXPECT_EQ(Panel::TITLE_ONLY, panel->expansion_state());
  bounds = panel->GetBounds();
  restored = panel->GetRestoredBounds();
  EXPECT_EQ(bounds.x(), restored.x());
  EXPECT_GT(bounds.y(), restored.y());
  EXPECT_EQ(bounds.width(), restored.width());
  EXPECT_LT(bounds.height(), restored.height());

  panel->SetExpansionState(Panel::MINIMIZED);
  EXPECT_EQ(Panel::MINIMIZED, panel->expansion_state());
  bounds = panel->GetBounds();
  restored = panel->GetRestoredBounds();
  EXPECT_EQ(bounds.x(), restored.x());
  EXPECT_GT(bounds.y(), restored.y());
  EXPECT_EQ(bounds.width(), restored.width());
  EXPECT_LT(bounds.height(), restored.height());

  panel->SetExpansionState(Panel::EXPANDED);
  EXPECT_EQ(panel->GetBounds(), panel->GetRestoredBounds());

  // Verify that changing the panel bounds does not affect the restored height.
  int saved_restored_height = restored.height();
  panel->SetExpansionState(Panel::MINIMIZED);
  bounds = gfx::Rect(10, 20, 300, 400);
  panel->SetPanelBounds(bounds);
  EXPECT_EQ(saved_restored_height, panel->GetRestoredBounds().height());

  panel->SetExpansionState(Panel::TITLE_ONLY);
  bounds = gfx::Rect(20, 30, 100, 200);
  panel->SetPanelBounds(bounds);
  EXPECT_EQ(saved_restored_height, panel->GetRestoredBounds().height());

  panel->SetExpansionState(Panel::EXPANDED);
  bounds = gfx::Rect(40, 60, 300, 400);
  panel->SetPanelBounds(bounds);
  EXPECT_EQ(saved_restored_height, panel->GetRestoredBounds().height());
  panel->set_full_size(bounds.size());
  EXPECT_NE(saved_restored_height, panel->GetRestoredBounds().height());

  panel->Close();
}

IN_PROC_BROWSER_TEST_F(PanelBrowserTest, MinimizeRestore) {
  // Test with one panel.
  CreatePanelWithBounds("PanelTest1", gfx::Rect(0, 0, 100, 100));
  TestMinimizeRestore();

  PanelManager::GetInstance()->CloseAll();
}

IN_PROC_BROWSER_TEST_F(PanelBrowserTest, MinimizeRestoreTwoPanels) {
  // Test with two panels.
  CreatePanelWithBounds("PanelTest1", gfx::Rect(0, 0, 100, 100));
  CreatePanelWithBounds("PanelTest2", gfx::Rect(0, 0, 110, 110));
  TestMinimizeRestore();

  PanelManager::GetInstance()->CloseAll();
}

IN_PROC_BROWSER_TEST_F(PanelBrowserTest, MinimizeRestoreThreePanels) {
  // Test with three panels.
  CreatePanelWithBounds("PanelTest1", gfx::Rect(0, 0, 100, 100));
  CreatePanelWithBounds("PanelTest2", gfx::Rect(0, 0, 110, 110));
  CreatePanelWithBounds("PanelTest3", gfx::Rect(0, 0, 120, 120));
  TestMinimizeRestore();

  PanelManager::GetInstance()->CloseAll();
}

IN_PROC_BROWSER_TEST_F(PanelBrowserTest, MinimizeRestoreButtonClick) {
  // Test with three panels.
  Panel* panel1 = CreatePanel("PanelTest1");
  Panel* panel2 = CreatePanel("PanelTest2");
  Panel* panel3 = CreatePanel("PanelTest3");
  EXPECT_FALSE(panel1->IsMinimized());
  EXPECT_FALSE(panel2->IsMinimized());
  EXPECT_FALSE(panel3->IsMinimized());

  // Click restore button on an expanded panel. Expect no change.
  panel1->OnRestoreButtonClicked(panel::NO_MODIFIER);
  EXPECT_FALSE(panel1->IsMinimized());
  EXPECT_FALSE(panel2->IsMinimized());
  EXPECT_FALSE(panel3->IsMinimized());

  // Click minimize button on an expanded panel. Only that panel will minimize.
  panel1->OnMinimizeButtonClicked(panel::NO_MODIFIER);
  EXPECT_TRUE(panel1->IsMinimized());
  EXPECT_FALSE(panel2->IsMinimized());
  EXPECT_FALSE(panel3->IsMinimized());

  // Click minimize button on a minimized panel. Expect no change.
  panel1->OnMinimizeButtonClicked(panel::NO_MODIFIER);
  EXPECT_TRUE(panel1->IsMinimized());
  EXPECT_FALSE(panel2->IsMinimized());
  EXPECT_FALSE(panel3->IsMinimized());

  // Minimize all panels by clicking minimize button on an expanded panel
  // with the apply-all modifier.
  panel2->OnMinimizeButtonClicked(panel::APPLY_TO_ALL);
  EXPECT_TRUE(panel1->IsMinimized());
  EXPECT_TRUE(panel2->IsMinimized());
  EXPECT_TRUE(panel3->IsMinimized());

  // Click restore button on a minimized panel. Only that panel will restore.
  panel2->OnRestoreButtonClicked(panel::NO_MODIFIER);
  EXPECT_TRUE(panel1->IsMinimized());
  EXPECT_FALSE(panel2->IsMinimized());
  EXPECT_TRUE(panel3->IsMinimized());

  // Restore all panels by clicking restore button on a minimized panel.
  panel3->OnRestoreButtonClicked(panel::APPLY_TO_ALL);
  EXPECT_FALSE(panel1->IsMinimized());
  EXPECT_FALSE(panel2->IsMinimized());
  EXPECT_FALSE(panel3->IsMinimized());
}

// http://crbug.com/243891 flaky on Linux
#if defined(OS_LINUX)
#define MAYBE_RestoreAllWithTitlebarClick DISABLED_RestoreAllWithTitlebarClick
#else
#define MAYBE_RestoreAllWithTitlebarClick RestoreAllWithTitlebarClick
#endif
IN_PROC_BROWSER_TEST_F(PanelBrowserTest, MAYBE_RestoreAllWithTitlebarClick) {
  // Test with three panels.
  Panel* panel1 = CreatePanel("PanelTest1");
  Panel* panel2 = CreatePanel("PanelTest2");
  Panel* panel3 = CreatePanel("PanelTest3");
  EXPECT_FALSE(panel1->IsMinimized());
  EXPECT_FALSE(panel2->IsMinimized());
  EXPECT_FALSE(panel3->IsMinimized());

  scoped_ptr<NativePanelTesting> test_panel1(
      CreateNativePanelTesting(panel1));
  scoped_ptr<NativePanelTesting> test_panel2(
      CreateNativePanelTesting(panel2));
  scoped_ptr<NativePanelTesting> test_panel3(
      CreateNativePanelTesting(panel3));

  // Click on an expanded panel's titlebar using the apply-all modifier.
  // Verify expansion state is unchanged.
  test_panel2->PressLeftMouseButtonTitlebar(panel2->GetBounds().origin(),
                                            panel::APPLY_TO_ALL);
  test_panel2->ReleaseMouseButtonTitlebar(panel::APPLY_TO_ALL);
  EXPECT_FALSE(panel1->IsMinimized());
  EXPECT_FALSE(panel2->IsMinimized());
  EXPECT_FALSE(panel3->IsMinimized());

  // Click on a minimized panel's titlebar using the apply-all modifier.
  panel1->Minimize();
  panel2->Minimize();
  panel3->Minimize();
  EXPECT_TRUE(panel1->IsMinimized());
  EXPECT_TRUE(panel2->IsMinimized());
  EXPECT_TRUE(panel3->IsMinimized());

  // Nothing changes until mouse is released.
  test_panel1->PressLeftMouseButtonTitlebar(panel1->GetBounds().origin(),
                                            panel::APPLY_TO_ALL);
  EXPECT_TRUE(panel1->IsMinimized());
  EXPECT_TRUE(panel2->IsMinimized());
  EXPECT_TRUE(panel3->IsMinimized());
  // Verify all panels restored when mouse is released.
  test_panel1->ReleaseMouseButtonTitlebar(panel::APPLY_TO_ALL);
  EXPECT_FALSE(panel1->IsMinimized());
  EXPECT_FALSE(panel2->IsMinimized());
  EXPECT_FALSE(panel3->IsMinimized());

  // Minimize a single panel. Then click on expanded panel with apply-all
  // modifier. Verify nothing changes.
  panel1->Minimize();
  EXPECT_TRUE(panel1->IsMinimized());
  EXPECT_FALSE(panel2->IsMinimized());
  EXPECT_FALSE(panel3->IsMinimized());

  test_panel2->PressLeftMouseButtonTitlebar(panel2->GetBounds().origin(),
                                            panel::APPLY_TO_ALL);
  test_panel2->ReleaseMouseButtonTitlebar(panel::APPLY_TO_ALL);
  EXPECT_TRUE(panel1->IsMinimized());
  EXPECT_FALSE(panel2->IsMinimized());
  EXPECT_FALSE(panel3->IsMinimized());

  // Minimize another panel. Then click on a minimized panel with apply-all
  // modifier to restore all panels.
  panel2->Minimize();
  EXPECT_TRUE(panel1->IsMinimized());
  EXPECT_TRUE(panel2->IsMinimized());
  EXPECT_FALSE(panel3->IsMinimized());

  test_panel2->PressLeftMouseButtonTitlebar(panel2->GetBounds().origin(),
                                            panel::APPLY_TO_ALL);
  test_panel2->ReleaseMouseButtonTitlebar(panel::APPLY_TO_ALL);
  EXPECT_FALSE(panel1->IsMinimized());
  EXPECT_FALSE(panel2->IsMinimized());
  EXPECT_FALSE(panel3->IsMinimized());

  // Click on the single minimized panel. Verify all are restored.
  panel1->Minimize();
  EXPECT_TRUE(panel1->IsMinimized());
  EXPECT_FALSE(panel2->IsMinimized());
  EXPECT_FALSE(panel3->IsMinimized());

  test_panel1->PressLeftMouseButtonTitlebar(panel1->GetBounds().origin(),
                                            panel::APPLY_TO_ALL);
  test_panel1->ReleaseMouseButtonTitlebar(panel::APPLY_TO_ALL);
  EXPECT_FALSE(panel1->IsMinimized());
  EXPECT_FALSE(panel2->IsMinimized());
  EXPECT_FALSE(panel3->IsMinimized());

  // Click on the single expanded panel. Verify nothing changes.
  panel1->Minimize();
  panel3->Minimize();
  EXPECT_TRUE(panel1->IsMinimized());
  EXPECT_FALSE(panel2->IsMinimized());
  EXPECT_TRUE(panel3->IsMinimized());

  test_panel2->PressLeftMouseButtonTitlebar(panel2->GetBounds().origin(),
                                            panel::APPLY_TO_ALL);
  test_panel2->ReleaseMouseButtonTitlebar(panel::APPLY_TO_ALL);
  EXPECT_TRUE(panel1->IsMinimized());
  EXPECT_FALSE(panel2->IsMinimized());
  EXPECT_TRUE(panel3->IsMinimized());

  // Hover over a minimized panel and click on the titlebar while it is in
  // title-only mode. Should restore all panels.
  panel2->Minimize();
  EXPECT_TRUE(panel1->IsMinimized());
  EXPECT_TRUE(panel2->IsMinimized());
  EXPECT_TRUE(panel3->IsMinimized());

  MoveMouseAndWaitForExpansionStateChange(panel2, panel2->GetBounds().origin());
  EXPECT_EQ(Panel::TITLE_ONLY, panel1->expansion_state());
  EXPECT_EQ(Panel::TITLE_ONLY, panel2->expansion_state());
  EXPECT_EQ(Panel::TITLE_ONLY, panel3->expansion_state());

  test_panel3->PressLeftMouseButtonTitlebar(panel3->GetBounds().origin(),
                                            panel::APPLY_TO_ALL);
  test_panel3->ReleaseMouseButtonTitlebar(panel::APPLY_TO_ALL);
  EXPECT_FALSE(panel1->IsMinimized());
  EXPECT_FALSE(panel2->IsMinimized());
  EXPECT_FALSE(panel3->IsMinimized());

  // Draw attention to a minimized panel. Click on a minimized panel that is
  // not drawing attention. Verify restore all applies without affecting
  // draw attention.
  panel1->Minimize();
  panel2->Minimize();
  panel3->Minimize();
  EXPECT_TRUE(panel1->IsMinimized());
  EXPECT_TRUE(panel2->IsMinimized());
  EXPECT_TRUE(panel3->IsMinimized());

  panel1->FlashFrame(true);
  EXPECT_TRUE(panel1->IsDrawingAttention());

  test_panel2->PressLeftMouseButtonTitlebar(panel2->GetBounds().origin(),
                                            panel::APPLY_TO_ALL);
  test_panel2->ReleaseMouseButtonTitlebar(panel::APPLY_TO_ALL);
  EXPECT_FALSE(panel1->IsMinimized());
  EXPECT_FALSE(panel2->IsMinimized());
  EXPECT_FALSE(panel3->IsMinimized());
  EXPECT_TRUE(panel1->IsDrawingAttention());

  // Restore all panels by clicking on the minimized panel that is drawing
  // attention. Verify restore all applies and clears draw attention.
  panel1->Minimize();
  panel2->Minimize();
  panel3->Minimize();
  EXPECT_TRUE(panel1->IsMinimized());
  EXPECT_TRUE(panel2->IsMinimized());
  EXPECT_TRUE(panel3->IsMinimized());

  test_panel1->PressLeftMouseButtonTitlebar(panel1->GetBounds().origin(),
                                            panel::APPLY_TO_ALL);
  test_panel1->ReleaseMouseButtonTitlebar(panel::APPLY_TO_ALL);
  EXPECT_FALSE(panel1->IsMinimized());
  EXPECT_FALSE(panel2->IsMinimized());
  EXPECT_FALSE(panel3->IsMinimized());
  EXPECT_FALSE(panel1->IsDrawingAttention());

  PanelManager::GetInstance()->CloseAll();
}

IN_PROC_BROWSER_TEST_F(PanelBrowserTest,
                       MinimizeRestoreOnAutoHidingDesktopBar) {
  PanelManager* panel_manager = PanelManager::GetInstance();
  DockedPanelCollection* docked_collection = panel_manager->docked_collection();
  int expected_bottom_on_expanded = docked_collection->work_area().bottom();
  int expected_bottom_on_title_only = expected_bottom_on_expanded;
  int expected_bottom_on_minimized = expected_bottom_on_expanded;

  // Turn on auto-hiding.
  static const int bottom_bar_thickness = 40;
  mock_display_settings_provider()->EnableAutoHidingDesktopBar(
      DisplaySettingsProvider::DESKTOP_BAR_ALIGNED_BOTTOM,
      true,
      bottom_bar_thickness);
  expected_bottom_on_title_only -= bottom_bar_thickness;

  Panel* panel = CreatePanel("1");
  int initial_height = panel->GetBounds().height();

  EXPECT_EQ(Panel::EXPANDED, panel->expansion_state());
  EXPECT_EQ(expected_bottom_on_expanded, panel->GetBounds().bottom());

  panel->Minimize();
  WaitForBoundsAnimationFinished(panel);
  EXPECT_EQ(Panel::MINIMIZED, panel->expansion_state());
  EXPECT_EQ(panel::kMinimizedPanelHeight, panel->GetBounds().height());
  EXPECT_EQ(expected_bottom_on_minimized, panel->GetBounds().bottom());

  panel->SetExpansionState(Panel::TITLE_ONLY);
  WaitForBoundsAnimationFinished(panel);
  EXPECT_EQ(Panel::TITLE_ONLY, panel->expansion_state());
  EXPECT_EQ(panel::kTitlebarHeight, panel->GetBounds().height());
  EXPECT_EQ(expected_bottom_on_title_only, panel->GetBounds().bottom());

  panel->Restore();
  WaitForBoundsAnimationFinished(panel);
  EXPECT_EQ(Panel::EXPANDED, panel->expansion_state());
  EXPECT_EQ(initial_height, panel->GetBounds().height());
  EXPECT_EQ(expected_bottom_on_expanded, panel->GetBounds().bottom());

  panel->Close();
}

IN_PROC_BROWSER_TEST_F(PanelBrowserTest, ChangeAutoHideTaskBarThickness) {
  PanelManager* manager = PanelManager::GetInstance();
  DockedPanelCollection* docked_collection = manager->docked_collection();
  int initial_starting_right_position =
      docked_collection->StartingRightPosition();

  int bottom_bar_thickness = 20;
  int right_bar_thickness = 30;
  mock_display_settings_provider()->EnableAutoHidingDesktopBar(
      DisplaySettingsProvider::DESKTOP_BAR_ALIGNED_BOTTOM,
      true,
      bottom_bar_thickness);
  mock_display_settings_provider()->EnableAutoHidingDesktopBar(
      DisplaySettingsProvider::DESKTOP_BAR_ALIGNED_RIGHT,
      true,
      right_bar_thickness);
  EXPECT_EQ(initial_starting_right_position,
            docked_collection->StartingRightPosition());

  Panel* panel = CreatePanel("PanelTest");
  panel->SetExpansionState(Panel::TITLE_ONLY);
  WaitForBoundsAnimationFinished(panel);

  EXPECT_EQ(docked_collection->work_area().bottom() - bottom_bar_thickness,
            panel->GetBounds().bottom());
  EXPECT_EQ(docked_collection->StartingRightPosition(),
            panel->GetBounds().right());

  initial_starting_right_position = docked_collection->StartingRightPosition();
  int bottom_bar_thickness_delta = 10;
  bottom_bar_thickness += bottom_bar_thickness_delta;
  int right_bar_thickness_delta = 15;
  right_bar_thickness += right_bar_thickness_delta;
  mock_display_settings_provider()->SetDesktopBarThickness(
      DisplaySettingsProvider::DESKTOP_BAR_ALIGNED_BOTTOM,
      bottom_bar_thickness);
  mock_display_settings_provider()->SetDesktopBarThickness(
      DisplaySettingsProvider::DESKTOP_BAR_ALIGNED_RIGHT,
      right_bar_thickness);
  base::MessageLoopForUI::current()->RunUntilIdle();
  EXPECT_EQ(initial_starting_right_position,
            docked_collection->StartingRightPosition());
  EXPECT_EQ(docked_collection->work_area().bottom() - bottom_bar_thickness,
            panel->GetBounds().bottom());
  EXPECT_EQ(docked_collection->StartingRightPosition(),
            panel->GetBounds().right());

  initial_starting_right_position = docked_collection->StartingRightPosition();
  bottom_bar_thickness_delta = 20;
  bottom_bar_thickness -= bottom_bar_thickness_delta;
  right_bar_thickness_delta = 10;
  right_bar_thickness -= right_bar_thickness_delta;
  mock_display_settings_provider()->SetDesktopBarThickness(
      DisplaySettingsProvider::DESKTOP_BAR_ALIGNED_BOTTOM,
      bottom_bar_thickness);
  mock_display_settings_provider()->SetDesktopBarThickness(
      DisplaySettingsProvider::DESKTOP_BAR_ALIGNED_RIGHT,
      right_bar_thickness);
  base::MessageLoopForUI::current()->RunUntilIdle();
  EXPECT_EQ(docked_collection->StartingRightPosition(),
            initial_starting_right_position);
  EXPECT_EQ(docked_collection->work_area().bottom() - bottom_bar_thickness,
            panel->GetBounds().bottom());
  EXPECT_EQ(docked_collection->StartingRightPosition(),
            panel->GetBounds().right());

  panel->Close();
}

IN_PROC_BROWSER_TEST_F(PanelBrowserTest, ActivatePanelOrTabbedWindow) {
  if (!WmSupportWindowActivation()) {
    LOG(WARNING) << "Skipping test due to WM problems.";
    return;
  }

  Panel* panel1 = CreatePanel("Panel1");
  Panel* panel2 = CreatePanel("Panel2");

  // Activate main tabbed window.
  browser()->window()->Activate();
  WaitForPanelActiveState(panel2, SHOW_AS_INACTIVE);

  // Activate a panel.
  panel2->Activate();
  WaitForPanelActiveState(panel2, SHOW_AS_ACTIVE);

  // Activate the main tabbed window back.
  browser()->window()->Activate();
  WaitForPanelActiveState(panel2, SHOW_AS_INACTIVE);

  // Activate another panel.
  panel1->Activate();
  WaitForPanelActiveState(panel1, SHOW_AS_ACTIVE);
  WaitForPanelActiveState(panel2, SHOW_AS_INACTIVE);

  // Switch focus between panels.
  panel2->Activate();
  WaitForPanelActiveState(panel2, SHOW_AS_ACTIVE);
  WaitForPanelActiveState(panel1, SHOW_AS_INACTIVE);

  PanelManager::GetInstance()->CloseAll();
}

// TODO(jianli): To be enabled for other platforms.
#if defined(OS_WIN) || defined(OS_LINUX)
#define MAYBE_ActivateDeactivateBasic ActivateDeactivateBasic
#else
#define MAYBE_ActivateDeactivateBasic DISABLED_ActivateDeactivateBasic
#endif
IN_PROC_BROWSER_TEST_F(PanelBrowserTest, MAYBE_ActivateDeactivateBasic) {
  if (!WmSupportWindowActivation()) {
    LOG(WARNING) << "Skipping test due to WM problems.";
    return;
  }

  // Create an active panel.
  Panel* panel = CreatePanel("PanelTest");
  scoped_ptr<NativePanelTesting> native_panel_testing(
      CreateNativePanelTesting(panel));

  WaitForPanelActiveState(panel, SHOW_AS_ACTIVE);  // doublecheck active state
  EXPECT_TRUE(native_panel_testing->VerifyActiveState(true));

  // Deactivate the panel.
  panel->Deactivate();
  WaitForPanelActiveState(panel, SHOW_AS_INACTIVE);

  // On GTK there is no way to deactivate a window. So the Deactivate() call
  // above does not actually deactivate the window, but simply lowers it.
#if !defined(OS_LINUX)
  EXPECT_TRUE(native_panel_testing->VerifyActiveState(false));
#endif

  // This test does not reactivate the panel because the panel might not be
  // reactivated programmatically once it is deactivated.
}

IN_PROC_BROWSER_TEST_F(PanelBrowserTest, ActivateDeactivateMultiple) {
  if (!WmSupportWindowActivation()) {
    LOG(WARNING) << "Skipping test due to WM problems.";
    return;
  }

  BrowserWindow* tabbed_window = browser()->window();

  // Create 4 panels in the following screen layout:
  //    P3  P2  P1  P0
  const int kNumPanels = 4;
  for (int i = 0; i < kNumPanels; ++i)
    CreatePanelWithBounds(MakePanelName(i), gfx::Rect(0, 0, 100, 100));
  const std::vector<Panel*>& panels = PanelManager::GetInstance()->panels();

  std::vector<bool> expected_active_states;
  std::vector<bool> last_active_states;

  // The last created panel, P3, should be active.
  expected_active_states = ProduceExpectedActiveStates(3);
  EXPECT_EQ(expected_active_states, GetAllPanelActiveStates());
  EXPECT_FALSE(tabbed_window->IsActive());

  // Activating P1 should cause P3 to lose focus.
  panels[1]->Activate();
  last_active_states = expected_active_states;
  expected_active_states = ProduceExpectedActiveStates(1);
  WaitForPanelActiveStates(last_active_states, expected_active_states);
  EXPECT_EQ(expected_active_states, GetAllPanelActiveStates());

  // Minimizing inactive panel P2 should not affect other panels' active states.
  panels[2]->SetExpansionState(Panel::MINIMIZED);
  EXPECT_EQ(expected_active_states, GetAllPanelActiveStates());
  EXPECT_FALSE(tabbed_window->IsActive());
}

IN_PROC_BROWSER_TEST_F(PanelBrowserTest, DrawAttentionBasic) {
  Panel* panel = CreateInactivePanel("P1");
  scoped_ptr<NativePanelTesting> native_panel_testing(
      CreateNativePanelTesting(panel));

  // Test that the attention is drawn when the expanded panel is not in focus.
  EXPECT_EQ(Panel::EXPANDED, panel->expansion_state());
  EXPECT_FALSE(panel->IsActive());
  EXPECT_FALSE(panel->IsDrawingAttention());
  panel->FlashFrame(true);
  EXPECT_TRUE(panel->IsDrawingAttention());
  EXPECT_TRUE(native_panel_testing->VerifyDrawingAttention());

  // Stop drawing attention.
  panel->FlashFrame(false);
  EXPECT_FALSE(panel->IsDrawingAttention());
  EXPECT_FALSE(native_panel_testing->VerifyDrawingAttention());

  // Draw attention, then minimize. Titlebar should remain visible.
  panel->FlashFrame(true);
  EXPECT_TRUE(panel->IsDrawingAttention());

  panel->Minimize();
  EXPECT_TRUE(panel->IsDrawingAttention());
  EXPECT_EQ(Panel::TITLE_ONLY, panel->expansion_state());

  // Stop drawing attention. Titlebar should no longer be visible.
  panel->FlashFrame(false);
  EXPECT_FALSE(panel->IsDrawingAttention());
  EXPECT_EQ(Panel::MINIMIZED, panel->expansion_state());

  panel->Close();
}

IN_PROC_BROWSER_TEST_F(PanelBrowserTest, DrawAttentionWhileMinimized) {
  Panel* panel1 = CreateInactivePanel("P1");
  Panel* panel2 = CreateInactivePanel("P2");

  scoped_ptr<NativePanelTesting> native_panel1_testing(
      CreateNativePanelTesting(panel1));

  // Test that the attention is drawn and the title-bar is brought up when the
  // minimized panel is drawing attention.
  panel1->Minimize();
  EXPECT_EQ(Panel::MINIMIZED, panel1->expansion_state());
  panel1->FlashFrame(true);
  EXPECT_TRUE(panel1->IsDrawingAttention());
  EXPECT_EQ(Panel::TITLE_ONLY, panel1->expansion_state());
  EXPECT_TRUE(native_panel1_testing->VerifyDrawingAttention());

  // Test that we cannot bring up other minimized panel if the mouse is over
  // the panel that draws attension.
  panel2->Minimize();
  gfx::Point hover_point(panel1->GetBounds().origin());
  MoveMouse(hover_point);
  EXPECT_EQ(Panel::TITLE_ONLY, panel1->expansion_state());
  EXPECT_EQ(Panel::MINIMIZED, panel2->expansion_state());

  // Test that we cannot bring down the panel that is drawing the attention.
  hover_point.set_y(hover_point.y() - 200);
  MoveMouse(hover_point);
  EXPECT_EQ(Panel::TITLE_ONLY, panel1->expansion_state());

  // Test that the attention is cleared when activated.
  panel1->Activate();
  WaitForPanelActiveState(panel1, SHOW_AS_ACTIVE);
  EXPECT_FALSE(panel1->IsDrawingAttention());
  EXPECT_EQ(Panel::EXPANDED, panel1->expansion_state());
  EXPECT_FALSE(native_panel1_testing->VerifyDrawingAttention());

  PanelManager::GetInstance()->CloseAll();
}

// Verify that minimized state of a panel is correct after draw attention
// is stopped when there are other minimized panels.
IN_PROC_BROWSER_TEST_F(PanelBrowserTest, StopDrawingAttentionWhileMinimized) {
  Panel* panel1 = CreateInactivePanel("P1");
  Panel* panel2 = CreateInactivePanel("P2");

  panel1->Minimize();
  EXPECT_EQ(Panel::MINIMIZED, panel1->expansion_state());
  panel2->Minimize();
  EXPECT_EQ(Panel::MINIMIZED, panel2->expansion_state());

  // Verify panel returns to minimized state when no longer drawing attention.
  panel1->FlashFrame(true);
  EXPECT_TRUE(panel1->IsDrawingAttention());
  EXPECT_EQ(Panel::TITLE_ONLY, panel1->expansion_state());

  panel1->FlashFrame(false);
  EXPECT_FALSE(panel1->IsDrawingAttention());
  EXPECT_EQ(Panel::MINIMIZED, panel1->expansion_state());

  // Hover over other minimized panel to bring up titlebars.
  gfx::Point hover_point(panel2->GetBounds().origin());
  MoveMouseAndWaitForExpansionStateChange(panel1, hover_point);
  EXPECT_EQ(Panel::TITLE_ONLY, panel1->expansion_state());
  EXPECT_EQ(Panel::TITLE_ONLY, panel2->expansion_state());

  // Verify panel keeps titlebar visible when no longer drawing attention
  // if titlebars are up.
  panel1->FlashFrame(true);
  EXPECT_TRUE(panel1->IsDrawingAttention());
  EXPECT_EQ(Panel::TITLE_ONLY, panel1->expansion_state());

  panel1->FlashFrame(false);
  EXPECT_FALSE(panel1->IsDrawingAttention());
  EXPECT_EQ(Panel::TITLE_ONLY, panel1->expansion_state());

  // Move mouse away. All panels should return to minimized state.
  hover_point.set_y(hover_point.y() - 200);
  MoveMouseAndWaitForExpansionStateChange(panel1, hover_point);
  EXPECT_EQ(Panel::MINIMIZED, panel1->expansion_state());
  EXPECT_EQ(Panel::MINIMIZED, panel2->expansion_state());

  // Verify minimized panel that is drawing attention stays in title-only mode
  // after attention is cleared if mouse is in the titlebar area.
  panel1->FlashFrame(true);
  EXPECT_TRUE(panel1->IsDrawingAttention());
  EXPECT_EQ(Panel::TITLE_ONLY, panel1->expansion_state());

  gfx::Point hover_point_in_panel(panel1->GetBounds().origin());
  MoveMouse(hover_point_in_panel);

  panel1->FlashFrame(false);
  EXPECT_FALSE(panel1->IsDrawingAttention());
  EXPECT_EQ(Panel::TITLE_ONLY, panel1->expansion_state());
  EXPECT_EQ(Panel::MINIMIZED, panel2->expansion_state());

  // Typical user scenario will detect the mouse in the panel
  // after attention is cleared, causing titles to pop up, so
  // we simulate that here.
  MoveMouseAndWaitForExpansionStateChange(panel2, hover_point_in_panel);
  EXPECT_EQ(Panel::TITLE_ONLY, panel1->expansion_state());
  EXPECT_EQ(Panel::TITLE_ONLY, panel2->expansion_state());

  // Move mouse away and panels should go back to fully minimized state.
  MoveMouseAndWaitForExpansionStateChange(panel1, hover_point);
  EXPECT_EQ(Panel::MINIMIZED, panel1->expansion_state());
  EXPECT_EQ(Panel::MINIMIZED, panel2->expansion_state());

  PanelManager::GetInstance()->CloseAll();
}

IN_PROC_BROWSER_TEST_F(PanelBrowserTest, DrawAttentionWhenActive) {
  // Create an active panel.
  Panel* panel = CreatePanel("P1");
  scoped_ptr<NativePanelTesting> native_panel_testing(
      CreateNativePanelTesting(panel));

  // Test that the attention should not be drawn if the expanded panel is in
  // focus.
  panel->FlashFrame(true);
  EXPECT_FALSE(panel->IsDrawingAttention());
  EXPECT_FALSE(native_panel_testing->VerifyDrawingAttention());

  panel->Close();
}

IN_PROC_BROWSER_TEST_F(PanelBrowserTest, DrawAttentionResetOnActivate) {
  Panel* panel = CreateInactivePanel("P1");
  scoped_ptr<NativePanelTesting> native_panel_testing(
      CreateNativePanelTesting(panel));

  panel->FlashFrame(true);
  EXPECT_TRUE(panel->IsDrawingAttention());
  EXPECT_TRUE(native_panel_testing->VerifyDrawingAttention());

  // Test that the attention is cleared when panel gets focus.
  panel->Activate();
  WaitForPanelActiveState(panel, SHOW_AS_ACTIVE);
  EXPECT_FALSE(panel->IsDrawingAttention());
  EXPECT_FALSE(native_panel_testing->VerifyDrawingAttention());

  panel->Close();
}

IN_PROC_BROWSER_TEST_F(PanelBrowserTest,
                       DrawAttentionMinimizedNotResetOnActivate) {
  Panel* panel = CreateInactivePanel("P1");

  panel->Minimize();
  EXPECT_TRUE(panel->IsMinimized());
  panel->FlashFrame(true);
  EXPECT_TRUE(panel->IsDrawingAttention());

  // Simulate panel being activated while minimized. Cannot call
  // Activate() as that expands the panel.
  panel->OnActiveStateChanged(true);
  EXPECT_TRUE(panel->IsDrawingAttention());  // Unchanged.

  // Unminimize panel to show that attention would have been cleared
  // if panel had not been minimized.
  panel->Restore();
  EXPECT_FALSE(panel->IsMinimized());
  EXPECT_TRUE(panel->IsDrawingAttention());  // Unchanged.

  panel->OnActiveStateChanged(true);
  EXPECT_FALSE(panel->IsDrawingAttention());  // Attention cleared.

  panel->Close();
}

IN_PROC_BROWSER_TEST_F(PanelBrowserTest, DrawAttentionResetOnClick) {
  Panel* panel = CreateInactivePanel("P1");
  scoped_ptr<NativePanelTesting> native_panel_testing(
      CreateNativePanelTesting(panel));

  panel->FlashFrame(true);
  EXPECT_TRUE(panel->IsDrawingAttention());
  EXPECT_TRUE(native_panel_testing->VerifyDrawingAttention());

  // Test that the attention is cleared when panel gets focus.
  native_panel_testing->PressLeftMouseButtonTitlebar(
      panel->GetBounds().origin());
  native_panel_testing->ReleaseMouseButtonTitlebar();

  WaitForPanelActiveState(panel, SHOW_AS_ACTIVE);
  EXPECT_FALSE(panel->IsDrawingAttention());
  EXPECT_FALSE(native_panel_testing->VerifyDrawingAttention());

  panel->Close();
}

// http://crbug.com/175760; several panel tests failing regularly on mac.
#if defined(OS_MACOSX)
#define MAYBE_MinimizeImmediatelyAfterRestore \
  DISABLED_MinimizeImmediatelyAfterRestore
#else
#define MAYBE_MinimizeImmediatelyAfterRestore MinimizeImmediatelyAfterRestore
#endif
IN_PROC_BROWSER_TEST_F(PanelBrowserTest,
                       MAYBE_MinimizeImmediatelyAfterRestore) {
  CreatePanelParams params("Panel Test", gfx::Rect(), SHOW_AS_ACTIVE);
  Panel* panel = CreatePanelWithParams(params);
  scoped_ptr<NativePanelTesting> native_panel_testing(
      CreateNativePanelTesting(panel));

  PanelActiveStateObserver signal(panel, false);
  panel->Minimize();  // this should deactivate.
  signal.Wait();
  EXPECT_EQ(Panel::MINIMIZED, panel->expansion_state());

  panel->Restore();
  EXPECT_EQ(Panel::EXPANDED, panel->expansion_state());

  // Verify that minimizing a panel right after expansion works.
  panel->Minimize();
  EXPECT_EQ(Panel::MINIMIZED, panel->expansion_state());

  panel->Close();
}

IN_PROC_BROWSER_TEST_F(PanelBrowserTest, FocusLostOnMinimize) {
  CreatePanelParams params("Initially Active", gfx::Rect(), SHOW_AS_ACTIVE);
  Panel* panel = CreatePanelWithParams(params);
  EXPECT_EQ(Panel::EXPANDED, panel->expansion_state());

  PanelActiveStateObserver signal(panel, false);
  panel->Minimize();
  signal.Wait();
  panel->Close();
}

IN_PROC_BROWSER_TEST_F(PanelBrowserTest, CreateInactiveSwitchToActive) {
  Panel* panel = CreateInactivePanel("1");

  panel->Activate();
  WaitForPanelActiveState(panel, SHOW_AS_ACTIVE);

  panel->Close();
}

// TODO(dimich): try/enable on other platforms. See bug 103253 for details on
// why this is disabled on windows.
#if defined(OS_MACOSX)
#define MAYBE_MinimizeTwoPanelsWithoutTabbedWindow \
    MinimizeTwoPanelsWithoutTabbedWindow
#else
#define MAYBE_MinimizeTwoPanelsWithoutTabbedWindow \
    DISABLED_MinimizeTwoPanelsWithoutTabbedWindow
#endif

// When there are 2 panels and no chrome window, minimizing one panel does
// not expand/focuses another.
IN_PROC_BROWSER_TEST_F(PanelBrowserTest,
                       MAYBE_MinimizeTwoPanelsWithoutTabbedWindow) {
  CreatePanelParams params("Initially Inactive", gfx::Rect(), SHOW_AS_INACTIVE);
  Panel* panel1 = CreatePanelWithParams(params);
  Panel* panel2 = CreatePanelWithParams(params);

  // Close main tabbed window.
  content::WindowedNotificationObserver signal(
      chrome::NOTIFICATION_BROWSER_CLOSED,
      content::Source<Browser>(browser()));
  chrome::CloseWindow(browser());
  signal.Wait();

  EXPECT_EQ(Panel::EXPANDED, panel1->expansion_state());
  EXPECT_EQ(Panel::EXPANDED, panel2->expansion_state());
  panel1->Activate();
  WaitForPanelActiveState(panel1, SHOW_AS_ACTIVE);

  panel1->SetExpansionState(Panel::MINIMIZED);
  base::MessageLoop::current()->RunUntilIdle();
  WaitForPanelActiveState(panel1, SHOW_AS_INACTIVE);
  EXPECT_EQ(Panel::MINIMIZED, panel1->expansion_state());

  panel2->SetExpansionState(Panel::MINIMIZED);
  base::MessageLoop::current()->RunUntilIdle();
  WaitForPanelActiveState(panel2, SHOW_AS_INACTIVE);
  EXPECT_EQ(Panel::MINIMIZED, panel2->expansion_state());

  // Verify that panel1 is still minimized and not active.
  WaitForPanelActiveState(panel1, SHOW_AS_INACTIVE);
  EXPECT_EQ(Panel::MINIMIZED, panel1->expansion_state());

  // Another check for the same.
  EXPECT_FALSE(panel1->IsActive());
  EXPECT_FALSE(panel2->IsActive());

  panel1->Close();
  panel2->Close();
}

IN_PROC_BROWSER_TEST_F(PanelBrowserTest,
                       NonExtensionDomainPanelsCloseOnUninstall) {
  // Create a test extension.
  DictionaryValue empty_value;
  scoped_refptr<extensions::Extension> extension =
      CreateExtension(FILE_PATH_LITERAL("TestExtension"),
                      extensions::Manifest::INTERNAL, empty_value);
  std::string extension_app_name =
      web_app::GenerateApplicationNameFromExtensionId(extension->id());

  PanelManager* panel_manager = PanelManager::GetInstance();
  EXPECT_EQ(0, panel_manager->num_panels());

  // Create a panel with the extension as host.
  CreatePanelParams params(extension_app_name, gfx::Rect(), SHOW_AS_ACTIVE);
  std::string extension_domain_url(extensions::kExtensionScheme);
  extension_domain_url += "://";
  extension_domain_url += extension->id();
  extension_domain_url += "/hello.html";
  params.url = GURL(extension_domain_url);
  Panel* panel = CreatePanelWithParams(params);
  EXPECT_EQ(1, panel_manager->num_panels());

  // Create a panel with a non-extension host.
  CreatePanelParams params1(extension_app_name, gfx::Rect(), SHOW_AS_ACTIVE);
  params1.url = GURL(content::kAboutBlankURL);
  Panel* panel1 = CreatePanelWithParams(params1);
  EXPECT_EQ(2, panel_manager->num_panels());

  // Create another extension and a panel from that extension.
  scoped_refptr<extensions::Extension> extension_other =
      CreateExtension(FILE_PATH_LITERAL("TestExtensionOther"),
                      extensions::Manifest::INTERNAL, empty_value);
  std::string extension_app_name_other =
      web_app::GenerateApplicationNameFromExtensionId(extension_other->id());
  Panel* panel_other = CreatePanel(extension_app_name_other);

  content::WindowedNotificationObserver signal(
      chrome::NOTIFICATION_PANEL_CLOSED,
      content::Source<Panel>(panel));
  content::WindowedNotificationObserver signal1(
      chrome::NOTIFICATION_PANEL_CLOSED,
      content::Source<Panel>(panel1));

  // Send unload notification on the first extension.
  extensions::UnloadedExtensionInfo details(
      extension.get(), extensions::UnloadedExtensionInfo::REASON_UNINSTALL);
  content::NotificationService::current()->Notify(
      chrome::NOTIFICATION_EXTENSION_UNLOADED,
      content::Source<Profile>(browser()->profile()),
      content::Details<extensions::UnloadedExtensionInfo>(&details));

  // Wait for the panels opened by the first extension to close.
  signal.Wait();
  signal1.Wait();

  // Verify that the panel that's left is the panel from the second extension.
  EXPECT_EQ(panel_other, panel_manager->panels()[0]);
  panel_other->Close();
}

IN_PROC_BROWSER_TEST_F(PanelBrowserTest, OnBeforeUnloadOnClose) {
  PanelManager* panel_manager = PanelManager::GetInstance();
  EXPECT_EQ(0, panel_manager->num_panels()); // No panels initially.

  const base::string16 title_first_close = UTF8ToUTF16("TitleFirstClose");
  const base::string16 title_second_close = UTF8ToUTF16("TitleSecondClose");

  // Create a test panel with web contents loaded.
  CreatePanelParams params("PanelTest1", gfx::Rect(0, 0, 300, 300),
                           SHOW_AS_ACTIVE);
  params.url = ui_test_utils::GetTestUrl(
      base::FilePath(kTestDir),
      base::FilePath(FILE_PATH_LITERAL("onbeforeunload.html")));
  Panel* panel = CreatePanelWithParams(params);
  EXPECT_EQ(1, panel_manager->num_panels());

  // Close panel and verify it closes despite having a onbeforeunload handler.
  CloseWindowAndWait(panel);
  EXPECT_EQ(0, panel_manager->num_panels());
}

// http://crbug.com/175760; several panel tests failing regularly on mac.
#if defined(OS_MACOSX)
#define MAYBE_SizeClamping DISABLED_SizeClamping
#else
#define MAYBE_SizeClamping SizeClamping
#endif
IN_PROC_BROWSER_TEST_F(PanelBrowserTest, MAYBE_SizeClamping) {
  // Using '0' sizes is equivalent of not providing sizes in API and causes
  // minimum sizes to be applied to facilitate auto-sizing.
  CreatePanelParams params("Panel", gfx::Rect(), SHOW_AS_ACTIVE);
  Panel* panel = CreatePanelWithParams(params);
  EXPECT_EQ(panel->min_size().width(), panel->GetBounds().width());
  EXPECT_EQ(panel->min_size().height(), panel->GetBounds().height());
  int reasonable_width = panel->min_size().width() + 10;
  int reasonable_height = panel->min_size().height() + 20;

  panel->Close();

  // Using reasonable actual sizes should avoid clamping.
  CreatePanelParams params1("Panel1",
                            gfx::Rect(0, 0,
                                      reasonable_width, reasonable_height),
                            SHOW_AS_ACTIVE);
  panel = CreatePanelWithParams(params1);
  EXPECT_EQ(reasonable_width, panel->GetBounds().width());
  EXPECT_EQ(reasonable_height, panel->GetBounds().height());
  panel->Close();

  // Using just one size should auto-compute some reasonable other size.
  int given_height = 200;
  CreatePanelParams params2("Panel2", gfx::Rect(0, 0, 0, given_height),
                            SHOW_AS_ACTIVE);
  panel = CreatePanelWithParams(params2);
  EXPECT_GT(panel->GetBounds().width(), 0);
  EXPECT_EQ(given_height, panel->GetBounds().height());
  panel->Close();
}

// http://crbug.com/175760; several panel tests failing regularly on mac.
// http://crbug.com/179890; TightAutosizeAroundSingleLine broken on Windows by
IN_PROC_BROWSER_TEST_F(PanelBrowserTest,
                       DISABLED_TightAutosizeAroundSingleLine) {
  PanelManager::GetInstance()->enable_auto_sizing(true);
  // Using 0 sizes triggers auto-sizing.
  CreatePanelParams params("Panel", gfx::Rect(), SHOW_AS_ACTIVE);
  params.url = GURL("data:text/html;charset=utf-8,<!doctype html><body>");
  Panel* panel = CreatePanelWithParams(params);

  // Ensure panel has auto resized to original web content size.
  WaitForStableInitialSize initial_resize(panel);
  initial_resize.Wait();

  int initial_width = panel->GetBounds().width();
  int initial_height = panel->GetBounds().height();

  // Inject some HTML content into the panel.
  WaitForAutoResizeWider enlarge(panel);
  EXPECT_TRUE(content::ExecuteScript(
      panel->GetWebContents(),
      "document.body.innerHTML ="
      "    '<nobr>line of text and a <button>Button</button>';"));
  enlarge.Wait();

  // The panel should have become larger in both dimensions (the minimums
  // has to be set to be smaller then a simple 1-line content, so the autosize
  // can work correctly.
  EXPECT_GT(panel->GetBounds().width(), initial_width);
  EXPECT_GT(panel->GetBounds().height(), initial_height);

  panel->Close();
}

// http://crbug.com/175760; several panel tests failing regularly on mac.
#if defined(OS_MACOSX)
#define MAYBE_DefaultMaxSizeOnDisplaySettingsChange \
        DISABLED_DefaultMaxSizeOnDisplaySettingsChange
#else
#define MAYBE_DefaultMaxSizeOnDisplaySettingsChange \
        DefaultMaxSizeOnDisplaySettingsChange
#endif
IN_PROC_BROWSER_TEST_F(PanelBrowserTest,
                       MAYBE_DefaultMaxSizeOnDisplaySettingsChange) {
  Panel* panel = CreatePanelWithBounds("1", gfx::Rect(0, 0, 240, 220));

  gfx::Size old_max_size = panel->max_size();
  gfx::Size old_full_size = panel->full_size();

  // Shrink the work area. Expect max size and full size become smaller.
  gfx::Rect smaller_work_area(0, 0, 500, 300);
  mock_display_settings_provider()->SetPrimaryDisplay(
      smaller_work_area, smaller_work_area);
  EXPECT_GT(old_max_size.width(), panel->max_size().width());
  EXPECT_GT(old_max_size.height(), panel->max_size().height());
  EXPECT_GT(smaller_work_area.width(), panel->max_size().width());
  EXPECT_GT(smaller_work_area.height(), panel->max_size().height());
  EXPECT_GT(old_full_size.width(), panel->full_size().width());
  EXPECT_GT(old_full_size.height(), panel->full_size().height());
  EXPECT_GE(panel->max_size().width(), panel->full_size().width());
  EXPECT_GE(panel->max_size().height(), panel->full_size().height());

  panel->Close();
}

// http://crbug.com/175760; several panel tests failing regularly on mac.
#if defined(OS_MACOSX)
#define MAYBE_CustomMaxSizeOnDisplaySettingsChange \
        DISABLED_CustomMaxSizeOnDisplaySettingsChange
#else
#define MAYBE_CustomMaxSizeOnDisplaySettingsChange \
        CustomMaxSizeOnDisplaySettingsChange
#endif
IN_PROC_BROWSER_TEST_F(PanelBrowserTest,
                       MAYBE_CustomMaxSizeOnDisplaySettingsChange) {
  PanelManager* panel_manager = PanelManager::GetInstance();
  Panel* panel = CreatePanelWithBounds("1", gfx::Rect(0, 0, 240, 220));

  // Trigger custom max size by user resizing.
  gfx::Size bigger_size = gfx::Size(550, 400);
  gfx::Point mouse_location = panel->GetBounds().origin();
  panel_manager->StartResizingByMouse(panel,
                                      mouse_location,
                                      panel::RESIZE_TOP_LEFT);
  mouse_location.Offset(panel->GetBounds().width() - bigger_size.width(),
                        panel->GetBounds().height() - bigger_size.height());
  panel_manager->ResizeByMouse(mouse_location);
  panel_manager->EndResizingByMouse(false);

  gfx::Size old_max_size = panel->max_size();
  EXPECT_EQ(bigger_size, old_max_size);
  gfx::Size old_full_size = panel->full_size();
  EXPECT_EQ(bigger_size, old_full_size);

  // Shrink the work area. Expect max size and full size become smaller.
  gfx::Rect smaller_work_area(0, 0, 500, 300);
  mock_display_settings_provider()->SetPrimaryDisplay(
      smaller_work_area, smaller_work_area);
  EXPECT_GT(old_max_size.width(), panel->max_size().width());
  EXPECT_GT(old_max_size.height(), panel->max_size().height());
  EXPECT_GE(smaller_work_area.width(), panel->max_size().width());
  EXPECT_EQ(smaller_work_area.height(), panel->max_size().height());
  EXPECT_GT(old_full_size.width(), panel->full_size().width());
  EXPECT_GT(old_full_size.height(), panel->full_size().height());
  EXPECT_GE(panel->max_size().width(), panel->full_size().width());
  EXPECT_GE(panel->max_size().height(), panel->full_size().height());
  EXPECT_EQ(smaller_work_area.height(), panel->full_size().height());

  panel->Close();
}

IN_PROC_BROWSER_TEST_F(PanelBrowserTest, DevTools) {
  // Create a test panel with web contents loaded.
  CreatePanelParams params("1", gfx::Rect(0, 0, 200, 220), SHOW_AS_ACTIVE);
  GURL url(ui_test_utils::GetTestUrl(
      base::FilePath(kTestDir),
      base::FilePath(FILE_PATH_LITERAL("update-preferred-size.html"))));
  params.url = url;
  Panel* panel = CreatePanelWithParams(params);

  // Open devtools.
  size_t num_browsers = 1;
  EXPECT_EQ(num_browsers, chrome::GetBrowserCount(
                              browser()->profile(),
                              browser()->host_desktop_type()));
  content::WindowedNotificationObserver signal(
      chrome::NOTIFICATION_BROWSER_WINDOW_READY,
      content::NotificationService::AllSources());
  EXPECT_TRUE(panel->ExecuteCommandIfEnabled(IDC_DEV_TOOLS));
  signal.Wait();

  // Check that the new browser window that opened is dev tools window.
  ++num_browsers;
  EXPECT_EQ(num_browsers, chrome::GetBrowserCount(
                              browser()->profile(),
                              browser()->host_desktop_type()));
  for (chrome::BrowserIterator iter; !iter.done(); iter.Next()) {
    if (*iter == browser())
      continue;
    ASSERT_TRUE((*iter)->is_devtools());
  }

  panel->Close();
}

IN_PROC_BROWSER_TEST_F(PanelBrowserTest, DevToolsConsole) {
  // Create a test panel with web contents loaded.
  CreatePanelParams params("1", gfx::Rect(0, 0, 200, 220), SHOW_AS_ACTIVE);
  GURL url(ui_test_utils::GetTestUrl(
      base::FilePath(kTestDir),
      base::FilePath(FILE_PATH_LITERAL("update-preferred-size.html"))));
  params.url = url;
  Panel* panel = CreatePanelWithParams(params);

  // Open devtools console.
  size_t num_browsers = 1;
  EXPECT_EQ(num_browsers, chrome::GetBrowserCount(
                              browser()->profile(),
                              browser()->host_desktop_type()));
  content::WindowedNotificationObserver signal(
      chrome::NOTIFICATION_BROWSER_WINDOW_READY,
      content::NotificationService::AllSources());
  EXPECT_TRUE(panel->ExecuteCommandIfEnabled(IDC_DEV_TOOLS_CONSOLE));
  signal.Wait();

  // Check that the new browser window that opened is dev tools window.
  ++num_browsers;
  EXPECT_EQ(num_browsers, chrome::GetBrowserCount(
                              browser()->profile(),
                              browser()->host_desktop_type()));
  for (chrome::BrowserIterator iter; !iter.done(); iter.Next()) {
    if (*iter == browser())
      continue;
    ASSERT_TRUE((*iter)->is_devtools());
  }

  panel->Close();
}

#if defined(OS_WIN)
#define MAYBE_Accelerator Accelerator
#else
#define MAYBE_Accelerator DISABLED_Accelerator
#endif
IN_PROC_BROWSER_TEST_F(PanelBrowserTest, MAYBE_Accelerator) {
  PanelManager* panel_manager = PanelManager::GetInstance();

  // Create a test panel with web contents loaded.
  CreatePanelParams params("1", gfx::Rect(), SHOW_AS_ACTIVE);
  GURL url(ui_test_utils::GetTestUrl(
      base::FilePath(kTestDir),
      base::FilePath(FILE_PATH_LITERAL("update-preferred-size.html"))));
  params.url = url;
  Panel* panel = CreatePanelWithParams(params);
  EXPECT_EQ(1, panel_manager->num_panels());

  // Close the panel by acclerator.
  content::WindowedNotificationObserver signal(
      chrome::NOTIFICATION_PANEL_CLOSED,
      content::Source<Panel>(panel));
#if defined(USE_AURA)
  double now = ui::EventTimeForNow().InSecondsF();
  content::NativeWebKeyboardEvent key_event(
      ui::ET_KEY_PRESSED,
      false,
      ui::VKEY_W,
      ui::EF_CONTROL_DOWN,
      now);
#elif defined(OS_WIN)
  ::MSG key_msg = { NULL, WM_KEYDOWN, ui::VKEY_W, 0 };
  content::NativeWebKeyboardEvent key_event(key_msg);
  key_event.modifiers = content::NativeWebKeyboardEvent::ControlKey;
#else
  content::NativeWebKeyboardEvent key_event;
#endif
  panel->HandleKeyboardEvent(key_event);
  signal.Wait();
  EXPECT_EQ(0, panel_manager->num_panels());
}

IN_PROC_BROWSER_TEST_F(PanelBrowserTest,
                       HideDockedPanelCreatedBeforeFullScreenMode) {
  // Create a docked panel.
  Panel* panel = CreatePanel("PanelTest");
  scoped_ptr<NativePanelTesting> panel_testing(CreateNativePanelTesting(panel));

  // Panel should be visible at first.
  EXPECT_TRUE(panel_testing->IsWindowVisible());

  // Panel should become hidden when entering full-screen mode.
  // Note that this is not needed on Linux because the full-screen window will
  // be always placed above any other windows.
  mock_display_settings_provider()->EnableFullScreenMode(true);
#if defined(OS_LINUX)
  EXPECT_TRUE(panel_testing->IsWindowVisible());
#else
  EXPECT_FALSE(panel_testing->IsWindowVisible());
#endif

  // Panel should become visible when leaving full-screen mode.
  mock_display_settings_provider()->EnableFullScreenMode(false);
  EXPECT_TRUE(panel_testing->IsWindowVisible());

  PanelManager::GetInstance()->CloseAll();
}

IN_PROC_BROWSER_TEST_F(PanelBrowserTest,
                       HideDockedPanelCreatedOnFullScreenMode) {
  // Enable full-screen mode first.
  mock_display_settings_provider()->EnableFullScreenMode(true);

  // Create a docked panel without waiting for it to be shown since it is not
  // supposed to be shown on full-screen mode.
  CreatePanelParams params("1", gfx::Rect(0, 0, 250, 200), SHOW_AS_ACTIVE);
  params.wait_for_fully_created = false;
  Panel* panel = CreatePanelWithParams(params);
  scoped_ptr<NativePanelTesting> panel_testing(
      CreateNativePanelTesting(panel));

  // Panel should not be shown on full-screen mode.
  EXPECT_FALSE(panel_testing->IsWindowVisible());

  // Panel should become visible when leaving full-screen mode.
  mock_display_settings_provider()->EnableFullScreenMode(false);
  EXPECT_TRUE(panel_testing->IsWindowVisible());

  PanelManager::GetInstance()->CloseAll();
}

class PanelExtensionApiTest : public ExtensionApiTest {
 protected:
  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
    ExtensionApiTest::SetUpCommandLine(command_line);
    command_line->AppendSwitch(switches::kEnablePanels);
  }
};

#if defined(OS_LINUX) || (!defined(OS_WIN) && defined(USE_AURA)) || \
    defined(OS_MACOSX)
// Focus test fails if there is no window manager on Linux.
// Aura panels have different behavior that do not apply to this test.
#define MAYBE_FocusChangeEventOnMinimize DISABLED_FocusChangeEventOnMinimize
#else
#define MAYBE_FocusChangeEventOnMinimize FocusChangeEventOnMinimize
#endif
IN_PROC_BROWSER_TEST_F(PanelExtensionApiTest,
                       MAYBE_FocusChangeEventOnMinimize) {
  // This is needed so the subsequently created panels can be activated.
  // On a Mac, it transforms background-only test process into foreground one.
  ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(browser()));
  ASSERT_TRUE(RunExtensionTest("panels/focus_change_on_minimize")) << message_;
}