1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/ui/browser_command_controller.h"
6 
7 #include "base/command_line.h"
8 #include "base/stl_util.h"
9 #include "build/branding_buildflags.h"
10 #include "build/build_config.h"
11 #include "chrome/app/chrome_command_ids.h"
12 #include "chrome/browser/browser_process.h"
13 #include "chrome/browser/command_updater.h"
14 #include "chrome/browser/prefs/incognito_mode_prefs.h"
15 #include "chrome/browser/profiles/profile_manager.h"
16 #include "chrome/browser/profiles/profiles_state.h"
17 #include "chrome/browser/ui/browser.h"
18 #include "chrome/browser/ui/browser_commands.h"
19 #include "chrome/browser/ui/browser_window_state.h"
20 #include "chrome/browser/ui/exclusive_access/exclusive_access_context.h"
21 #include "chrome/browser/ui/tabs/tab_strip_model.h"
22 #include "chrome/common/chrome_switches.h"
23 #include "chrome/common/pref_names.h"
24 #include "chrome/test/base/browser_with_test_window_test.h"
25 #include "chrome/test/base/test_browser_window.h"
26 #include "chrome/test/base/testing_browser_process.h"
27 #include "chrome/test/base/testing_profile.h"
28 #include "chrome/test/base/testing_profile_manager.h"
29 #include "components/signin/public/base/signin_pref_names.h"
30 #include "content/public/browser/native_web_keyboard_event.h"
31 #include "ui/events/keycodes/dom/dom_code.h"
32 #include "ui/events/keycodes/keyboard_codes.h"
33 
34 typedef BrowserWithTestWindowTest BrowserCommandControllerTest;
35 
36 class GuestBrowserCommandControllerTest
37     : public BrowserWithTestWindowTest,
38       public testing::WithParamInterface<bool> {
39  public:
GuestBrowserCommandControllerTest()40   GuestBrowserCommandControllerTest() : is_ephemeral_(GetParam()) {
41     // Change the value if Ephemeral is not supported.
42     is_ephemeral_ &=
43         TestingProfile::SetScopedFeatureListForEphemeralGuestProfiles(
44             scoped_feature_list_, is_ephemeral_);
45   }
46 
is_ephemeral() const47   bool is_ephemeral() const { return is_ephemeral_; }
48 
49  private:
50   bool is_ephemeral_;
51   base::test::ScopedFeatureList scoped_feature_list_;
52 };
53 
TEST_F(BrowserCommandControllerTest,IsReservedCommandOrKey)54 TEST_F(BrowserCommandControllerTest, IsReservedCommandOrKey) {
55 #if defined(OS_CHROMEOS)
56   // F1-3 keys are reserved Chrome accelerators on Chrome OS.
57   EXPECT_TRUE(browser()->command_controller()->IsReservedCommandOrKey(
58       IDC_BACK, content::NativeWebKeyboardEvent(
59                     ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_BROWSER_BACK,
60                                  ui::DomCode::BROWSER_BACK, 0))));
61   EXPECT_TRUE(browser()->command_controller()->IsReservedCommandOrKey(
62       IDC_FORWARD, content::NativeWebKeyboardEvent(ui::KeyEvent(
63                        ui::ET_KEY_PRESSED, ui::VKEY_BROWSER_FORWARD,
64                        ui::DomCode::BROWSER_FORWARD, 0))));
65   EXPECT_TRUE(browser()->command_controller()->IsReservedCommandOrKey(
66       IDC_RELOAD, content::NativeWebKeyboardEvent(
67                       ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_BROWSER_REFRESH,
68                                    ui::DomCode::BROWSER_REFRESH, 0))));
69 
70   // When there are modifier keys pressed, don't reserve.
71   EXPECT_FALSE(browser()->command_controller()->IsReservedCommandOrKey(
72       IDC_RELOAD_BYPASSING_CACHE, content::NativeWebKeyboardEvent(ui::KeyEvent(
73                                       ui::ET_KEY_PRESSED, ui::VKEY_F3,
74                                       ui::DomCode::F3, ui::EF_SHIFT_DOWN))));
75   EXPECT_FALSE(browser()->command_controller()->IsReservedCommandOrKey(
76       IDC_RELOAD_BYPASSING_CACHE, content::NativeWebKeyboardEvent(ui::KeyEvent(
77                                       ui::ET_KEY_PRESSED, ui::VKEY_F3,
78                                       ui::DomCode::F3, ui::EF_CONTROL_DOWN))));
79   EXPECT_FALSE(browser()->command_controller()->IsReservedCommandOrKey(
80       IDC_FULLSCREEN, content::NativeWebKeyboardEvent(
81                           ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_F4,
82                                        ui::DomCode::F4, ui::EF_SHIFT_DOWN))));
83 
84   // F4-10 keys are not reserved since they are Ash accelerators.
85   EXPECT_FALSE(browser()->command_controller()->IsReservedCommandOrKey(
86       -1, content::NativeWebKeyboardEvent(ui::KeyEvent(
87               ui::ET_KEY_PRESSED, ui::VKEY_F4, ui::DomCode::F4, 0))));
88   EXPECT_FALSE(browser()->command_controller()->IsReservedCommandOrKey(
89       -1, content::NativeWebKeyboardEvent(ui::KeyEvent(
90               ui::ET_KEY_PRESSED, ui::VKEY_F5, ui::DomCode::F5, 0))));
91   EXPECT_FALSE(browser()->command_controller()->IsReservedCommandOrKey(
92       -1, content::NativeWebKeyboardEvent(ui::KeyEvent(
93               ui::ET_KEY_PRESSED, ui::VKEY_F6, ui::DomCode::F6, 0))));
94   EXPECT_FALSE(browser()->command_controller()->IsReservedCommandOrKey(
95       -1, content::NativeWebKeyboardEvent(ui::KeyEvent(
96               ui::ET_KEY_PRESSED, ui::VKEY_F7, ui::DomCode::F7, 0))));
97   EXPECT_FALSE(browser()->command_controller()->IsReservedCommandOrKey(
98       -1, content::NativeWebKeyboardEvent(ui::KeyEvent(
99               ui::ET_KEY_PRESSED, ui::VKEY_F8, ui::DomCode::F8, 0))));
100   EXPECT_FALSE(browser()->command_controller()->IsReservedCommandOrKey(
101       -1, content::NativeWebKeyboardEvent(ui::KeyEvent(
102               ui::ET_KEY_PRESSED, ui::VKEY_F9, ui::DomCode::F9, 0))));
103   EXPECT_FALSE(browser()->command_controller()->IsReservedCommandOrKey(
104       -1, content::NativeWebKeyboardEvent(ui::KeyEvent(
105               ui::ET_KEY_PRESSED, ui::VKEY_F10, ui::DomCode::F10, 0))));
106 
107   // Shift+Control+Alt+F3 is also an Ash accelerator. Don't reserve it.
108   EXPECT_FALSE(browser()->command_controller()->IsReservedCommandOrKey(
109       -1, content::NativeWebKeyboardEvent(ui::KeyEvent(
110               ui::ET_KEY_PRESSED, ui::VKEY_F3, ui::DomCode::F3,
111               ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN))));
112 #endif  // OS_CHROMEOS
113 
114 #if defined(USE_AURA)
115   // Ctrl+n, Ctrl+w are reserved while Ctrl+f is not.
116 
117   // The content::NativeWebKeyboardEvent constructor is available only when
118   // USE_AURA is #defined.
119   EXPECT_TRUE(browser()->command_controller()->IsReservedCommandOrKey(
120       IDC_NEW_WINDOW, content::NativeWebKeyboardEvent(ui::KeyEvent(
121                           ui::ET_KEY_PRESSED, ui::VKEY_N, ui::DomCode::US_N,
122                           ui::EF_CONTROL_DOWN))));
123   EXPECT_TRUE(browser()->command_controller()->IsReservedCommandOrKey(
124       IDC_CLOSE_TAB, content::NativeWebKeyboardEvent(ui::KeyEvent(
125                          ui::ET_KEY_PRESSED, ui::VKEY_W, ui::DomCode::US_W,
126                          ui::EF_CONTROL_DOWN))));
127   EXPECT_FALSE(browser()->command_controller()->IsReservedCommandOrKey(
128       IDC_FIND, content::NativeWebKeyboardEvent(
129                     ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_F,
130                                  ui::DomCode::US_F, ui::EF_CONTROL_DOWN))));
131 #endif  // USE_AURA
132 }
133 
TEST_F(BrowserCommandControllerTest,IsReservedCommandOrKeyIsApp)134 TEST_F(BrowserCommandControllerTest, IsReservedCommandOrKeyIsApp) {
135   Browser::CreateParams params = Browser::CreateParams::CreateForApp(
136       "app",
137       /*trusted_source=*/true, browser()->window()->GetBounds(), profile(),
138       /*user_gesture=*/true);
139   params.window = browser()->window();
140   set_browser(Browser::Create(params));
141 
142   ASSERT_TRUE(browser()->is_type_app());
143 
144   // When is_type_app(), no keys are reserved.
145 #if defined(OS_CHROMEOS)
146   EXPECT_FALSE(browser()->command_controller()->IsReservedCommandOrKey(
147       IDC_BACK, content::NativeWebKeyboardEvent(ui::KeyEvent(
148                     ui::ET_KEY_PRESSED, ui::VKEY_F1, ui::DomCode::F1, 0))));
149   EXPECT_FALSE(browser()->command_controller()->IsReservedCommandOrKey(
150       IDC_FORWARD, content::NativeWebKeyboardEvent(ui::KeyEvent(
151                        ui::ET_KEY_PRESSED, ui::VKEY_F2, ui::DomCode::F2, 0))));
152   EXPECT_FALSE(browser()->command_controller()->IsReservedCommandOrKey(
153       IDC_RELOAD, content::NativeWebKeyboardEvent(ui::KeyEvent(
154                       ui::ET_KEY_PRESSED, ui::VKEY_F3, ui::DomCode::F3, 0))));
155   EXPECT_FALSE(browser()->command_controller()->IsReservedCommandOrKey(
156       -1, content::NativeWebKeyboardEvent(ui::KeyEvent(
157               ui::ET_KEY_PRESSED, ui::VKEY_F4, ui::DomCode::F4, 0))));
158 #endif  // OS_CHROMEOS
159 
160 #if defined(USE_AURA)
161   // The content::NativeWebKeyboardEvent constructor is available only when
162   // USE_AURA is #defined.
163   EXPECT_FALSE(browser()->command_controller()->IsReservedCommandOrKey(
164       IDC_NEW_WINDOW, content::NativeWebKeyboardEvent(ui::KeyEvent(
165                           ui::ET_KEY_PRESSED, ui::VKEY_N, ui::DomCode::US_N,
166                           ui::EF_CONTROL_DOWN))));
167   EXPECT_FALSE(browser()->command_controller()->IsReservedCommandOrKey(
168       IDC_CLOSE_TAB, content::NativeWebKeyboardEvent(ui::KeyEvent(
169                          ui::ET_KEY_PRESSED, ui::VKEY_W, ui::DomCode::US_W,
170                          ui::EF_CONTROL_DOWN))));
171   EXPECT_FALSE(browser()->command_controller()->IsReservedCommandOrKey(
172       IDC_FIND, content::NativeWebKeyboardEvent(
173                     ui::KeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_F,
174                                  ui::DomCode::US_F, ui::EF_CONTROL_DOWN))));
175 #endif  // USE_AURA
176 }
177 
TEST_P(GuestBrowserCommandControllerTest,IncognitoCommands)178 TEST_P(GuestBrowserCommandControllerTest, IncognitoCommands) {
179   EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_OPTIONS));
180   EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_IMPORT_SETTINGS));
181   EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_SHOW_SIGNIN));
182 
183   TestingProfile* testprofile = browser()->profile()->AsTestingProfile();
184   EXPECT_TRUE(testprofile);
185   testprofile->SetGuestSession(true);
186   chrome::BrowserCommandController ::
187       UpdateSharedCommandsForIncognitoAvailability(
188           browser()->command_controller(), testprofile);
189   EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_OPTIONS));
190   EXPECT_FALSE(chrome::IsCommandEnabled(browser(), IDC_IMPORT_SETTINGS));
191   EXPECT_FALSE(chrome::IsCommandEnabled(browser(), IDC_SHOW_SIGNIN));
192 
193   testprofile->SetGuestSession(false);
194   IncognitoModePrefs::SetAvailability(browser()->profile()->GetPrefs(),
195                                       IncognitoModePrefs::FORCED);
196   chrome::BrowserCommandController ::
197       UpdateSharedCommandsForIncognitoAvailability(
198           browser()->command_controller(), testprofile);
199   EXPECT_FALSE(chrome::IsCommandEnabled(browser(), IDC_OPTIONS));
200   EXPECT_FALSE(chrome::IsCommandEnabled(browser(), IDC_IMPORT_SETTINGS));
201   EXPECT_FALSE(chrome::IsCommandEnabled(browser(), IDC_SHOW_SIGNIN));
202 }
203 
TEST_F(BrowserCommandControllerTest,AppFullScreen)204 TEST_F(BrowserCommandControllerTest, AppFullScreen) {
205   // Enable for tabbed browser.
206   EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_FULLSCREEN));
207 
208   // Enabled for app windows.
209   Browser::CreateParams params = Browser::CreateParams::CreateForApp(
210       "app",
211       /*trusted_source=*/true, browser()->window()->GetBounds(), profile(),
212       /*user_gesture=*/true);
213   params.window = browser()->window();
214   set_browser(Browser::Create(params));
215   ASSERT_TRUE(browser()->is_type_app());
216   browser()->command_controller()->FullscreenStateChanged();
217   EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_FULLSCREEN));
218 }
219 
TEST_F(BrowserCommandControllerTest,AvatarAcceleratorEnabledOnDesktop)220 TEST_F(BrowserCommandControllerTest, AvatarAcceleratorEnabledOnDesktop) {
221   if (!profiles::IsMultipleProfilesEnabled())
222     return;
223 
224   TestingProfileManager* testing_profile_manager = profile_manager();
225   ProfileManager* profile_manager = testing_profile_manager->profile_manager();
226   chrome::BrowserCommandController command_controller(browser());
227   const CommandUpdater* command_updater = &command_controller;
228 
229   bool enabled = true;
230   size_t profiles_count = 1U;
231 #if defined(OS_CHROMEOS)
232   // Chrome OS uses system tray menu to handle multi-profiles.
233   enabled = false;
234   profiles_count = 2U;
235 #endif
236 
237   ASSERT_EQ(profiles_count, profile_manager->GetNumberOfProfiles());
238   EXPECT_EQ(enabled, command_updater->IsCommandEnabled(IDC_SHOW_AVATAR_MENU));
239 
240   testing_profile_manager->CreateTestingProfile("p2");
241   profiles_count++;
242   ASSERT_EQ(profiles_count, profile_manager->GetNumberOfProfiles());
243   EXPECT_EQ(enabled, command_updater->IsCommandEnabled(IDC_SHOW_AVATAR_MENU));
244 
245   testing_profile_manager->DeleteTestingProfile("p2");
246   profiles_count--;
247   ASSERT_EQ(profiles_count, profile_manager->GetNumberOfProfiles());
248   EXPECT_EQ(enabled, command_updater->IsCommandEnabled(IDC_SHOW_AVATAR_MENU));
249 }
250 
TEST_F(BrowserCommandControllerTest,AvatarMenuAlwaysEnabledInIncognitoMode)251 TEST_F(BrowserCommandControllerTest, AvatarMenuAlwaysEnabledInIncognitoMode) {
252   // Set up a profile with an off the record profile.
253   TestingProfile::Builder normal_builder;
254   std::unique_ptr<TestingProfile> original_profile = normal_builder.Build();
255 
256   // Create a new browser based on the off the record profile.
257   Browser::CreateParams profile_params(original_profile->GetPrimaryOTRProfile(),
258                                        true);
259   std::unique_ptr<Browser> otr_browser(
260       CreateBrowserWithTestWindowForParams(profile_params));
261 
262   chrome::BrowserCommandController command_controller(otr_browser.get());
263   const CommandUpdater* command_updater = &command_controller;
264 
265   // The avatar menu should be enabled.
266   EXPECT_TRUE(command_updater->IsCommandEnabled(IDC_SHOW_AVATAR_MENU));
267   // The command line is reset at the end of every test by the test suite.
268 }
269 
270 //////////////////////////////////////////////////////////////////////////////
271 class BrowserCommandControllerFullscreenTest;
272 
273 // A test browser window that can toggle fullscreen state.
274 class FullscreenTestBrowserWindow : public TestBrowserWindow,
275                                     ExclusiveAccessContext {
276  public:
FullscreenTestBrowserWindow(BrowserCommandControllerFullscreenTest * test_browser)277   FullscreenTestBrowserWindow(
278       BrowserCommandControllerFullscreenTest* test_browser)
279       : fullscreen_(false),
280         toolbar_showing_(false),
281         test_browser_(test_browser) {}
282 
~FullscreenTestBrowserWindow()283   ~FullscreenTestBrowserWindow() override {}
284 
285   // TestBrowserWindow overrides:
ShouldHideUIForFullscreen() const286   bool ShouldHideUIForFullscreen() const override { return fullscreen_; }
IsFullscreen() const287   bool IsFullscreen() const override { return fullscreen_; }
EnterFullscreen(const GURL & url,ExclusiveAccessBubbleType type,int64_t display_id)288   void EnterFullscreen(const GURL& url,
289                        ExclusiveAccessBubbleType type,
290                        int64_t display_id) override {
291     fullscreen_ = true;
292   }
ExitFullscreen()293   void ExitFullscreen() override { fullscreen_ = false; }
IsToolbarShowing() const294   bool IsToolbarShowing() const override { return toolbar_showing_; }
295 
GetExclusiveAccessContext()296   ExclusiveAccessContext* GetExclusiveAccessContext() override { return this; }
297 
298   // Exclusive access interface:
299   Profile* GetProfile() override;
300   content::WebContents* GetActiveWebContents() override;
UpdateExclusiveAccessExitBubbleContent(const GURL & url,ExclusiveAccessBubbleType bubble_type,ExclusiveAccessBubbleHideCallback bubble_first_hide_callback,bool force_update)301   void UpdateExclusiveAccessExitBubbleContent(
302       const GURL& url,
303       ExclusiveAccessBubbleType bubble_type,
304       ExclusiveAccessBubbleHideCallback bubble_first_hide_callback,
305       bool force_update) override {}
OnExclusiveAccessUserInput()306   void OnExclusiveAccessUserInput() override {}
CanUserExitFullscreen() const307   bool CanUserExitFullscreen() const override { return true; }
308 
set_toolbar_showing(bool showing)309   void set_toolbar_showing(bool showing) { toolbar_showing_ = showing; }
310 
311  private:
312   bool fullscreen_;
313   bool toolbar_showing_;
314   BrowserCommandControllerFullscreenTest* test_browser_;
315 
316   DISALLOW_COPY_AND_ASSIGN(FullscreenTestBrowserWindow);
317 };
318 
319 // Test that uses FullscreenTestBrowserWindow for its window.
320 class BrowserCommandControllerFullscreenTest
321     : public BrowserWithTestWindowTest,
322       public testing::WithParamInterface<bool> {
323  public:
BrowserCommandControllerFullscreenTest()324   BrowserCommandControllerFullscreenTest() {
325     TestingProfile::SetScopedFeatureListForEphemeralGuestProfiles(
326         scoped_feature_list_, GetParam());
327   }
328   ~BrowserCommandControllerFullscreenTest() override = default;
329 
GetBrowser()330   Browser* GetBrowser() { return BrowserWithTestWindowTest::browser(); }
331 
332   // BrowserWithTestWindowTest overrides:
CreateBrowserWindow()333   std::unique_ptr<BrowserWindow> CreateBrowserWindow() override {
334     return std::make_unique<FullscreenTestBrowserWindow>(this);
335   }
336 
337  private:
338   base::test::ScopedFeatureList scoped_feature_list_;
339   DISALLOW_COPY_AND_ASSIGN(BrowserCommandControllerFullscreenTest);
340 };
341 
GetProfile()342 Profile* FullscreenTestBrowserWindow::GetProfile() {
343   return test_browser_->GetBrowser()->profile();
344 }
345 
GetActiveWebContents()346 content::WebContents* FullscreenTestBrowserWindow::GetActiveWebContents() {
347   return test_browser_->GetBrowser()->tab_strip_model()->GetActiveWebContents();
348 }
349 
TEST_P(BrowserCommandControllerFullscreenTest,UpdateCommandsForFullscreenMode)350 TEST_P(BrowserCommandControllerFullscreenTest,
351        UpdateCommandsForFullscreenMode) {
352   struct {
353     int command_id;
354     // Whether the command is enabled in tab mode.
355     bool enabled_in_tab;
356     // Whether the keyboard shortcut is reserved in tab mode.
357     bool reserved_in_tab;
358     // Whether the command is enabled in fullscreen mode.
359     bool enabled_in_fullscreen;
360     // Whether the keyboard shortcut is reserved in fullscreen mode.
361     bool reserved_in_fullscreen;
362   } commands[] = {
363     // 1. Most commands are disabled in fullscreen.
364     // 2. In fullscreen, only the exit fullscreen commands are reserved. All
365     // other shortcuts should be delivered to the web page. See
366     // http://crbug.com/680809.
367 
368     //         Command ID        |      tab mode      |      fullscreen     |
369     //                           | enabled | reserved | enabled  | reserved |
370     // clang-format off
371     { IDC_OPEN_CURRENT_URL,        true,     false,     false,     false    },
372     { IDC_FOCUS_TOOLBAR,           true,     false,     false,     false    },
373     { IDC_FOCUS_LOCATION,          true,     false,     false,     false    },
374     { IDC_FOCUS_SEARCH,            true,     false,     false,     false    },
375     { IDC_FOCUS_MENU_BAR,          true,     false,     false,     false    },
376     { IDC_FOCUS_NEXT_PANE,         true,     false,     false,     false    },
377     { IDC_FOCUS_PREVIOUS_PANE,     true,     false,     false,     false    },
378     { IDC_FOCUS_BOOKMARKS,         true,     false,     false,     false    },
379     { IDC_DEVELOPER_MENU,          true,     false,     false,     false    },
380 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
381     { IDC_FEEDBACK,                true,     false,     false,     false    },
382 #endif
383     { IDC_OPTIONS,                 true,     false,     false,     false    },
384     { IDC_IMPORT_SETTINGS,         true,     false,     false,     false    },
385     { IDC_EDIT_SEARCH_ENGINES,     true,     false,     false,     false    },
386     { IDC_VIEW_PASSWORDS,          true,     false,     false,     false    },
387     { IDC_ABOUT,                   true,     false,     false,     false    },
388     { IDC_SHOW_APP_MENU,           true,     false,     false,     false    },
389     { IDC_SEND_TAB_TO_SELF,        true,     false,     false,     false    },
390     { IDC_SEND_TAB_TO_SELF_SINGLE_TARGET,
391                                    true,     false,     false,     false    },
392     { IDC_FULLSCREEN,              true,     false,     true,      true     },
393     { IDC_CLOSE_TAB,               true,     true,      true,      false    },
394     { IDC_CLOSE_WINDOW,            true,     true,      true,      false    },
395     { IDC_NEW_INCOGNITO_WINDOW,    true,     true,      true,      false    },
396     { IDC_NEW_TAB,                 true,     true,      true,      false    },
397     { IDC_NEW_WINDOW,              true,     true,      true,      false    },
398     { IDC_SELECT_NEXT_TAB,         true,     true,      true,      false    },
399     { IDC_SELECT_PREVIOUS_TAB,     true,     true,      true,      false    },
400     { IDC_EXIT,                    true,     true,      true,      true     },
401     { IDC_SHOW_AS_TAB,             false,    false,     false,     false    },
402     { IDC_SHOW_SIGNIN,             true,     false,      true,      false   },
403     // clang-format on
404   };
405   const content::NativeWebKeyboardEvent key_event(
406       blink::WebInputEvent::Type::kUndefined, 0,
407       blink::WebInputEvent::GetStaticTimeStampForTests());
408   // Defaults for a tabbed browser.
409   for (size_t i = 0; i < base::size(commands); i++) {
410     SCOPED_TRACE(commands[i].command_id);
411     EXPECT_EQ(chrome::IsCommandEnabled(browser(), commands[i].command_id),
412               commands[i].enabled_in_tab);
413     EXPECT_EQ(browser()->command_controller()->IsReservedCommandOrKey(
414                   commands[i].command_id, key_event),
415               commands[i].reserved_in_tab);
416   }
417 
418   // Simulate going fullscreen.
419   chrome::ToggleFullscreenMode(browser());
420   ASSERT_TRUE(browser()->window()->IsFullscreen());
421   browser()->command_controller()->FullscreenStateChanged();
422 
423   // By default, in fullscreen mode, the toolbar should be hidden; and all
424   // platforms behave similarly.
425   EXPECT_FALSE(window()->IsToolbarShowing());
426   for (size_t i = 0; i < base::size(commands); i++) {
427     SCOPED_TRACE(commands[i].command_id);
428     EXPECT_EQ(chrome::IsCommandEnabled(browser(), commands[i].command_id),
429               commands[i].enabled_in_fullscreen);
430     EXPECT_EQ(browser()->command_controller()->IsReservedCommandOrKey(
431                   commands[i].command_id, key_event),
432               commands[i].reserved_in_fullscreen);
433   }
434 
435 #if defined(OS_MAC)
436   // When the toolbar is showing, commands should be reserved as if the content
437   // were in a tab; IDC_FULLSCREEN should also be reserved.
438   static_cast<FullscreenTestBrowserWindow*>(window())->set_toolbar_showing(
439       true);
440   EXPECT_TRUE(browser()->command_controller()->IsReservedCommandOrKey(
441       IDC_FULLSCREEN, key_event));
442   for (size_t i = 0; i < base::size(commands); i++) {
443     if (commands[i].command_id != IDC_FULLSCREEN) {
444       SCOPED_TRACE(commands[i].command_id);
445       EXPECT_EQ(browser()->command_controller()->IsReservedCommandOrKey(
446                     commands[i].command_id, key_event),
447                 commands[i].reserved_in_tab);
448     }
449   }
450   // Return to default state.
451   static_cast<FullscreenTestBrowserWindow*>(window())->set_toolbar_showing(
452       false);
453 #endif
454 
455   // Exit fullscreen.
456   chrome::ToggleFullscreenMode(browser());
457   ASSERT_FALSE(browser()->window()->IsFullscreen());
458   browser()->command_controller()->FullscreenStateChanged();
459 
460   for (size_t i = 0; i < base::size(commands); i++) {
461     SCOPED_TRACE(commands[i].command_id);
462     EXPECT_EQ(chrome::IsCommandEnabled(browser(), commands[i].command_id),
463               commands[i].enabled_in_tab);
464     EXPECT_EQ(browser()->command_controller()->IsReservedCommandOrKey(
465                   commands[i].command_id, key_event),
466               commands[i].reserved_in_tab);
467   }
468 
469   // Guest Profiles disallow some options.
470   TestingProfile* testprofile = browser()->profile()->AsTestingProfile();
471   EXPECT_TRUE(testprofile);
472   testprofile->SetGuestSession(true);
473 
474   browser()->command_controller()->FullscreenStateChanged();
475   EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_OPTIONS));
476   EXPECT_FALSE(chrome::IsCommandEnabled(browser(), IDC_IMPORT_SETTINGS));
477 }
478 
479 INSTANTIATE_TEST_SUITE_P(AllGuestTypes,
480                          BrowserCommandControllerFullscreenTest,
481                          /*is_ephemeral=*/testing::Bool());
482 
483 // Ensure that the logic for enabling IDC_OPTIONS is consistent, regardless of
484 // the order of entering fullscreen and forced incognito modes. See
485 // http://crbug.com/694331.
TEST_P(GuestBrowserCommandControllerTest,OptionsConsistency)486 TEST_P(GuestBrowserCommandControllerTest, OptionsConsistency) {
487   TestingProfile* profile = browser()->profile()->AsTestingProfile();
488   // Setup guest session.
489   profile->SetGuestSession(true);
490   // Setup forced incognito mode.
491   IncognitoModePrefs::SetAvailability(browser()->profile()->GetPrefs(),
492                                       IncognitoModePrefs::FORCED);
493   EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_OPTIONS));
494   // Enter fullscreen.
495   browser()->command_controller()->FullscreenStateChanged();
496   EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_OPTIONS));
497   // Exit fullscreen
498   browser()->command_controller()->FullscreenStateChanged();
499   EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_OPTIONS));
500   // Reenter incognito mode, this should trigger
501   // UpdateSharedCommandsForIncognitoAvailability() again.
502   IncognitoModePrefs::SetAvailability(browser()->profile()->GetPrefs(),
503                                       IncognitoModePrefs::DISABLED);
504   IncognitoModePrefs::SetAvailability(browser()->profile()->GetPrefs(),
505                                       IncognitoModePrefs::FORCED);
506   EXPECT_TRUE(chrome::IsCommandEnabled(browser(), IDC_OPTIONS));
507 }
508 
TEST_F(BrowserCommandControllerTest,IncognitoModeOnSigninAllowedPrefChange)509 TEST_F(BrowserCommandControllerTest, IncognitoModeOnSigninAllowedPrefChange) {
510   // Set up a profile with an off the record profile.
511   std::unique_ptr<TestingProfile> profile1 = TestingProfile::Builder().Build();
512   Profile* profile2 = profile1->GetPrimaryOTRProfile();
513 
514   EXPECT_EQ(profile2->GetOriginalProfile(), profile1.get());
515 
516   // Create a new browser based on the off the record profile.
517   Browser::CreateParams profile_params(profile1->GetPrimaryOTRProfile(), true);
518   std::unique_ptr<Browser> browser2(
519       CreateBrowserWithTestWindowForParams(profile_params));
520 
521   chrome::BrowserCommandController command_controller(browser2.get());
522   const CommandUpdater* command_updater = &command_controller;
523 
524   // Check that the SYNC_SETUP command is updated on preference change.
525   EXPECT_TRUE(command_updater->IsCommandEnabled(IDC_SHOW_SIGNIN));
526   profile1->GetPrefs()->SetBoolean(prefs::kSigninAllowed, false);
527   EXPECT_FALSE(command_updater->IsCommandEnabled(IDC_SHOW_SIGNIN));
528 }
529 
TEST_F(BrowserCommandControllerTest,OnSigninAllowedPrefChange)530 TEST_F(BrowserCommandControllerTest, OnSigninAllowedPrefChange) {
531   chrome::BrowserCommandController command_controller(browser());
532   const CommandUpdater* command_updater = &command_controller;
533 
534   // Check that the SYNC_SETUP command is updated on preference change.
535   EXPECT_TRUE(command_updater->IsCommandEnabled(IDC_SHOW_SIGNIN));
536   profile()->GetPrefs()->SetBoolean(prefs::kSigninAllowed, false);
537   EXPECT_FALSE(command_updater->IsCommandEnabled(IDC_SHOW_SIGNIN));
538 }
539 
540 INSTANTIATE_TEST_SUITE_P(AllGuestTypes,
541                          GuestBrowserCommandControllerTest,
542                          /*is_ephemeral=*/testing::Bool());
543