1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ash/shelf/shelf_context_menu_model.h"
6
7 #include "ash/public/cpp/app_menu_constants.h"
8 #include "ash/public/cpp/shelf_item_delegate.h"
9 #include "ash/public/cpp/wallpaper_controller_client.h"
10 #include "ash/session/test_session_controller_client.h"
11 #include "ash/shelf/shelf.h"
12 #include "ash/shell.h"
13 #include "ash/test/ash_test_base.h"
14 #include "ash/test_shell_delegate.h"
15 #include "ash/wallpaper/wallpaper_controller_impl.h"
16 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "ui/display/display.h"
19 #include "ui/views/widget/widget.h"
20
21 namespace ash {
22 namespace {
23
24 using CommandId = ShelfContextMenuModel::CommandId;
25
26 class ShelfContextMenuModelTest : public AshTestBase {
27 public:
28 ShelfContextMenuModelTest() = default;
29 ~ShelfContextMenuModelTest() override = default;
30
SetUp()31 void SetUp() override {
32 AshTestBase::SetUp();
33 TestSessionControllerClient* session = GetSessionControllerClient();
34 session->AddUserSession("user1@test.com");
35 session->SetSessionState(session_manager::SessionState::ACTIVE);
36 session->SwitchActiveUser(AccountId::FromUserEmail("user1@test.com"));
37 }
38
39 private:
40 DISALLOW_COPY_AND_ASSIGN(ShelfContextMenuModelTest);
41 };
42
43 // A test wallpaper controller client class.
44 class TestWallpaperControllerClient : public WallpaperControllerClient {
45 public:
46 TestWallpaperControllerClient() = default;
47 virtual ~TestWallpaperControllerClient() = default;
48
open_count() const49 size_t open_count() const { return open_count_; }
50
51 // WallpaperControllerClient:
OpenWallpaperPicker()52 void OpenWallpaperPicker() override { open_count_++; }
MaybeClosePreviewWallpaper()53 void MaybeClosePreviewWallpaper() override {}
54
55 private:
56 size_t open_count_ = 0;
57
58 DISALLOW_COPY_AND_ASSIGN(TestWallpaperControllerClient);
59 };
60
61 // A test shelf item delegate that records the commands sent for execution.
62 class TestShelfItemDelegate : public ShelfItemDelegate {
63 public:
TestShelfItemDelegate()64 TestShelfItemDelegate() : ShelfItemDelegate(ShelfID()) {}
65 ~TestShelfItemDelegate() override = default;
66
last_executed_command() const67 int last_executed_command() const { return last_executed_command_; }
68
69 // ShelfItemDelegate:
ItemSelected(std::unique_ptr<ui::Event> event,int64_t display_id,ShelfLaunchSource source,ItemSelectedCallback callback,const ItemFilterPredicate & filter_predicate)70 void ItemSelected(std::unique_ptr<ui::Event> event,
71 int64_t display_id,
72 ShelfLaunchSource source,
73 ItemSelectedCallback callback,
74 const ItemFilterPredicate& filter_predicate) override {}
ExecuteCommand(bool from_context_menu,int64_t command_id,int32_t event_flags,int64_t display_id)75 void ExecuteCommand(bool from_context_menu,
76 int64_t command_id,
77 int32_t event_flags,
78 int64_t display_id) override {
79 ASSERT_TRUE(from_context_menu);
80 last_executed_command_ = command_id;
81 }
Close()82 void Close() override {}
83
84 private:
85 int last_executed_command_ = 0;
86
87 DISALLOW_COPY_AND_ASSIGN(TestShelfItemDelegate);
88 };
89
90 // Tests the default items in a shelf context menu.
TEST_F(ShelfContextMenuModelTest,Basic)91 TEST_F(ShelfContextMenuModelTest, Basic) {
92 ShelfContextMenuModel menu(nullptr, GetPrimaryDisplay().id());
93
94 ASSERT_EQ(3, menu.GetItemCount());
95 EXPECT_EQ(CommandId::MENU_AUTO_HIDE, menu.GetCommandIdAt(0));
96 EXPECT_EQ(CommandId::MENU_ALIGNMENT_MENU, menu.GetCommandIdAt(1));
97 EXPECT_EQ(CommandId::MENU_CHANGE_WALLPAPER, menu.GetCommandIdAt(2));
98 for (int i = 0; i < menu.GetItemCount(); ++i) {
99 EXPECT_TRUE(menu.IsEnabledAt(i));
100 EXPECT_TRUE(menu.IsVisibleAt(i));
101 }
102
103 // Check the alignment submenu.
104 EXPECT_EQ(ui::MenuModel::TYPE_SUBMENU, menu.GetTypeAt(1));
105 ui::MenuModel* submenu = menu.GetSubmenuModelAt(1);
106 ASSERT_TRUE(submenu);
107 ASSERT_EQ(3, submenu->GetItemCount());
108 EXPECT_EQ(CommandId::MENU_ALIGNMENT_LEFT, submenu->GetCommandIdAt(0));
109 EXPECT_EQ(CommandId::MENU_ALIGNMENT_BOTTOM, submenu->GetCommandIdAt(1));
110 EXPECT_EQ(CommandId::MENU_ALIGNMENT_RIGHT, submenu->GetCommandIdAt(2));
111 }
112
113 // Test invocation of the default menu items.
TEST_F(ShelfContextMenuModelTest,Invocation)114 TEST_F(ShelfContextMenuModelTest, Invocation) {
115 int64_t primary_id = GetPrimaryDisplay().id();
116 Shelf* shelf = GetPrimaryShelf();
117
118 // Check the shelf auto-hide behavior and menu interaction.
119 ShelfContextMenuModel menu1(nullptr, primary_id);
120 EXPECT_EQ(ShelfAutoHideBehavior::kNever, shelf->auto_hide_behavior());
121 menu1.ActivatedAt(0);
122 EXPECT_EQ(ShelfAutoHideBehavior::kAlways, shelf->auto_hide_behavior());
123
124 // Recreate the menu, auto-hide should still be enabled.
125 ShelfContextMenuModel menu2(nullptr, primary_id);
126 EXPECT_EQ(ShelfAutoHideBehavior::kAlways, shelf->auto_hide_behavior());
127
128 // By default the shelf should be on bottom, shelf alignment options in order:
129 // Left, Bottom, Right. Bottom should be checked.
130 ui::MenuModel* submenu = menu2.GetSubmenuModelAt(1);
131 EXPECT_TRUE(submenu->IsItemCheckedAt(1));
132 EXPECT_EQ(ShelfAlignment::kBottom, shelf->alignment());
133
134 // Activate the left shelf alignment option.
135 submenu->ActivatedAt(0);
136 EXPECT_EQ(ShelfAlignment::kLeft, shelf->alignment());
137
138 // Recreate the menu, it should show left alignment checked.
139 ShelfContextMenuModel menu3(nullptr, primary_id);
140 submenu = menu3.GetSubmenuModelAt(1);
141 EXPECT_TRUE(submenu->IsItemCheckedAt(0));
142
143 TestWallpaperControllerClient client;
144 Shell::Get()->wallpaper_controller()->SetClient(&client);
145 EXPECT_EQ(0u, client.open_count());
146
147 // Click the third option, wallpaper picker. It should open.
148 menu3.ActivatedAt(2);
149 EXPECT_EQ(1u, client.open_count());
150 }
151
152 // Tests custom items in a shelf context menu for an application.
TEST_F(ShelfContextMenuModelTest,CustomItems)153 TEST_F(ShelfContextMenuModelTest, CustomItems) {
154 // Pass a valid delegate to indicate the menu is for an application.
155 TestShelfItemDelegate delegate;
156 ShelfContextMenuModel menu(&delegate, GetPrimaryDisplay().id());
157
158 // Because the delegate is valid, the context menu will not have the desktop
159 // menu options (autohide, shelf position, and wallpaper picker).
160 ASSERT_EQ(0, menu.GetItemCount());
161
162 // Add some custom items.
163 menu.AddItem(203, base::ASCIIToUTF16("item"));
164 menu.AddCheckItem(107, base::ASCIIToUTF16("check"));
165 menu.AddRadioItem(101, base::ASCIIToUTF16("radio"), 0);
166 ui::SimpleMenuModel submenu(nullptr);
167 menu.AddSubMenu(55, base::ASCIIToUTF16("submenu"), &submenu);
168
169 // Ensure the menu contents match the items above.
170 ASSERT_EQ(4, menu.GetItemCount());
171 EXPECT_EQ(ui::MenuModel::TYPE_COMMAND, menu.GetTypeAt(0));
172 EXPECT_EQ(ui::MenuModel::TYPE_CHECK, menu.GetTypeAt(1));
173 EXPECT_EQ(ui::MenuModel::TYPE_RADIO, menu.GetTypeAt(2));
174 EXPECT_EQ(ui::MenuModel::TYPE_SUBMENU, menu.GetTypeAt(3));
175
176 // Invoking a custom item should execute the command id on the delegate.
177 menu.ActivatedAt(1);
178 EXPECT_EQ(107, delegate.last_executed_command());
179 }
180
181 // Tests fullscreen's per-display removal of "Autohide shelf": crbug.com/496681
TEST_F(ShelfContextMenuModelTest,AutohideShelfOptionOnExternalDisplay)182 TEST_F(ShelfContextMenuModelTest, AutohideShelfOptionOnExternalDisplay) {
183 UpdateDisplay("940x550,940x550");
184 int64_t primary_id = GetPrimaryDisplay().id();
185 int64_t secondary_id = GetSecondaryDisplay().id();
186
187 // Create a normal window on the primary display.
188 std::unique_ptr<views::Widget> widget = CreateTestWidget();
189 widget->Show();
190 widget->SetFullscreen(true);
191
192 ShelfContextMenuModel primary_menu(nullptr, primary_id);
193 ShelfContextMenuModel secondary_menu(nullptr, secondary_id);
194 EXPECT_EQ(-1, primary_menu.GetIndexOfCommandId(CommandId::MENU_AUTO_HIDE));
195 EXPECT_NE(-1, secondary_menu.GetIndexOfCommandId(CommandId::MENU_AUTO_HIDE));
196 }
197
198 // Tests that the autohide and alignment menu options are not included in tablet
199 // mode.
TEST_F(ShelfContextMenuModelTest,ExcludeClamshellOptionsOnTabletMode)200 TEST_F(ShelfContextMenuModelTest, ExcludeClamshellOptionsOnTabletMode) {
201 TabletModeController* tablet_mode_controller =
202 Shell::Get()->tablet_mode_controller();
203 int64_t primary_id = GetPrimaryDisplay().id();
204
205 // In tablet mode, the wallpaper picker and auto-hide should be the only two
206 // options because other options are disabled.
207 tablet_mode_controller->SetEnabledForTest(true);
208 ShelfContextMenuModel menu1(nullptr, primary_id);
209 EXPECT_EQ(2, menu1.GetItemCount());
210 EXPECT_EQ(ShelfContextMenuModel::MENU_AUTO_HIDE, menu1.GetCommandIdAt(0));
211 EXPECT_EQ(ShelfContextMenuModel::MENU_CHANGE_WALLPAPER,
212 menu1.GetCommandIdAt(1));
213
214 // Test that a menu shown out of tablet mode includes all three options:
215 // MENU_AUTO_HIDE, MENU_ALIGNMENT_MENU, and MENU_CHANGE_WALLPAPER.
216 tablet_mode_controller->SetEnabledForTest(false);
217 ShelfContextMenuModel menu2(nullptr, primary_id);
218 EXPECT_EQ(3, menu2.GetItemCount());
219
220 // Test the auto hide option.
221 EXPECT_EQ(ShelfContextMenuModel::MENU_AUTO_HIDE, menu2.GetCommandIdAt(0));
222 EXPECT_TRUE(menu2.IsEnabledAt(0));
223
224 // Test the shelf alignment menu option.
225 EXPECT_EQ(ShelfContextMenuModel::MENU_ALIGNMENT_MENU,
226 menu2.GetCommandIdAt(1));
227 EXPECT_TRUE(menu2.IsEnabledAt(1));
228
229 // Test the shelf alignment submenu.
230 ui::MenuModel* submenu = menu2.GetSubmenuModelAt(1);
231 EXPECT_EQ(ShelfContextMenuModel::MENU_ALIGNMENT_LEFT,
232 submenu->GetCommandIdAt(0));
233 EXPECT_TRUE(submenu->IsEnabledAt(0));
234
235 EXPECT_EQ(ShelfContextMenuModel::MENU_ALIGNMENT_BOTTOM,
236 submenu->GetCommandIdAt(1));
237 EXPECT_TRUE(submenu->IsEnabledAt(1));
238
239 EXPECT_EQ(ShelfContextMenuModel::MENU_ALIGNMENT_RIGHT,
240 submenu->GetCommandIdAt(2));
241 EXPECT_TRUE(submenu->IsEnabledAt(2));
242
243 // Test the wallpaper picker option.
244 EXPECT_EQ(ShelfContextMenuModel::MENU_CHANGE_WALLPAPER,
245 menu2.GetCommandIdAt(2));
246 EXPECT_TRUE(menu2.IsEnabledAt(2));
247 }
248
TEST_F(ShelfContextMenuModelTest,CommandIdsMatchEnumsForHistograms)249 TEST_F(ShelfContextMenuModelTest, CommandIdsMatchEnumsForHistograms) {
250 // Tests that CommandId enums are not changed as the values are used in
251 // histograms.
252 EXPECT_EQ(500, ShelfContextMenuModel::MENU_AUTO_HIDE);
253 EXPECT_EQ(501, ShelfContextMenuModel::MENU_ALIGNMENT_MENU);
254 EXPECT_EQ(502, ShelfContextMenuModel::MENU_ALIGNMENT_LEFT);
255 EXPECT_EQ(503, ShelfContextMenuModel::MENU_ALIGNMENT_RIGHT);
256 EXPECT_EQ(504, ShelfContextMenuModel::MENU_ALIGNMENT_BOTTOM);
257 EXPECT_EQ(505, ShelfContextMenuModel::MENU_CHANGE_WALLPAPER);
258 }
259
TEST_F(ShelfContextMenuModelTest,ShelfContextMenuOptions)260 TEST_F(ShelfContextMenuModelTest, ShelfContextMenuOptions) {
261 // Tests that there are exactly 3 shelf context menu options. If you're adding
262 // a context menu option ensure that you have added the enum to
263 // tools/metrics/enums.xml and that you haven't modified the order of the
264 // existing enums.
265 ShelfContextMenuModel menu(nullptr, GetPrimaryDisplay().id());
266 EXPECT_EQ(3, menu.GetItemCount());
267 }
268
TEST_F(ShelfContextMenuModelTest,NotificationContainerEnabled)269 TEST_F(ShelfContextMenuModelTest, NotificationContainerEnabled) {
270 // Tests that NOTIFICATION_CONTAINER is enabled. This ensures that the
271 // container is able to handle gesture events.
272 ShelfContextMenuModel menu(nullptr, GetPrimaryDisplay().id());
273 menu.AddItem(NOTIFICATION_CONTAINER, base::string16());
274
275 EXPECT_TRUE(menu.IsCommandIdEnabled(NOTIFICATION_CONTAINER));
276 }
277
278 } // namespace
279 } // namespace ash
280