123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329 |
- // Copyright 2013 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 "ash/shelf/shelf_window_watcher.h"
- #include <memory>
- #include "ash/public/cpp/shelf_item.h"
- #include "ash/public/cpp/shelf_model.h"
- #include "ash/public/cpp/shell_window_ids.h"
- #include "ash/public/cpp/window_properties.h"
- #include "ash/root_window_controller.h"
- #include "ash/session/session_controller_impl.h"
- #include "ash/shell.h"
- #include "ash/test/ash_test_base.h"
- #include "ash/wm/desks/desks_util.h"
- #include "ash/wm/window_resizer.h"
- #include "ash/wm/window_state.h"
- #include "base/strings/string_number_conversions.h"
- #include "third_party/skia/include/core/SkBitmap.h"
- #include "ui/aura/client/aura_constants.h"
- #include "ui/aura/window.h"
- #include "ui/base/hit_test.h"
- #include "ui/base/resource/resource_bundle.h"
- #include "ui/gfx/image/image_skia.h"
- #include "ui/resources/grit/ui_resources.h"
- #include "ui/views/widget/widget.h"
- #include "ui/wm/core/transient_window_controller.h"
- namespace ash {
- namespace {
- // Create a test 1x1 icon image with a given |color|.
- gfx::ImageSkia CreateImageSkiaIcon(SkColor color) {
- SkBitmap bitmap;
- bitmap.allocN32Pixels(1, 1);
- bitmap.eraseColor(color);
- return gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
- }
- static ShelfID CreateShelfItem(aura::Window* window) {
- static int id = 0;
- ShelfID shelf_id(base::NumberToString(id++));
- window->SetProperty(kShelfIDKey, shelf_id.Serialize());
- window->SetProperty(kShelfItemTypeKey, static_cast<int32_t>(TYPE_DIALOG));
- return shelf_id;
- }
- using ShelfWindowWatcherTest = AshTestBase;
- // Ensure shelf items are added and removed as windows are opened and closed.
- TEST_F(ShelfWindowWatcherTest, OpenAndClose) {
- ShelfModel* model = ShelfModel::Get();
- ASSERT_EQ(0, model->item_count());
- // Windows with valid ShelfItemType and ShelfID properties get shelf items.
- std::unique_ptr<views::Widget> widget1 = CreateTestWidget(
- nullptr, desks_util::GetActiveDeskContainerId(), gfx::Rect());
- CreateShelfItem(widget1->GetNativeWindow());
- EXPECT_EQ(1, model->item_count());
- std::unique_ptr<views::Widget> widget2 = CreateTestWidget(
- nullptr, desks_util::GetActiveDeskContainerId(), gfx::Rect());
- CreateShelfItem(widget2->GetNativeWindow());
- EXPECT_EQ(2, model->item_count());
- // Each ShelfItem is removed when the associated window is destroyed.
- widget1.reset();
- EXPECT_EQ(1, model->item_count());
- widget2.reset();
- EXPECT_EQ(0, model->item_count());
- }
- TEST_F(ShelfWindowWatcherTest, CreateAndRemoveShelfItemProperties) {
- ShelfModel* model = ShelfModel::Get();
- // Creating windows without a valid ShelfItemType does not add items.
- std::unique_ptr<views::Widget> widget1 = CreateTestWidget(
- nullptr, desks_util::GetActiveDeskContainerId(), gfx::Rect());
- std::unique_ptr<views::Widget> widget2 = CreateTestWidget(
- nullptr, desks_util::GetActiveDeskContainerId(), gfx::Rect());
- EXPECT_EQ(0, model->item_count());
- // Create a ShelfItem for the first window.
- ShelfID id_w1 = CreateShelfItem(widget1->GetNativeWindow());
- EXPECT_EQ(1, model->item_count());
- int index_w1 = model->ItemIndexByID(id_w1);
- EXPECT_EQ(STATUS_RUNNING, model->items()[index_w1].status);
- // Create a ShelfItem for the second window.
- ShelfID id_w2 = CreateShelfItem(widget2->GetNativeWindow());
- EXPECT_EQ(2, model->item_count());
- int index_w2 = model->ItemIndexByID(id_w2);
- EXPECT_EQ(STATUS_RUNNING, model->items()[index_w2].status);
- // ShelfItem is removed when the type property is cleared.
- widget1->GetNativeWindow()->SetProperty(kShelfItemTypeKey,
- static_cast<int32_t>(TYPE_UNDEFINED));
- EXPECT_EQ(1, model->item_count());
- widget2->GetNativeWindow()->SetProperty(kShelfItemTypeKey,
- static_cast<int32_t>(TYPE_UNDEFINED));
- EXPECT_EQ(0, model->item_count());
- // Clearing twice doesn't do anything.
- widget2->GetNativeWindow()->SetProperty(kShelfItemTypeKey,
- static_cast<int32_t>(TYPE_UNDEFINED));
- EXPECT_EQ(0, model->item_count());
- // Closing the windows once the properties are cleared doesn't do anything.
- widget1->CloseNow();
- EXPECT_EQ(0, model->item_count());
- widget2->CloseNow();
- EXPECT_EQ(0, model->item_count());
- }
- TEST_F(ShelfWindowWatcherTest, UpdateWindowProperty) {
- ShelfModel* model = ShelfModel::Get();
- // Create a ShelfItem for a new window.
- std::unique_ptr<views::Widget> widget = CreateTestWidget(
- nullptr, desks_util::GetActiveDeskContainerId(), gfx::Rect());
- ShelfID id = CreateShelfItem(widget->GetNativeWindow());
- EXPECT_EQ(1, model->item_count());
- int index = model->ItemIndexByID(id);
- EXPECT_EQ(STATUS_RUNNING, model->items()[index].status);
- // No new item is created after updating a launcher item.
- EXPECT_EQ(1, model->item_count());
- // index and id are not changed after updating a launcher item.
- EXPECT_EQ(index, model->ItemIndexByID(id));
- EXPECT_EQ(id, model->items()[index].id);
- }
- TEST_F(ShelfWindowWatcherTest, MaximizeAndRestoreWindow) {
- ShelfModel* model = ShelfModel::Get();
- // Create a ShelfItem for a new window.
- std::unique_ptr<views::Widget> widget = CreateTestWidget(
- nullptr, desks_util::GetActiveDeskContainerId(), gfx::Rect());
- ShelfID id = CreateShelfItem(widget->GetNativeWindow());
- EXPECT_EQ(1, model->item_count());
- int index = model->ItemIndexByID(id);
- EXPECT_EQ(STATUS_RUNNING, model->items()[index].status);
- // Maximize the window.
- WindowState* window_state = WindowState::Get(widget->GetNativeWindow());
- EXPECT_FALSE(window_state->IsMaximized());
- window_state->Maximize();
- EXPECT_TRUE(window_state->IsMaximized());
- // No new item is created after maximizing the window.
- EXPECT_EQ(1, model->item_count());
- // index and id are not changed after maximizing the window.
- EXPECT_EQ(index, model->ItemIndexByID(id));
- EXPECT_EQ(id, model->items()[index].id);
- // Restore the window.
- window_state->Restore();
- EXPECT_FALSE(window_state->IsMaximized());
- // No new item is created after restoring the window.
- EXPECT_EQ(1, model->item_count());
- // Index and id are not changed after maximizing the window.
- EXPECT_EQ(index, model->ItemIndexByID(id));
- EXPECT_EQ(id, model->items()[index].id);
- }
- // Check |window|'s item is not changed during the dragging.
- // TODO(simonhong): Add a test for removing a Window during the dragging.
- TEST_F(ShelfWindowWatcherTest, DragWindow) {
- ShelfModel* model = ShelfModel::Get();
- // Create a ShelfItem for a new window.
- std::unique_ptr<views::Widget> widget = CreateTestWidget(
- nullptr, desks_util::GetActiveDeskContainerId(), gfx::Rect());
- ShelfID id = CreateShelfItem(widget->GetNativeWindow());
- EXPECT_EQ(1, model->item_count());
- int index = model->ItemIndexByID(id);
- EXPECT_EQ(STATUS_RUNNING, model->items()[index].status);
- // Simulate dragging of the window and check its item is not changed.
- std::unique_ptr<WindowResizer> resizer(
- CreateWindowResizer(widget->GetNativeWindow(), gfx::PointF(), HTCAPTION,
- ::wm::WINDOW_MOVE_SOURCE_MOUSE));
- ASSERT_TRUE(resizer.get());
- resizer->Drag(gfx::PointF(50, 50), 0);
- resizer->CompleteDrag();
- // Index and id are not changed after dragging the window.
- EXPECT_EQ(index, model->ItemIndexByID(id));
- EXPECT_EQ(id, model->items()[index].id);
- }
- // Ensure dialogs get shelf items.
- TEST_F(ShelfWindowWatcherTest, DialogWindows) {
- ShelfModel* model = ShelfModel::Get();
- // An item is created for a dialog window.
- std::unique_ptr<views::Widget> dialog_widget = CreateTestWidget(
- nullptr, desks_util::GetActiveDeskContainerId(), gfx::Rect());
- aura::Window* dialog = dialog_widget->GetNativeWindow();
- dialog->SetProperty(kShelfIDKey, ShelfID("a").Serialize());
- dialog->SetProperty(kShelfItemTypeKey, static_cast<int32_t>(TYPE_DIALOG));
- EXPECT_EQ(1, model->item_count());
- // An item is not created for an app window.
- std::unique_ptr<views::Widget> app_widget = CreateTestWidget(
- nullptr, desks_util::GetActiveDeskContainerId(), gfx::Rect());
- aura::Window* app = app_widget->GetNativeWindow();
- app->SetProperty(kShelfIDKey, ShelfID("c").Serialize());
- app->SetProperty(kShelfItemTypeKey, static_cast<int32_t>(TYPE_APP));
- EXPECT_EQ(1, model->item_count());
- app_widget.reset();
- // Each ShelfItem is removed when the associated window is destroyed.
- dialog_widget.reset();
- EXPECT_EQ(0, model->item_count());
- }
- // Ensure items use the app icon and window icon aura::Window properties.
- TEST_F(ShelfWindowWatcherTest, ItemIcon) {
- ShelfModel* model = ShelfModel::Get();
- // Create a ShelfItem for a window; it should have a default icon.
- std::unique_ptr<views::Widget> widget = CreateTestWidget(
- nullptr, desks_util::GetActiveDeskContainerId(), gfx::Rect());
- aura::Window* window = widget->GetNativeWindow();
- ShelfID id = CreateShelfItem(window);
- EXPECT_EQ(1, model->item_count());
- ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
- gfx::Image default_image = rb.GetImageNamed(IDR_DEFAULT_FAVICON_32);
- EXPECT_TRUE(model->items()[0].image.BackedBySameObjectAs(
- default_image.AsImageSkia()));
- // Setting a window icon should update the item icon.
- gfx::ImageSkia red = CreateImageSkiaIcon(SK_ColorRED);
- window->SetProperty(aura::client::kWindowIconKey, std::move(red));
- EXPECT_EQ(SK_ColorRED, model->items()[0].image.bitmap()->getColor(0, 0));
- // Setting an app icon should override the window icon.
- gfx::ImageSkia blue = CreateImageSkiaIcon(SK_ColorBLUE);
- window->SetProperty(aura::client::kAppIconKey, std::move(blue));
- EXPECT_EQ(SK_ColorBLUE, model->items()[0].image.bitmap()->getColor(0, 0));
- // Clearing the app icon should restore the window icon to the shelf item.
- window->ClearProperty(aura::client::kAppIconKey);
- EXPECT_EQ(SK_ColorRED, model->items()[0].image.bitmap()->getColor(0, 0));
- }
- TEST_F(ShelfWindowWatcherTest, DontCreateShelfEntriesForChildWindows) {
- ShelfModel* model = ShelfModel::Get();
- std::unique_ptr<aura::Window> window =
- std::make_unique<aura::Window>(nullptr, aura::client::WINDOW_TYPE_NORMAL);
- window->Init(ui::LAYER_NOT_DRAWN);
- window->SetProperty(kShelfIDKey, ShelfID("a").Serialize());
- window->SetProperty(kShelfItemTypeKey, static_cast<int32_t>(TYPE_DIALOG));
- Shell::GetPrimaryRootWindow()
- ->GetChildById(desks_util::GetActiveDeskContainerId())
- ->AddChild(window.get());
- window->Show();
- EXPECT_EQ(1, model->item_count());
- std::unique_ptr<aura::Window> child =
- std::make_unique<aura::Window>(nullptr, aura::client::WINDOW_TYPE_NORMAL);
- child->Init(ui::LAYER_NOT_DRAWN);
- child->SetProperty(kShelfIDKey, ShelfID("b").Serialize());
- child->SetProperty(kShelfItemTypeKey, static_cast<int32_t>(TYPE_DIALOG));
- window->AddChild(child.get());
- child->Show();
- // There should not be a new shelf item for |child|.
- EXPECT_EQ(1, model->item_count());
- child.reset();
- EXPECT_EQ(1, model->item_count());
- window.reset();
- EXPECT_EQ(0, model->item_count());
- }
- TEST_F(ShelfWindowWatcherTest, CreateShelfEntriesForTransientWindows) {
- ShelfModel* model = ShelfModel::Get();
- std::unique_ptr<aura::Window> window =
- std::make_unique<aura::Window>(nullptr, aura::client::WINDOW_TYPE_NORMAL);
- window->Init(ui::LAYER_NOT_DRAWN);
- window->SetProperty(kShelfIDKey, ShelfID("a").Serialize());
- window->SetProperty(kShelfItemTypeKey, static_cast<int32_t>(TYPE_DIALOG));
- Shell::GetPrimaryRootWindow()
- ->GetChildById(desks_util::GetActiveDeskContainerId())
- ->AddChild(window.get());
- window->Show();
- EXPECT_EQ(1, model->item_count());
- std::unique_ptr<aura::Window> transient =
- std::make_unique<aura::Window>(nullptr, aura::client::WINDOW_TYPE_NORMAL);
- transient->Init(ui::LAYER_NOT_DRAWN);
- transient->SetProperty(kShelfIDKey,
- new std::string(ShelfID("b").Serialize()));
- transient->SetProperty(kShelfItemTypeKey, static_cast<int32_t>(TYPE_DIALOG));
- Shell::GetPrimaryRootWindow()
- ->GetChildById(desks_util::GetActiveDeskContainerId())
- ->AddChild(transient.get());
- ::wm::TransientWindowController::Get()->AddTransientChild(window.get(),
- transient.get());
- transient->Show();
- // There should be a new shelf item for |transient|.
- EXPECT_EQ(2, model->item_count());
- transient.reset();
- EXPECT_EQ(1, model->item_count());
- window.reset();
- EXPECT_EQ(0, model->item_count());
- }
- // Ensures ShelfWindowWatcher supports windows opened prior to session start.
- using ShelfWindowWatcherSessionStartTest = NoSessionAshTestBase;
- TEST_F(ShelfWindowWatcherSessionStartTest, PreExistingWindow) {
- ShelfModel* model = ShelfModel::Get();
- ASSERT_FALSE(
- Shell::Get()->session_controller()->IsActiveUserSessionStarted());
- EXPECT_EQ(0, model->item_count());
- // Construct a window that should get a shelf item once the session starts.
- std::unique_ptr<views::Widget> widget = CreateTestWidget(
- nullptr, desks_util::GetActiveDeskContainerId(), gfx::Rect());
- CreateShelfItem(widget->GetNativeWindow());
- EXPECT_EQ(0, model->item_count());
- // Start the test user session; ShelfWindowWatcher will find the open window.
- CreateUserSessions(1);
- EXPECT_EQ(1, model->item_count());
- }
- } // namespace
- } // namespace ash
|