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 <stddef.h>
8 
9 #include <string>
10 
11 #include "base/bind.h"
12 #include "base/command_line.h"
13 #include "base/debug/debugging_buildflags.h"
14 #include "base/debug/profiler.h"
15 #include "base/macros.h"
16 #include "base/metrics/user_metrics.h"
17 #include "base/stl_util.h"
18 #include "build/branding_buildflags.h"
19 #include "build/build_config.h"
20 #include "chrome/app/chrome_command_ids.h"
21 #include "chrome/browser/browser_process.h"
22 #include "chrome/browser/chrome_notification_types.h"
23 #include "chrome/browser/defaults.h"
24 #include "chrome/browser/devtools/devtools_window.h"
25 #include "chrome/browser/extensions/extension_service.h"
26 #include "chrome/browser/lifetime/application_lifetime.h"
27 #include "chrome/browser/prefs/incognito_mode_prefs.h"
28 #include "chrome/browser/profiles/profile.h"
29 #include "chrome/browser/profiles/profile_manager.h"
30 #include "chrome/browser/sessions/tab_restore_service_factory.h"
31 #include "chrome/browser/shell_integration.h"
32 #include "chrome/browser/signin/signin_promo.h"
33 #include "chrome/browser/sync/profile_sync_service_factory.h"
34 #include "chrome/browser/ui/apps/app_info_dialog.h"
35 #include "chrome/browser/ui/bookmarks/bookmark_tab_helper.h"
36 #include "chrome/browser/ui/browser.h"
37 #include "chrome/browser/ui/browser_commands.h"
38 #include "chrome/browser/ui/browser_finder.h"
39 #include "chrome/browser/ui/browser_window.h"
40 #include "chrome/browser/ui/chrome_pages.h"
41 #include "chrome/browser/ui/commander/commander.h"
42 #include "chrome/browser/ui/page_info/page_info_dialog.h"
43 #include "chrome/browser/ui/singleton_tabs.h"
44 #include "chrome/browser/ui/tabs/tab_strip_model.h"
45 #include "chrome/browser/ui/ui_features.h"
46 #include "chrome/browser/ui/web_applications/app_browser_controller.h"
47 #include "chrome/browser/ui/web_applications/web_app_dialog_utils.h"
48 #include "chrome/browser/ui/web_applications/web_app_launch_utils.h"
49 #include "chrome/browser/ui/webui/inspect_ui.h"
50 #include "chrome/common/content_restriction.h"
51 #include "chrome/common/pref_names.h"
52 #include "chrome/common/url_constants.h"
53 #include "components/bookmarks/common/bookmark_pref_names.h"
54 #include "components/dom_distiller/core/dom_distiller_features.h"
55 #include "components/prefs/pref_service.h"
56 #include "components/sessions/core/tab_restore_service.h"
57 #include "components/signin/public/base/signin_pref_names.h"
58 #include "content/public/browser/native_web_keyboard_event.h"
59 #include "content/public/browser/navigation_controller.h"
60 #include "content/public/browser/navigation_entry.h"
61 #include "content/public/browser/render_frame_host.h"
62 #include "content/public/browser/web_contents.h"
63 #include "content/public/browser/web_contents_observer.h"
64 #include "content/public/common/profiling.h"
65 #include "content/public/common/url_constants.h"
66 #include "extensions/browser/extension_system.h"
67 #include "printing/buildflags/buildflags.h"
68 #include "ui/events/keycodes/keyboard_codes.h"
69 
70 #if defined(OS_MAC)
71 #include "chrome/browser/ui/browser_commands_mac.h"
72 #endif
73 
74 #if defined(OS_WIN)
75 #include "base/win/windows_version.h"
76 #include "content/public/browser/gpu_data_manager.h"
77 #endif
78 
79 #if defined(OS_CHROMEOS)
80 #include "chrome/browser/platform_util.h"
81 #include "chrome/browser/ui/ash/multi_user/multi_user_context_menu.h"
82 #include "chrome/browser/ui/browser_commands_chromeos.h"
83 #include "components/session_manager/core/session_manager.h"
84 #endif
85 
86 #if (defined(OS_LINUX) && !defined(OS_CHROMEOS)) || defined(OS_BSD)
87 #include "ui/base/ime/linux/text_edit_key_bindings_delegate_auralinux.h"
88 #endif
89 
90 #if defined(USE_OZONE)
91 #include "ui/base/ui_base_features.h"
92 #include "ui/ozone/public/ozone_platform.h"
93 #endif
94 
95 using content::NavigationController;
96 using content::NavigationEntry;
97 using content::WebContents;
98 
99 namespace chrome {
100 
101 namespace {
102 
103 // Ensures that - if we have not popped up an infobar to prompt the user to e.g.
104 // reload the current page - that the content pane of the browser is refocused.
AppInfoDialogClosedCallback(content::WebContents * web_contents,views::Widget::ClosedReason closed_reason,bool reload_prompt)105 void AppInfoDialogClosedCallback(content::WebContents* web_contents,
106                                  views::Widget::ClosedReason closed_reason,
107                                  bool reload_prompt) {
108   if (reload_prompt)
109     return;
110 
111   // If the user clicked on something specific or focus was changed, don't
112   // override the focus.
113   if (closed_reason != views::Widget::ClosedReason::kEscKeyPressed &&
114       closed_reason != views::Widget::ClosedReason::kCloseButtonClicked) {
115     return;
116   }
117 
118   // Ensure that the web contents handle we have is still valid. It's possible
119   // (though unlikely) that either the browser or web contents has been pulled
120   // out from underneath us.
121   Browser* const browser = chrome::FindBrowserWithWebContents(web_contents);
122   if (!browser)
123     return;
124 
125   // We want to focus the active web contents, which again, might not be the
126   // original web contents (though it should be the vast majority of the time).
127   content::WebContents* const active_contents =
128       browser->tab_strip_model()->GetActiveWebContents();
129   if (active_contents)
130     active_contents->Focus();
131 }
132 
133 }  // namespace
134 
135 ///////////////////////////////////////////////////////////////////////////////
136 // BrowserCommandController, public:
137 
BrowserCommandController(Browser * browser)138 BrowserCommandController::BrowserCommandController(Browser* browser)
139     : browser_(browser), command_updater_(nullptr) {
140   browser_->tab_strip_model()->AddObserver(this);
141   PrefService* local_state = g_browser_process->local_state();
142   if (local_state) {
143     local_pref_registrar_.Init(local_state);
144     local_pref_registrar_.Add(
145         prefs::kAllowFileSelectionDialogs,
146         base::Bind(
147             &BrowserCommandController::UpdateCommandsForFileSelectionDialogs,
148             base::Unretained(this)));
149   }
150 
151   profile_pref_registrar_.Init(profile()->GetPrefs());
152   profile_pref_registrar_.Add(
153       prefs::kDevToolsAvailability,
154       base::Bind(&BrowserCommandController::UpdateCommandsForDevTools,
155                  base::Unretained(this)));
156   profile_pref_registrar_.Add(
157       bookmarks::prefs::kEditBookmarksEnabled,
158       base::Bind(&BrowserCommandController::UpdateCommandsForBookmarkEditing,
159                  base::Unretained(this)));
160   profile_pref_registrar_.Add(
161       bookmarks::prefs::kShowBookmarkBar,
162       base::Bind(&BrowserCommandController::UpdateCommandsForBookmarkBar,
163                  base::Unretained(this)));
164   profile_pref_registrar_.Add(
165       prefs::kIncognitoModeAvailability,
166       base::Bind(
167           &BrowserCommandController::UpdateCommandsForIncognitoAvailability,
168           base::Unretained(this)));
169   profile_pref_registrar_.Add(
170       prefs::kPrintingEnabled,
171       base::Bind(&BrowserCommandController::UpdatePrintingState,
172                  base::Unretained(this)));
173 #if !defined(OS_MAC)
174   profile_pref_registrar_.Add(
175       prefs::kFullscreenAllowed,
176       base::Bind(&BrowserCommandController::UpdateCommandsForFullscreenMode,
177                  base::Unretained(this)));
178 #endif
179   pref_signin_allowed_.Init(
180       prefs::kSigninAllowed, profile()->GetOriginalProfile()->GetPrefs(),
181       base::BindRepeating(&BrowserCommandController::OnSigninAllowedPrefChange,
182                           base::Unretained(this)));
183 
184   InitCommandState();
185 
186   sessions::TabRestoreService* tab_restore_service =
187       TabRestoreServiceFactory::GetForProfile(profile());
188   if (tab_restore_service) {
189     tab_restore_service->AddObserver(this);
190     if (!tab_restore_service->IsLoaded())
191       tab_restore_service->LoadTabsFromLastSession();
192   }
193 }
194 
~BrowserCommandController()195 BrowserCommandController::~BrowserCommandController() {
196   // TabRestoreService may have been shutdown by the time we get here. Don't
197   // trigger creating it.
198   sessions::TabRestoreService* tab_restore_service =
199       TabRestoreServiceFactory::GetForProfileIfExisting(profile());
200   if (tab_restore_service)
201     tab_restore_service->RemoveObserver(this);
202   profile_pref_registrar_.RemoveAll();
203   local_pref_registrar_.RemoveAll();
204   browser_->tab_strip_model()->RemoveObserver(this);
205 }
206 
IsReservedCommandOrKey(int command_id,const content::NativeWebKeyboardEvent & event)207 bool BrowserCommandController::IsReservedCommandOrKey(
208     int command_id,
209     const content::NativeWebKeyboardEvent& event) {
210   // In Apps mode, no keys are reserved.
211   if (browser_->is_type_app() || browser_->is_type_app_popup())
212     return false;
213 
214 #if defined(OS_CHROMEOS)
215   // On Chrome OS, the top row of keys are mapped to browser actions like
216   // back/forward or refresh. We don't want web pages to be able to change the
217   // behavior of these keys.  Ash handles F4 and up; this leaves us needing to
218   // reserve browser back/forward and refresh here.
219   ui::KeyboardCode key_code =
220       static_cast<ui::KeyboardCode>(event.windows_key_code);
221   if ((key_code == ui::VKEY_BROWSER_BACK && command_id == IDC_BACK) ||
222       (key_code == ui::VKEY_BROWSER_FORWARD && command_id == IDC_FORWARD) ||
223       (key_code == ui::VKEY_BROWSER_REFRESH && command_id == IDC_RELOAD)) {
224     return true;
225   }
226 #endif
227 
228   if (window()->IsFullscreen()) {
229     // In fullscreen, all commands except for IDC_FULLSCREEN and IDC_EXIT should
230     // be delivered to the web page. The intent to implement and ship can be
231     // found in http://crbug.com/680809.
232     const bool is_exit_fullscreen =
233         (command_id == IDC_EXIT || command_id == IDC_FULLSCREEN);
234 #if defined(OS_MAC)
235     // This behavior is different on Mac OS, which has a unique user-initiated
236     // full-screen mode. According to the discussion in http://crbug.com/702251,
237     // the commands should be reserved for browser-side handling if the browser
238     // window's toolbar is visible.
239     if (window()->IsToolbarShowing()) {
240       if (command_id == IDC_FULLSCREEN)
241         return true;
242     } else {
243       return is_exit_fullscreen;
244     }
245 #else
246     return is_exit_fullscreen;
247 #endif
248   }
249 
250 #if (defined(OS_LINUX) || defined(OS_BSD)) && !defined(OS_CHROMEOS)
251   // If this key was registered by the user as a content editing hotkey, then
252   // it is not reserved.
253   ui::TextEditKeyBindingsDelegateAuraLinux* delegate =
254       ui::GetTextEditKeyBindingsDelegate();
255   if (delegate && event.os_event && delegate->MatchEvent(*event.os_event, NULL))
256     return false;
257 #endif
258 
259   return command_id == IDC_CLOSE_TAB || command_id == IDC_CLOSE_WINDOW ||
260          command_id == IDC_NEW_INCOGNITO_WINDOW || command_id == IDC_NEW_TAB ||
261          command_id == IDC_NEW_WINDOW || command_id == IDC_RESTORE_TAB ||
262          command_id == IDC_SELECT_NEXT_TAB ||
263          command_id == IDC_SELECT_PREVIOUS_TAB || command_id == IDC_EXIT;
264 }
265 
TabStateChanged()266 void BrowserCommandController::TabStateChanged() {
267   UpdateCommandsForTabState();
268   UpdateCommandsForWebContentsFocus();
269 }
270 
ZoomStateChanged()271 void BrowserCommandController::ZoomStateChanged() {
272   UpdateCommandsForZoomState();
273 }
274 
ContentRestrictionsChanged()275 void BrowserCommandController::ContentRestrictionsChanged() {
276   UpdateCommandsForContentRestrictionState();
277 }
278 
FullscreenStateChanged()279 void BrowserCommandController::FullscreenStateChanged() {
280   UpdateCommandsForFullscreenMode();
281 }
282 
283 #if defined(OS_CHROMEOS)
LockedFullscreenStateChanged()284 void BrowserCommandController::LockedFullscreenStateChanged() {
285   UpdateCommandsForLockedFullscreenMode();
286 }
287 #endif
288 
PrintingStateChanged()289 void BrowserCommandController::PrintingStateChanged() {
290   UpdatePrintingState();
291 }
292 
LoadingStateChanged(bool is_loading,bool force)293 void BrowserCommandController::LoadingStateChanged(bool is_loading,
294                                                    bool force) {
295   UpdateReloadStopState(is_loading, force);
296 }
297 
FindBarVisibilityChanged()298 void BrowserCommandController::FindBarVisibilityChanged() {
299   if (is_locked_fullscreen_)
300     return;
301   UpdateCloseFindOrStop();
302 }
303 
ExtensionStateChanged()304 void BrowserCommandController::ExtensionStateChanged() {
305   // Extensions may disable the bookmark editing commands.
306   UpdateCommandsForBookmarkEditing();
307 }
308 
TabKeyboardFocusChangedTo(base::Optional<int> index)309 void BrowserCommandController::TabKeyboardFocusChangedTo(
310     base::Optional<int> index) {
311   UpdateCommandsForTabKeyboardFocus(index);
312 }
313 
WebContentsFocusChanged()314 void BrowserCommandController::WebContentsFocusChanged() {
315   UpdateCommandsForWebContentsFocus();
316 }
317 
318 ////////////////////////////////////////////////////////////////////////////////
319 // BrowserCommandController, CommandUpdater implementation:
320 
SupportsCommand(int id) const321 bool BrowserCommandController::SupportsCommand(int id) const {
322   return command_updater_.SupportsCommand(id);
323 }
324 
IsCommandEnabled(int id) const325 bool BrowserCommandController::IsCommandEnabled(int id) const {
326   return command_updater_.IsCommandEnabled(id);
327 }
328 
ExecuteCommand(int id,base::TimeTicks time_stamp)329 bool BrowserCommandController::ExecuteCommand(int id,
330                                               base::TimeTicks time_stamp) {
331   return ExecuteCommandWithDisposition(id, WindowOpenDisposition::CURRENT_TAB,
332                                        time_stamp);
333 }
334 
ExecuteCommandWithDisposition(int id,WindowOpenDisposition disposition,base::TimeTicks time_stamp)335 bool BrowserCommandController::ExecuteCommandWithDisposition(
336     int id,
337     WindowOpenDisposition disposition,
338     base::TimeTicks time_stamp) {
339   // Doesn't go through the command_updater_ to avoid dealing with having a
340   // naming collision for ExecuteCommandWithDisposition (both
341   // CommandUpdaterDelegate and CommandUpdater declare this function so we
342   // choose to not implement CommandUpdaterDelegate inside this class and
343   // therefore command_updater_ doesn't have the delegate set).
344   if (!SupportsCommand(id) || !IsCommandEnabled(id))
345     return false;
346 
347   // No commands are enabled if there is not yet any selected tab.
348   // TODO(pkasting): It seems like we should not need this, because either
349   // most/all commands should not have been enabled yet anyway or the ones that
350   // are enabled should be global, or safe themselves against having no selected
351   // tab.  However, Ben says he tried removing this before and got lots of
352   // crashes, e.g. from Windows sending WM_COMMANDs at random times during
353   // window construction.  This probably could use closer examination someday.
354   if (browser_->tab_strip_model()->active_index() == TabStripModel::kNoTab)
355     return true;
356 
357   DCHECK(command_updater_.IsCommandEnabled(id))
358       << "Invalid/disabled command " << id;
359 
360   // The order of commands in this switch statement must match the function
361   // declaration order in browser.h!
362   switch (id) {
363     // Navigation commands
364     case IDC_BACK:
365       GoBack(browser_, disposition);
366       break;
367     case IDC_FORWARD:
368       GoForward(browser_, disposition);
369       break;
370     case IDC_RELOAD:
371       Reload(browser_, disposition);
372       break;
373     case IDC_RELOAD_CLEARING_CACHE:
374       ClearCache(browser_);
375       FALLTHROUGH;
376     case IDC_RELOAD_BYPASSING_CACHE:
377       ReloadBypassingCache(browser_, disposition);
378       break;
379     case IDC_HOME:
380       Home(browser_, disposition);
381       break;
382     case IDC_OPEN_CURRENT_URL:
383       OpenCurrentURL(browser_);
384       break;
385     case IDC_STOP:
386       Stop(browser_);
387       break;
388     case IDC_TAB_SEARCH:
389       ShowTabSearch(browser_);
390       break;
391     case IDC_TAB_SEARCH_CLOSE:
392       CloseTabSearch(browser_);
393       break;
394 
395       // Window management commands
396     case IDC_NEW_WINDOW:
397       NewWindow(browser_);
398       break;
399     case IDC_NEW_INCOGNITO_WINDOW:
400       NewIncognitoWindow(profile());
401       break;
402     case IDC_CLOSE_WINDOW:
403       base::RecordAction(base::UserMetricsAction("CloseWindowByKey"));
404       CloseWindow(browser_);
405       break;
406     case IDC_NEW_TAB: {
407       NewTab(browser_);
408       break;
409     }
410     case IDC_CLOSE_TAB:
411       base::RecordAction(base::UserMetricsAction("CloseTabByKey"));
412       CloseTab(browser_);
413       break;
414     case IDC_SELECT_NEXT_TAB:
415       base::RecordAction(base::UserMetricsAction("Accel_SelectNextTab"));
416       SelectNextTab(browser_,
417                     {TabStripModel::GestureType::kKeyboard, time_stamp});
418       break;
419     case IDC_SELECT_PREVIOUS_TAB:
420       base::RecordAction(base::UserMetricsAction("Accel_SelectPreviousTab"));
421       SelectPreviousTab(browser_,
422                         {TabStripModel::GestureType::kKeyboard, time_stamp});
423       break;
424     case IDC_MOVE_TAB_NEXT:
425       MoveTabNext(browser_);
426       break;
427     case IDC_MOVE_TAB_PREVIOUS:
428       MoveTabPrevious(browser_);
429       break;
430     case IDC_SELECT_TAB_0:
431     case IDC_SELECT_TAB_1:
432     case IDC_SELECT_TAB_2:
433     case IDC_SELECT_TAB_3:
434     case IDC_SELECT_TAB_4:
435     case IDC_SELECT_TAB_5:
436     case IDC_SELECT_TAB_6:
437     case IDC_SELECT_TAB_7:
438       base::RecordAction(base::UserMetricsAction("Accel_SelectNumberedTab"));
439       SelectNumberedTab(browser_, id - IDC_SELECT_TAB_0,
440                         {TabStripModel::GestureType::kKeyboard, time_stamp});
441       break;
442     case IDC_SELECT_LAST_TAB:
443       base::RecordAction(base::UserMetricsAction("Accel_SelectNumberedTab"));
444       SelectLastTab(browser_,
445                     {TabStripModel::GestureType::kKeyboard, time_stamp});
446       break;
447     case IDC_DUPLICATE_TAB:
448       DuplicateTab(browser_);
449       break;
450     case IDC_RESTORE_TAB:
451       RestoreTab(browser_);
452       browser_->window()->OnTabRestored(IDC_RESTORE_TAB);
453       break;
454     case IDC_SHOW_AS_TAB:
455       ConvertPopupToTabbedBrowser(browser_);
456       break;
457     case IDC_FULLSCREEN:
458       chrome::ToggleFullscreenMode(browser_);
459       break;
460     case IDC_OPEN_IN_PWA_WINDOW:
461       base::RecordAction(base::UserMetricsAction("OpenActiveTabInPwaWindow"));
462       web_app::ReparentWebAppForActiveTab(browser_);
463       break;
464     case IDC_MOVE_TAB_TO_NEW_WINDOW:
465       MoveActiveTabToNewWindow(browser_);
466       break;
467     case IDC_NAME_WINDOW:
468       PromptToNameWindow(browser_);
469       break;
470 
471 #if defined(OS_CHROMEOS)
472     case IDC_VISIT_DESKTOP_OF_LRU_USER_2:
473     case IDC_VISIT_DESKTOP_OF_LRU_USER_3:
474     case IDC_VISIT_DESKTOP_OF_LRU_USER_4:
475     case IDC_VISIT_DESKTOP_OF_LRU_USER_5:
476       ExecuteVisitDesktopCommand(id, window()->GetNativeWindow());
477       break;
478 #endif
479 
480 #if (defined(OS_LINUX) || defined(OS_BSD)) && !defined(OS_CHROMEOS)
481     case IDC_MINIMIZE_WINDOW:
482       browser_->window()->Minimize();
483       break;
484     case IDC_MAXIMIZE_WINDOW:
485       browser_->window()->Maximize();
486       break;
487     case IDC_RESTORE_WINDOW:
488       browser_->window()->Restore();
489       break;
490     case IDC_USE_SYSTEM_TITLE_BAR: {
491       PrefService* prefs = profile()->GetPrefs();
492       prefs->SetBoolean(prefs::kUseCustomChromeFrame,
493                         !prefs->GetBoolean(prefs::kUseCustomChromeFrame));
494       break;
495     }
496 #endif
497 
498 #if defined(OS_MAC)
499     case IDC_TOGGLE_FULLSCREEN_TOOLBAR:
500       chrome::ToggleFullscreenToolbar(browser_);
501       break;
502     case IDC_TOGGLE_JAVASCRIPT_APPLE_EVENTS: {
503       chrome::ToggleJavaScriptFromAppleEventsAllowed(browser_);
504       break;
505     }
506 #endif
507     case IDC_EXIT:
508       Exit();
509       break;
510 
511     // Page-related commands
512     case IDC_SAVE_PAGE:
513       SavePage(browser_);
514       break;
515     case IDC_BOOKMARK_THIS_TAB:
516       BookmarkCurrentTab(browser_);
517       break;
518     case IDC_BOOKMARK_ALL_TABS:
519       BookmarkAllTabs(browser_);
520       break;
521     case IDC_VIEW_SOURCE:
522       browser_->tab_strip_model()
523           ->GetActiveWebContents()
524           ->GetMainFrame()
525           ->ViewSource();
526       break;
527     case IDC_PRINT:
528       Print(browser_);
529       break;
530 
531 #if BUILDFLAG(ENABLE_PRINTING)
532     case IDC_BASIC_PRINT:
533       base::RecordAction(base::UserMetricsAction("Accel_Advanced_Print"));
534       BasicPrint(browser_);
535       break;
536 #endif  // ENABLE_PRINTING
537 
538     case IDC_SAVE_CREDIT_CARD_FOR_PAGE:
539       SaveCreditCard(browser_);
540       break;
541     case IDC_MIGRATE_LOCAL_CREDIT_CARD_FOR_PAGE:
542       MigrateLocalCards(browser_);
543       break;
544     case IDC_SHOW_SAVE_LOCAL_CARD_SIGN_IN_PROMO_IF_APPLICABLE:
545       MaybeShowSaveLocalCardSignInPromo(browser_);
546       break;
547     case IDC_CLOSE_SIGN_IN_PROMO:
548       CloseSaveLocalCardSignInPromo(browser_);
549       break;
550     case IDC_TRANSLATE_PAGE:
551       Translate(browser_);
552       break;
553     case IDC_MANAGE_PASSWORDS_FOR_PAGE:
554       ManagePasswordsForPage(browser_);
555       break;
556     case IDC_SEND_TAB_TO_SELF:
557       SendTabToSelfFromPageAction(browser_);
558       break;
559     case IDC_QRCODE_GENERATOR:
560       GenerateQRCodeFromPageAction(browser_);
561       break;
562 
563     // Clipboard commands
564     case IDC_CUT:
565     case IDC_COPY:
566     case IDC_PASTE:
567       CutCopyPaste(browser_, id);
568       break;
569 
570     // Find-in-page
571     case IDC_FIND:
572       Find(browser_);
573       break;
574     case IDC_FIND_NEXT:
575       FindNext(browser_);
576       break;
577     case IDC_FIND_PREVIOUS:
578       FindPrevious(browser_);
579       break;
580     case IDC_CLOSE_FIND_OR_STOP:
581       if (CanCloseFind(browser_))
582         CloseFind(browser_);
583       else if (IsCommandEnabled(IDC_STOP))
584         ExecuteCommand(IDC_STOP);
585       break;
586 
587     // Zoom
588     case IDC_ZOOM_PLUS:
589       Zoom(browser_, content::PAGE_ZOOM_IN);
590       break;
591     case IDC_ZOOM_NORMAL:
592       Zoom(browser_, content::PAGE_ZOOM_RESET);
593       break;
594     case IDC_ZOOM_MINUS:
595       Zoom(browser_, content::PAGE_ZOOM_OUT);
596       break;
597 
598     // Focus various bits of UI
599     case IDC_FOCUS_TOOLBAR:
600       base::RecordAction(base::UserMetricsAction("Accel_Focus_Toolbar"));
601       FocusToolbar(browser_);
602       break;
603     case IDC_FOCUS_LOCATION:
604       base::RecordAction(base::UserMetricsAction("Accel_Focus_Location"));
605       FocusLocationBar(browser_);
606       break;
607     case IDC_FOCUS_SEARCH:
608       base::RecordAction(base::UserMetricsAction("Accel_Focus_Search"));
609       FocusSearch(browser_);
610       break;
611     case IDC_FOCUS_MENU_BAR:
612       FocusAppMenu(browser_);
613       break;
614     case IDC_FOCUS_BOOKMARKS:
615       base::RecordAction(base::UserMetricsAction("Accel_Focus_Bookmarks"));
616       FocusBookmarksToolbar(browser_);
617       break;
618     case IDC_FOCUS_INACTIVE_POPUP_FOR_ACCESSIBILITY:
619       FocusInactivePopupForAccessibility(browser_);
620       break;
621     case IDC_FOCUS_NEXT_PANE:
622       FocusNextPane(browser_);
623       break;
624     case IDC_FOCUS_PREVIOUS_PANE:
625       FocusPreviousPane(browser_);
626       break;
627 
628     // Show various bits of UI
629     case IDC_OPEN_FILE:
630       browser_->OpenFile();
631       break;
632     case IDC_CREATE_SHORTCUT:
633       base::RecordAction(base::UserMetricsAction("CreateShortcut"));
634       web_app::CreateWebAppFromCurrentWebContents(
635           browser_, true /* force_shortcut_app */);
636       break;
637     case IDC_INSTALL_PWA:
638       base::RecordAction(base::UserMetricsAction("InstallWebAppFromMenu"));
639       web_app::CreateWebAppFromCurrentWebContents(
640           browser_, false /* force_shortcut_app */);
641       break;
642     case IDC_DEV_TOOLS:
643       ToggleDevToolsWindow(browser_, DevToolsToggleAction::Show(),
644                            DevToolsOpenedByAction::kMainMenuOrMainShortcut);
645       break;
646     case IDC_DEV_TOOLS_CONSOLE:
647       ToggleDevToolsWindow(browser_, DevToolsToggleAction::ShowConsolePanel(),
648                            DevToolsOpenedByAction::kConsoleShortcut);
649       break;
650     case IDC_DEV_TOOLS_DEVICES:
651       InspectUI::InspectDevices(browser_);
652       break;
653     case IDC_DEV_TOOLS_INSPECT:
654       ToggleDevToolsWindow(browser_, DevToolsToggleAction::Inspect(),
655                            DevToolsOpenedByAction::kInspectorModeShortcut);
656       break;
657     case IDC_DEV_TOOLS_TOGGLE:
658       ToggleDevToolsWindow(browser_, DevToolsToggleAction::Toggle(),
659                            DevToolsOpenedByAction::kToggleShortcut);
660       break;
661     case IDC_TASK_MANAGER:
662       OpenTaskManager(browser_);
663       break;
664 #if defined(OS_CHROMEOS)
665     case IDC_TAKE_SCREENSHOT:
666       TakeScreenshot();
667       break;
668 #endif
669 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
670     case IDC_FEEDBACK:
671       OpenFeedbackDialog(browser_, kFeedbackSourceBrowserCommand);
672       break;
673 #endif
674     case IDC_SHOW_BOOKMARK_BAR:
675       ToggleBookmarkBar(browser_);
676       break;
677     case IDC_SHOW_FULL_URLS:
678       ToggleShowFullURLs(browser_);
679       break;
680     case IDC_PROFILING_ENABLED:
681       content::Profiling::Toggle();
682       break;
683     case IDC_CARET_BROWSING_TOGGLE:
684       ToggleCaretBrowsing(browser_);
685       break;
686 
687     case IDC_SHOW_BOOKMARK_MANAGER:
688       ShowBookmarkManager(browser_);
689       break;
690     case IDC_SHOW_APP_MENU:
691       base::RecordAction(base::UserMetricsAction("Accel_Show_App_Menu"));
692       ShowAppMenu(browser_);
693       break;
694     case IDC_SHOW_AVATAR_MENU:
695       ShowAvatarMenu(browser_);
696       break;
697     case IDC_SHOW_HISTORY:
698       ShowHistory(browser_);
699       break;
700     case IDC_SHOW_DOWNLOADS:
701       ShowDownloads(browser_);
702       break;
703     case IDC_MANAGE_EXTENSIONS:
704       ShowExtensions(browser_, std::string());
705       break;
706     case IDC_OPTIONS:
707       ShowSettings(browser_);
708       break;
709     case IDC_EDIT_SEARCH_ENGINES:
710       ShowSearchEngineSettings(browser_);
711       break;
712     case IDC_VIEW_PASSWORDS:
713       ShowPasswordManager(browser_);
714       break;
715     case IDC_CLEAR_BROWSING_DATA:
716       ShowClearBrowsingDataDialog(browser_);
717       break;
718     case IDC_IMPORT_SETTINGS:
719       ShowImportDialog(browser_);
720       break;
721     case IDC_TOGGLE_REQUEST_TABLET_SITE:
722       ToggleRequestTabletSite(browser_);
723       break;
724     case IDC_ABOUT:
725       ShowAboutChrome(browser_);
726       break;
727     case IDC_UPGRADE_DIALOG:
728       OpenUpdateChromeDialog(browser_);
729       break;
730     case IDC_HELP_PAGE_VIA_KEYBOARD:
731       ShowHelp(browser_, HELP_SOURCE_KEYBOARD);
732       break;
733     case IDC_HELP_PAGE_VIA_MENU:
734       ShowHelp(browser_, HELP_SOURCE_MENU);
735       break;
736     case IDC_SHOW_BETA_FORUM:
737       ShowBetaForum(browser_);
738       break;
739     case IDC_TOGGLE_COMMANDER:
740       ToggleCommander(browser_);
741       break;
742 #if !defined(OS_CHROMEOS)
743     case IDC_SHOW_SIGNIN:
744       ShowBrowserSigninOrSettings(
745           browser_, signin_metrics::AccessPoint::ACCESS_POINT_MENU);
746       break;
747 #endif
748     case IDC_DISTILL_PAGE:
749       ToggleDistilledView(browser_);
750       break;
751     case IDC_ROUTE_MEDIA:
752       RouteMediaInvokedFromAppMenu(browser_);
753       break;
754     case IDC_WINDOW_MUTE_SITE:
755       MuteSite(browser_);
756       break;
757     case IDC_WINDOW_PIN_TAB:
758       PinTab(browser_);
759       break;
760     case IDC_WINDOW_GROUP_TAB:
761       GroupTab(browser_);
762       break;
763     case IDC_WINDOW_CLOSE_TABS_TO_RIGHT:
764       CloseTabsToRight(browser_);
765       break;
766     case IDC_WINDOW_CLOSE_OTHER_TABS:
767       CloseOtherTabs(browser_);
768       break;
769     case IDC_SHOW_MANAGEMENT_PAGE: {
770       ShowSingletonTab(browser_, GURL(kChromeUIManagementURL));
771       break;
772     }
773     case IDC_MUTE_TARGET_SITE:
774       MuteSiteForKeyboardFocusedTab(browser_);
775       break;
776     case IDC_PIN_TARGET_TAB:
777       PinKeyboardFocusedTab(browser_);
778       break;
779     case IDC_GROUP_TARGET_TAB:
780       GroupKeyboardFocusedTab(browser_);
781       break;
782     case IDC_DUPLICATE_TARGET_TAB:
783       DuplicateKeyboardFocusedTab(browser_);
784       break;
785     // Hosted App commands
786     case IDC_COPY_URL:
787       CopyURL(browser_);
788       break;
789     case IDC_OPEN_IN_CHROME:
790       OpenInChrome(browser_);
791       break;
792     case IDC_SITE_SETTINGS:
793       ShowSiteSettings(
794           browser_,
795           browser_->tab_strip_model()->GetActiveWebContents()->GetVisibleURL());
796       break;
797     case IDC_WEB_APP_MENU_APP_INFO: {
798       content::WebContents* const web_contents =
799           browser_->tab_strip_model()->GetActiveWebContents();
800       if (web_contents) {
801         ShowPageInfoDialog(web_contents,
802                            base::BindOnce(&AppInfoDialogClosedCallback,
803                                           base::Unretained(web_contents)),
804                            bubble_anchor_util::kAppMenuButton);
805       }
806       break;
807     }
808     default:
809       LOG(WARNING) << "Received Unimplemented Command: " << id;
810       break;
811   }
812 
813   return true;
814 }
815 
AddCommandObserver(int id,CommandObserver * observer)816 void BrowserCommandController::AddCommandObserver(int id,
817                                                   CommandObserver* observer) {
818   command_updater_.AddCommandObserver(id, observer);
819 }
820 
RemoveCommandObserver(int id,CommandObserver * observer)821 void BrowserCommandController::RemoveCommandObserver(
822     int id,
823     CommandObserver* observer) {
824   command_updater_.RemoveCommandObserver(id, observer);
825 }
826 
RemoveCommandObserver(CommandObserver * observer)827 void BrowserCommandController::RemoveCommandObserver(
828     CommandObserver* observer) {
829   command_updater_.RemoveCommandObserver(observer);
830 }
831 
UpdateCommandEnabled(int id,bool state)832 bool BrowserCommandController::UpdateCommandEnabled(int id, bool state) {
833   if (is_locked_fullscreen_)
834     return false;
835 
836   return command_updater_.UpdateCommandEnabled(id, state);
837 }
838 
839 ////////////////////////////////////////////////////////////////////////////////
840 // BrowserCommandController, SigninPrefObserver implementation:
841 
OnSigninAllowedPrefChange()842 void BrowserCommandController::OnSigninAllowedPrefChange() {
843   // For unit tests, we don't have a window.
844   if (!window())
845     return;
846   UpdateShowSyncState(IsShowingMainUI());
847 }
848 
849 // BrowserCommandController, TabStripModelObserver implementation:
850 
OnTabStripModelChanged(TabStripModel * tab_strip_model,const TabStripModelChange & change,const TabStripSelectionChange & selection)851 void BrowserCommandController::OnTabStripModelChanged(
852     TabStripModel* tab_strip_model,
853     const TabStripModelChange& change,
854     const TabStripSelectionChange& selection) {
855   std::vector<content::WebContents*> new_contents;
856   std::vector<content::WebContents*> old_contents;
857 
858   switch (change.type()) {
859     case TabStripModelChange::kInserted:
860       for (const auto& contents : change.GetInsert()->contents)
861         new_contents.push_back(contents.contents);
862       break;
863     case TabStripModelChange::kReplaced: {
864       auto* replace = change.GetReplace();
865       new_contents.push_back(replace->new_contents);
866       old_contents.push_back(replace->old_contents);
867       break;
868     }
869     case TabStripModelChange::kRemoved:
870       for (const auto& contents : change.GetRemove()->contents)
871         old_contents.push_back(contents.contents);
872       break;
873     default:
874       break;
875   }
876 }
877 
TabBlockedStateChanged(content::WebContents * contents,int index)878 void BrowserCommandController::TabBlockedStateChanged(
879     content::WebContents* contents,
880     int index) {
881   PrintingStateChanged();
882   FullscreenStateChanged();
883   UpdateCommandsForFind();
884   UpdateCommandsForMediaRouter();
885 }
886 
887 ////////////////////////////////////////////////////////////////////////////////
888 // BrowserCommandController, TabRestoreServiceObserver implementation:
889 
TabRestoreServiceChanged(sessions::TabRestoreService * service)890 void BrowserCommandController::TabRestoreServiceChanged(
891     sessions::TabRestoreService* service) {
892   UpdateTabRestoreCommandState();
893 }
894 
TabRestoreServiceDestroyed(sessions::TabRestoreService * service)895 void BrowserCommandController::TabRestoreServiceDestroyed(
896     sessions::TabRestoreService* service) {
897   service->RemoveObserver(this);
898 }
899 
TabRestoreServiceLoaded(sessions::TabRestoreService * service)900 void BrowserCommandController::TabRestoreServiceLoaded(
901     sessions::TabRestoreService* service) {
902   UpdateTabRestoreCommandState();
903 }
904 
905 ////////////////////////////////////////////////////////////////////////////////
906 // BrowserCommandController, private:
907 
IsShowingMainUI()908 bool BrowserCommandController::IsShowingMainUI() {
909   return browser_->SupportsWindowFeature(Browser::FEATURE_TABSTRIP);
910 }
911 
IsShowingLocationBar()912 bool BrowserCommandController::IsShowingLocationBar() {
913   return browser_->SupportsWindowFeature(Browser::FEATURE_LOCATIONBAR);
914 }
915 
InitCommandState()916 void BrowserCommandController::InitCommandState() {
917   // All browser commands whose state isn't set automagically some other way
918   // (like Back & Forward with initial page load) must have their state
919   // initialized here, otherwise they will be forever disabled.
920 
921   if (is_locked_fullscreen_)
922     return;
923 
924   // Navigation commands
925   command_updater_.UpdateCommandEnabled(IDC_RELOAD, true);
926   command_updater_.UpdateCommandEnabled(IDC_RELOAD_BYPASSING_CACHE, true);
927   command_updater_.UpdateCommandEnabled(IDC_RELOAD_CLEARING_CACHE, true);
928 
929   // Window management commands
930   command_updater_.UpdateCommandEnabled(IDC_CLOSE_WINDOW, true);
931   command_updater_.UpdateCommandEnabled(IDC_NEW_TAB, true);
932   command_updater_.UpdateCommandEnabled(IDC_CLOSE_TAB, true);
933   command_updater_.UpdateCommandEnabled(IDC_DUPLICATE_TAB, true);
934   UpdateTabRestoreCommandState();
935   command_updater_.UpdateCommandEnabled(IDC_EXIT, true);
936   command_updater_.UpdateCommandEnabled(IDC_DEBUG_FRAME_TOGGLE, true);
937   command_updater_.UpdateCommandEnabled(IDC_NAME_WINDOW, true);
938 #if defined(OS_CHROMEOS)
939   command_updater_.UpdateCommandEnabled(IDC_MINIMIZE_WINDOW, true);
940   // The VisitDesktop command is only supported for up to 5 logged in users
941   // because that's the max number of user sessions. If that number is increased
942   // the IDC_VISIT_DESKTOP_OF_LRU_USER_ command ids should be updated as well.
943   // crbug.com/940461
944   static_assert(
945       session_manager::kMaximumNumberOfUserSessions <=
946           IDC_VISIT_DESKTOP_OF_LRU_USER_LAST -
947               IDC_VISIT_DESKTOP_OF_LRU_USER_NEXT + 2,
948       "The max number of user sessions exceeds the number of users supported.");
949   command_updater_.UpdateCommandEnabled(IDC_VISIT_DESKTOP_OF_LRU_USER_2, true);
950   command_updater_.UpdateCommandEnabled(IDC_VISIT_DESKTOP_OF_LRU_USER_3, true);
951   command_updater_.UpdateCommandEnabled(IDC_VISIT_DESKTOP_OF_LRU_USER_4, true);
952   command_updater_.UpdateCommandEnabled(IDC_VISIT_DESKTOP_OF_LRU_USER_5, true);
953 #endif
954 #if (defined(OS_LINUX) || defined(OS_BSD)) && !defined(OS_CHROMEOS)
955   command_updater_.UpdateCommandEnabled(IDC_MINIMIZE_WINDOW, true);
956   command_updater_.UpdateCommandEnabled(IDC_MAXIMIZE_WINDOW, true);
957   command_updater_.UpdateCommandEnabled(IDC_RESTORE_WINDOW, true);
958   bool use_system_title_bar = true;
959 #if defined(USE_OZONE)
960   if (features::IsUsingOzonePlatform()) {
961     use_system_title_bar = ui::OzonePlatform::GetInstance()
962                                ->GetPlatformProperties()
963                                .use_system_title_bar;
964   }
965 #endif
966   command_updater_.UpdateCommandEnabled(IDC_USE_SYSTEM_TITLE_BAR,
967                                         use_system_title_bar);
968 #endif
969   command_updater_.UpdateCommandEnabled(IDC_OPEN_IN_PWA_WINDOW, true);
970 
971   // Page-related commands
972   command_updater_.UpdateCommandEnabled(IDC_MANAGE_PASSWORDS_FOR_PAGE, true);
973 
974   // Zoom
975   command_updater_.UpdateCommandEnabled(IDC_ZOOM_MENU, true);
976   command_updater_.UpdateCommandEnabled(IDC_ZOOM_PLUS, true);
977   command_updater_.UpdateCommandEnabled(IDC_ZOOM_NORMAL, false);
978   command_updater_.UpdateCommandEnabled(IDC_ZOOM_MINUS, true);
979 
980   // Show various bits of UI
981   DCHECK(!profile()->IsSystemProfile())
982       << "Ought to never have browser for the system profile.";
983   const bool normal_window = browser_->is_type_normal();
984   UpdateOpenFileState(&command_updater_);
985   UpdateCommandsForDevTools();
986   command_updater_.UpdateCommandEnabled(IDC_TASK_MANAGER, CanOpenTaskManager());
987   command_updater_.UpdateCommandEnabled(
988       IDC_SHOW_HISTORY,
989       (!profile()->IsGuestSession() && !profile()->IsSystemProfile()));
990   command_updater_.UpdateCommandEnabled(IDC_SHOW_DOWNLOADS, true);
991   command_updater_.UpdateCommandEnabled(IDC_HELP_MENU, true);
992   command_updater_.UpdateCommandEnabled(IDC_HELP_PAGE_VIA_KEYBOARD, true);
993   command_updater_.UpdateCommandEnabled(IDC_HELP_PAGE_VIA_MENU, true);
994   command_updater_.UpdateCommandEnabled(IDC_SHOW_BETA_FORUM, true);
995   command_updater_.UpdateCommandEnabled(
996       IDC_BOOKMARKS_MENU,
997       (!profile()->IsGuestSession() && !profile()->IsSystemProfile() &&
998        !profile()->IsEphemeralGuestProfile()));
999   command_updater_.UpdateCommandEnabled(
1000       IDC_RECENT_TABS_MENU,
1001       (!profile()->IsGuestSession() && !profile()->IsSystemProfile() &&
1002        !profile()->IsIncognitoProfile()));
1003   command_updater_.UpdateCommandEnabled(
1004       IDC_CLEAR_BROWSING_DATA,
1005       (!profile()->IsGuestSession() && !profile()->IsSystemProfile() &&
1006        !profile()->IsIncognitoProfile()));
1007 #if defined(OS_CHROMEOS)
1008   command_updater_.UpdateCommandEnabled(IDC_TAKE_SCREENSHOT, true);
1009   // Chrome OS uses the system tray menu to handle multi-profiles. Avatar menu
1010   // is only required in incognito mode.
1011   if (profile()->IsIncognitoProfile())
1012     command_updater_.UpdateCommandEnabled(IDC_SHOW_AVATAR_MENU, true);
1013 #else
1014   if (normal_window)
1015     command_updater_.UpdateCommandEnabled(IDC_SHOW_AVATAR_MENU, true);
1016 #endif
1017   command_updater_.UpdateCommandEnabled(
1018       IDC_SHOW_SAVE_LOCAL_CARD_SIGN_IN_PROMO_IF_APPLICABLE, true);
1019   command_updater_.UpdateCommandEnabled(IDC_CLOSE_SIGN_IN_PROMO, true);
1020   command_updater_.UpdateCommandEnabled(IDC_CARET_BROWSING_TOGGLE, true);
1021   command_updater_.UpdateCommandEnabled(IDC_TOGGLE_COMMANDER,
1022                                         commander::IsEnabled());
1023   UpdateShowSyncState(true);
1024 
1025   // Navigation commands
1026   command_updater_.UpdateCommandEnabled(
1027       IDC_HOME, normal_window || browser_->deprecated_is_app());
1028 
1029   const bool is_web_app_or_custom_tab =
1030 #if defined(OS_CHROMEOS)
1031       browser_->is_type_custom_tab() ||
1032 #endif
1033       web_app::AppBrowserController::IsForWebAppBrowser(browser_);
1034   // Hosted app browser commands.
1035   command_updater_.UpdateCommandEnabled(IDC_COPY_URL, is_web_app_or_custom_tab);
1036   command_updater_.UpdateCommandEnabled(IDC_OPEN_IN_CHROME,
1037                                         is_web_app_or_custom_tab);
1038   command_updater_.UpdateCommandEnabled(IDC_SITE_SETTINGS,
1039                                         is_web_app_or_custom_tab);
1040   command_updater_.UpdateCommandEnabled(IDC_WEB_APP_MENU_APP_INFO,
1041                                         is_web_app_or_custom_tab);
1042 
1043   // Tab management commands
1044   const bool supports_tabs =
1045       browser_->SupportsWindowFeature(Browser::FEATURE_TABSTRIP);
1046   command_updater_.UpdateCommandEnabled(IDC_SELECT_NEXT_TAB, supports_tabs);
1047   command_updater_.UpdateCommandEnabled(IDC_SELECT_PREVIOUS_TAB, supports_tabs);
1048   command_updater_.UpdateCommandEnabled(IDC_MOVE_TAB_NEXT, supports_tabs);
1049   command_updater_.UpdateCommandEnabled(IDC_MOVE_TAB_PREVIOUS, supports_tabs);
1050   command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_0, supports_tabs);
1051   command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_1, supports_tabs);
1052   command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_2, supports_tabs);
1053   command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_3, supports_tabs);
1054   command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_4, supports_tabs);
1055   command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_5, supports_tabs);
1056   command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_6, supports_tabs);
1057   command_updater_.UpdateCommandEnabled(IDC_SELECT_TAB_7, supports_tabs);
1058   command_updater_.UpdateCommandEnabled(IDC_SELECT_LAST_TAB, supports_tabs);
1059 
1060   // These are always enabled; the menu determines their menu item visibility.
1061   command_updater_.UpdateCommandEnabled(IDC_UPGRADE_DIALOG, true);
1062 
1063   // Distill current page.
1064   command_updater_.UpdateCommandEnabled(IDC_DISTILL_PAGE,
1065                                         dom_distiller::IsDomDistillerEnabled());
1066 
1067   command_updater_.UpdateCommandEnabled(IDC_WINDOW_MUTE_SITE, normal_window);
1068   command_updater_.UpdateCommandEnabled(IDC_WINDOW_PIN_TAB, normal_window);
1069   command_updater_.UpdateCommandEnabled(IDC_WINDOW_GROUP_TAB, normal_window);
1070   command_updater_.UpdateCommandEnabled(IDC_WINDOW_CLOSE_TABS_TO_RIGHT,
1071                                         normal_window);
1072   command_updater_.UpdateCommandEnabled(IDC_WINDOW_CLOSE_OTHER_TABS,
1073                                         normal_window);
1074 
1075   const bool enable_tab_search_commands =
1076       base::FeatureList::IsEnabled(features::kTabSearch) &&
1077       browser_->is_type_normal();
1078   command_updater_.UpdateCommandEnabled(IDC_TAB_SEARCH,
1079                                         enable_tab_search_commands);
1080   command_updater_.UpdateCommandEnabled(IDC_TAB_SEARCH_CLOSE,
1081                                         enable_tab_search_commands);
1082 
1083   // Initialize other commands whose state changes based on various conditions.
1084   UpdateCommandsForFullscreenMode();
1085   UpdateCommandsForContentRestrictionState();
1086   UpdateCommandsForBookmarkEditing();
1087   UpdateCommandsForIncognitoAvailability();
1088   UpdateCommandsForTabKeyboardFocus(GetKeyboardFocusedTabIndex(browser_));
1089   UpdateCommandsForWebContentsFocus();
1090 }
1091 
1092 // static
UpdateSharedCommandsForIncognitoAvailability(CommandUpdater * command_updater,Profile * profile)1093 void BrowserCommandController::UpdateSharedCommandsForIncognitoAvailability(
1094     CommandUpdater* command_updater,
1095     Profile* profile) {
1096   IncognitoModePrefs::Availability incognito_availability =
1097       IncognitoModePrefs::GetAvailability(profile->GetPrefs());
1098   command_updater->UpdateCommandEnabled(
1099       IDC_NEW_WINDOW, incognito_availability != IncognitoModePrefs::FORCED);
1100   command_updater->UpdateCommandEnabled(
1101       IDC_NEW_INCOGNITO_WINDOW,
1102       incognito_availability != IncognitoModePrefs::DISABLED &&
1103           !profile->IsGuestSession() && !profile->IsEphemeralGuestProfile());
1104 
1105   const bool forced_incognito =
1106       incognito_availability == IncognitoModePrefs::FORCED;
1107   const bool is_guest =
1108       profile->IsGuestSession() || profile->IsEphemeralGuestProfile();
1109 
1110   command_updater->UpdateCommandEnabled(
1111       IDC_SHOW_BOOKMARK_MANAGER,
1112       browser_defaults::bookmarks_enabled && !forced_incognito && !is_guest);
1113   extensions::ExtensionService* extension_service =
1114       extensions::ExtensionSystem::Get(profile)->extension_service();
1115   const bool enable_extensions =
1116       extension_service && extension_service->extensions_enabled();
1117 
1118   command_updater->UpdateCommandEnabled(IDC_SHOW_FULL_URLS, true);
1119 
1120   // Bookmark manager and settings page/subpages are forced to open in normal
1121   // mode. For this reason we disable these commands when incognito is forced.
1122   command_updater->UpdateCommandEnabled(
1123       IDC_MANAGE_EXTENSIONS,
1124       enable_extensions && !forced_incognito && !is_guest);
1125 
1126   command_updater->UpdateCommandEnabled(IDC_IMPORT_SETTINGS,
1127                                         !forced_incognito && !is_guest);
1128   command_updater->UpdateCommandEnabled(IDC_OPTIONS,
1129                                         !forced_incognito || is_guest);
1130   command_updater->UpdateCommandEnabled(IDC_SHOW_SIGNIN,
1131                                         !forced_incognito && !is_guest);
1132 }
1133 
UpdateCommandsForIncognitoAvailability()1134 void BrowserCommandController::UpdateCommandsForIncognitoAvailability() {
1135   if (is_locked_fullscreen_)
1136     return;
1137 
1138   UpdateSharedCommandsForIncognitoAvailability(&command_updater_, profile());
1139 
1140   if (!IsShowingMainUI()) {
1141     command_updater_.UpdateCommandEnabled(IDC_IMPORT_SETTINGS, false);
1142     command_updater_.UpdateCommandEnabled(IDC_OPTIONS, false);
1143   }
1144 }
1145 
UpdateCommandsForTabState()1146 void BrowserCommandController::UpdateCommandsForTabState() {
1147   if (is_locked_fullscreen_)
1148     return;
1149 
1150   WebContents* current_web_contents =
1151       browser_->tab_strip_model()->GetActiveWebContents();
1152   if (!current_web_contents)  // May be NULL during tab restore.
1153     return;
1154 
1155   // Navigation commands
1156   command_updater_.UpdateCommandEnabled(IDC_BACK, CanGoBack(browser_));
1157   command_updater_.UpdateCommandEnabled(IDC_FORWARD, CanGoForward(browser_));
1158   command_updater_.UpdateCommandEnabled(IDC_RELOAD, CanReload(browser_));
1159   command_updater_.UpdateCommandEnabled(IDC_RELOAD_BYPASSING_CACHE,
1160                                         CanReload(browser_));
1161   command_updater_.UpdateCommandEnabled(IDC_RELOAD_CLEARING_CACHE,
1162                                         CanReload(browser_));
1163 
1164   // Window management commands
1165   command_updater_.UpdateCommandEnabled(
1166       IDC_DUPLICATE_TAB,
1167       !browser_->deprecated_is_app() && CanDuplicateTab(browser_));
1168   command_updater_.UpdateCommandEnabled(IDC_WINDOW_MUTE_SITE,
1169                                         !browser_->deprecated_is_app());
1170   command_updater_.UpdateCommandEnabled(IDC_WINDOW_PIN_TAB,
1171                                         !browser_->deprecated_is_app());
1172   command_updater_.UpdateCommandEnabled(IDC_WINDOW_GROUP_TAB,
1173                                         !browser_->deprecated_is_app());
1174   command_updater_.UpdateCommandEnabled(IDC_WINDOW_CLOSE_TABS_TO_RIGHT,
1175                                         CanCloseTabsToRight(browser_));
1176   command_updater_.UpdateCommandEnabled(IDC_WINDOW_CLOSE_OTHER_TABS,
1177                                         CanCloseOtherTabs(browser_));
1178   command_updater_.UpdateCommandEnabled(IDC_MOVE_TAB_TO_NEW_WINDOW,
1179                                         CanMoveActiveTabToNewWindow(browser_));
1180 
1181   // Page-related commands
1182   window()->SetStarredState(
1183       BookmarkTabHelper::FromWebContents(current_web_contents)->is_starred());
1184   window()->ZoomChangedForActiveTab(false);
1185   command_updater_.UpdateCommandEnabled(IDC_VIEW_SOURCE,
1186                                         CanViewSource(browser_));
1187   if (browser_->is_type_devtools())
1188     command_updater_.UpdateCommandEnabled(IDC_OPEN_FILE, false);
1189 
1190   bool can_create_web_app = web_app::CanCreateWebApp(browser_);
1191   command_updater_.UpdateCommandEnabled(IDC_INSTALL_PWA, can_create_web_app);
1192   command_updater_.UpdateCommandEnabled(IDC_CREATE_SHORTCUT,
1193                                         can_create_web_app);
1194   // Note that additional logic in AppMenuModel::Build() controls the presence
1195   // of this command.
1196   command_updater_.UpdateCommandEnabled(IDC_OPEN_IN_PWA_WINDOW,
1197                                         web_app::CanPopOutWebApp(profile()));
1198 
1199   command_updater_.UpdateCommandEnabled(
1200       IDC_TOGGLE_REQUEST_TABLET_SITE,
1201       CanRequestTabletSite(current_web_contents));
1202 
1203   UpdateCommandsForContentRestrictionState();
1204   UpdateCommandsForBookmarkEditing();
1205   UpdateCommandsForFind();
1206   UpdateCommandsForMediaRouter();
1207   // Update the zoom commands when an active tab is selected.
1208   UpdateCommandsForZoomState();
1209   UpdateCommandsForTabKeyboardFocus(GetKeyboardFocusedTabIndex(browser_));
1210 }
1211 
UpdateCommandsForZoomState()1212 void BrowserCommandController::UpdateCommandsForZoomState() {
1213   WebContents* contents = browser_->tab_strip_model()->GetActiveWebContents();
1214   if (!contents)
1215     return;
1216   command_updater_.UpdateCommandEnabled(IDC_ZOOM_PLUS, CanZoomIn(contents));
1217   command_updater_.UpdateCommandEnabled(IDC_ZOOM_NORMAL,
1218                                         CanResetZoom(contents));
1219   command_updater_.UpdateCommandEnabled(IDC_ZOOM_MINUS, CanZoomOut(contents));
1220 }
1221 
UpdateCommandsForContentRestrictionState()1222 void BrowserCommandController::UpdateCommandsForContentRestrictionState() {
1223   int restrictions = GetContentRestrictions(browser_);
1224 
1225   command_updater_.UpdateCommandEnabled(
1226       IDC_COPY, !(restrictions & CONTENT_RESTRICTION_COPY));
1227   command_updater_.UpdateCommandEnabled(
1228       IDC_CUT, !(restrictions & CONTENT_RESTRICTION_CUT));
1229   command_updater_.UpdateCommandEnabled(
1230       IDC_PASTE, !(restrictions & CONTENT_RESTRICTION_PASTE));
1231   UpdateSaveAsState();
1232   UpdatePrintingState();
1233 }
1234 
UpdateCommandsForDevTools()1235 void BrowserCommandController::UpdateCommandsForDevTools() {
1236   if (is_locked_fullscreen_)
1237     return;
1238 
1239   bool dev_tools_enabled = DevToolsWindow::AllowDevToolsFor(
1240       profile(), browser_->tab_strip_model()->GetActiveWebContents());
1241   command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS, dev_tools_enabled);
1242   command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS_CONSOLE,
1243                                         dev_tools_enabled);
1244   command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS_DEVICES,
1245                                         dev_tools_enabled);
1246   command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS_INSPECT,
1247                                         dev_tools_enabled);
1248   command_updater_.UpdateCommandEnabled(IDC_DEV_TOOLS_TOGGLE,
1249                                         dev_tools_enabled);
1250 #if defined(OS_MAC)
1251   command_updater_.UpdateCommandEnabled(IDC_TOGGLE_JAVASCRIPT_APPLE_EVENTS,
1252                                         dev_tools_enabled);
1253 #endif
1254 }
1255 
UpdateCommandsForBookmarkEditing()1256 void BrowserCommandController::UpdateCommandsForBookmarkEditing() {
1257   if (is_locked_fullscreen_)
1258     return;
1259 
1260   command_updater_.UpdateCommandEnabled(IDC_BOOKMARK_THIS_TAB,
1261                                         CanBookmarkCurrentTab(browser_));
1262   command_updater_.UpdateCommandEnabled(IDC_BOOKMARK_ALL_TABS,
1263                                         CanBookmarkAllTabs(browser_));
1264 #if defined(OS_WIN)
1265   command_updater_.UpdateCommandEnabled(IDC_PIN_TO_START_SCREEN, true);
1266 #endif
1267 }
1268 
UpdateCommandsForBookmarkBar()1269 void BrowserCommandController::UpdateCommandsForBookmarkBar() {
1270   if (is_locked_fullscreen_)
1271     return;
1272 
1273   command_updater_.UpdateCommandEnabled(
1274       IDC_SHOW_BOOKMARK_BAR, browser_defaults::bookmarks_enabled &&
1275                                  !profile()->IsGuestSession() &&
1276                                  !profile()->IsEphemeralGuestProfile() &&
1277                                  !profile()->IsSystemProfile() &&
1278                                  !profile()->GetPrefs()->IsManagedPreference(
1279                                      bookmarks::prefs::kShowBookmarkBar) &&
1280                                  IsShowingMainUI());
1281 }
1282 
UpdateCommandsForFileSelectionDialogs()1283 void BrowserCommandController::UpdateCommandsForFileSelectionDialogs() {
1284   if (is_locked_fullscreen_)
1285     return;
1286 
1287   UpdateSaveAsState();
1288   UpdateOpenFileState(&command_updater_);
1289 }
1290 
UpdateCommandsForFullscreenMode()1291 void BrowserCommandController::UpdateCommandsForFullscreenMode() {
1292   if (is_locked_fullscreen_)
1293     return;
1294 
1295   const bool is_fullscreen = window() && window()->IsFullscreen();
1296   const bool show_main_ui = IsShowingMainUI();
1297   const bool show_location_bar = IsShowingLocationBar();
1298 
1299   const bool main_not_fullscreen = show_main_ui && !is_fullscreen;
1300 
1301   // Navigation commands
1302   command_updater_.UpdateCommandEnabled(IDC_OPEN_CURRENT_URL, show_main_ui);
1303 
1304   // Window management commands
1305   command_updater_.UpdateCommandEnabled(
1306       IDC_SHOW_AS_TAB, !browser_->is_type_normal() && !is_fullscreen);
1307 
1308   // Focus various bits of UI
1309   command_updater_.UpdateCommandEnabled(IDC_FOCUS_TOOLBAR, show_main_ui);
1310   command_updater_.UpdateCommandEnabled(IDC_FOCUS_LOCATION, show_location_bar);
1311   command_updater_.UpdateCommandEnabled(IDC_FOCUS_SEARCH, show_main_ui);
1312   command_updater_.UpdateCommandEnabled(IDC_FOCUS_MENU_BAR,
1313                                         main_not_fullscreen);
1314   command_updater_.UpdateCommandEnabled(IDC_FOCUS_NEXT_PANE,
1315                                         main_not_fullscreen);
1316   command_updater_.UpdateCommandEnabled(IDC_FOCUS_PREVIOUS_PANE,
1317                                         main_not_fullscreen);
1318   command_updater_.UpdateCommandEnabled(IDC_FOCUS_BOOKMARKS,
1319                                         main_not_fullscreen);
1320   command_updater_.UpdateCommandEnabled(
1321       IDC_FOCUS_INACTIVE_POPUP_FOR_ACCESSIBILITY, main_not_fullscreen);
1322 
1323   // Show various bits of UI
1324   command_updater_.UpdateCommandEnabled(IDC_DEVELOPER_MENU, show_main_ui);
1325 #if BUILDFLAG(GOOGLE_CHROME_BRANDING)
1326   command_updater_.UpdateCommandEnabled(
1327       IDC_FEEDBACK, show_main_ui || browser_->is_type_devtools());
1328 #endif
1329   UpdateShowSyncState(show_main_ui);
1330 
1331   command_updater_.UpdateCommandEnabled(IDC_EDIT_SEARCH_ENGINES, show_main_ui);
1332   command_updater_.UpdateCommandEnabled(IDC_VIEW_PASSWORDS, show_main_ui);
1333   command_updater_.UpdateCommandEnabled(IDC_ABOUT, show_main_ui);
1334   command_updater_.UpdateCommandEnabled(IDC_QRCODE_GENERATOR, show_main_ui);
1335   command_updater_.UpdateCommandEnabled(IDC_SHOW_APP_MENU, show_main_ui);
1336   command_updater_.UpdateCommandEnabled(IDC_SEND_TAB_TO_SELF, show_main_ui);
1337   command_updater_.UpdateCommandEnabled(IDC_SEND_TAB_TO_SELF_SINGLE_TARGET,
1338                                         show_main_ui);
1339   command_updater_.UpdateCommandEnabled(IDC_SHOW_MANAGEMENT_PAGE, true);
1340 
1341   if (base::debug::IsProfilingSupported())
1342     command_updater_.UpdateCommandEnabled(IDC_PROFILING_ENABLED, show_main_ui);
1343 
1344 #if !defined(OS_MAC)
1345   // Disable toggling into fullscreen mode if disallowed by pref.
1346   const bool fullscreen_enabled =
1347       is_fullscreen ||
1348       profile()->GetPrefs()->GetBoolean(prefs::kFullscreenAllowed);
1349 #else
1350   const bool fullscreen_enabled = true;
1351 #endif
1352 
1353   command_updater_.UpdateCommandEnabled(IDC_FULLSCREEN, fullscreen_enabled);
1354   command_updater_.UpdateCommandEnabled(IDC_TOGGLE_FULLSCREEN_TOOLBAR,
1355                                         fullscreen_enabled);
1356 
1357   UpdateCommandsForBookmarkBar();
1358   UpdateCommandsForIncognitoAvailability();
1359   UpdateCommandsForHostedAppAvailability();
1360 }
1361 
UpdateCommandsForHostedAppAvailability()1362 void BrowserCommandController::UpdateCommandsForHostedAppAvailability() {
1363   bool has_toolbar =
1364       browser_->is_type_normal() ||
1365       web_app::AppBrowserController::IsForWebAppBrowser(browser_);
1366   if (window() && window()->ShouldHideUIForFullscreen())
1367     has_toolbar = false;
1368   command_updater_.UpdateCommandEnabled(IDC_FOCUS_TOOLBAR, has_toolbar);
1369   command_updater_.UpdateCommandEnabled(IDC_FOCUS_NEXT_PANE, has_toolbar);
1370   command_updater_.UpdateCommandEnabled(IDC_FOCUS_PREVIOUS_PANE, has_toolbar);
1371   command_updater_.UpdateCommandEnabled(IDC_SHOW_APP_MENU, has_toolbar);
1372 }
1373 
1374 #if defined(OS_CHROMEOS)
1375 namespace {
1376 
1377 #if DCHECK_IS_ON()
1378 // Makes sure that all commands that are not allowlisted are disabled. DCHECKs
1379 // otherwise. Compiled only in debug mode.
NonAllowlistedCommandsAreDisabled(CommandUpdaterImpl * command_updater)1380 void NonAllowlistedCommandsAreDisabled(CommandUpdaterImpl* command_updater) {
1381   constexpr int kAllowlistedIds[] = {IDC_CUT, IDC_COPY, IDC_PASTE};
1382 
1383   // Go through all the command ids, skip the allowlisted ones.
1384   for (int id : command_updater->GetAllIds()) {
1385     if (base::Contains(kAllowlistedIds, id)) {
1386       continue;
1387     }
1388     DCHECK(!command_updater->IsCommandEnabled(id));
1389   }
1390 }
1391 #endif
1392 
1393 }  // namespace
1394 
UpdateCommandsForLockedFullscreenMode()1395 void BrowserCommandController::UpdateCommandsForLockedFullscreenMode() {
1396   bool is_locked_fullscreen =
1397       platform_util::IsBrowserLockedFullscreen(browser_);
1398   // Sanity check to make sure this function is called only on state change.
1399   DCHECK_NE(is_locked_fullscreen, is_locked_fullscreen_);
1400   if (is_locked_fullscreen == is_locked_fullscreen_)
1401     return;
1402   is_locked_fullscreen_ = is_locked_fullscreen;
1403 
1404   if (is_locked_fullscreen_) {
1405     command_updater_.DisableAllCommands();
1406     // Update the state of allowlisted commands:
1407     // IDC_CUT/IDC_COPY/IDC_PASTE,
1408     UpdateCommandsForContentRestrictionState();
1409     // TODO(crbug.com/904637): Re-enable Find and Zoom in locked fullscreen.
1410     // All other commands will be disabled (there is an early return in their
1411     // corresponding UpdateCommandsFor* functions).
1412 #if DCHECK_IS_ON()
1413     NonAllowlistedCommandsAreDisabled(&command_updater_);
1414 #endif
1415   } else {
1416     // Do an init call to re-initialize command state after the
1417     // DisableAllCommands.
1418     InitCommandState();
1419   }
1420 }
1421 #endif
1422 
UpdatePrintingState()1423 void BrowserCommandController::UpdatePrintingState() {
1424   if (is_locked_fullscreen_)
1425     return;
1426 
1427   bool print_enabled = CanPrint(browser_);
1428   command_updater_.UpdateCommandEnabled(IDC_PRINT, print_enabled);
1429 #if BUILDFLAG(ENABLE_PRINTING)
1430   command_updater_.UpdateCommandEnabled(IDC_BASIC_PRINT,
1431                                         CanBasicPrint(browser_));
1432 #endif
1433 }
1434 
UpdateSaveAsState()1435 void BrowserCommandController::UpdateSaveAsState() {
1436   if (is_locked_fullscreen_)
1437     return;
1438 
1439   command_updater_.UpdateCommandEnabled(IDC_SAVE_PAGE, CanSavePage(browser_));
1440 }
1441 
UpdateShowSyncState(bool show_main_ui)1442 void BrowserCommandController::UpdateShowSyncState(bool show_main_ui) {
1443   if (is_locked_fullscreen_)
1444     return;
1445 
1446   command_updater_.UpdateCommandEnabled(
1447       IDC_SHOW_SIGNIN, show_main_ui && pref_signin_allowed_.GetValue());
1448 }
1449 
1450 // static
UpdateOpenFileState(CommandUpdater * command_updater)1451 void BrowserCommandController::UpdateOpenFileState(
1452     CommandUpdater* command_updater) {
1453   bool enabled = true;
1454   PrefService* local_state = g_browser_process->local_state();
1455   if (local_state)
1456     enabled = local_state->GetBoolean(prefs::kAllowFileSelectionDialogs);
1457 
1458   command_updater->UpdateCommandEnabled(IDC_OPEN_FILE, enabled);
1459 }
1460 
UpdateReloadStopState(bool is_loading,bool force)1461 void BrowserCommandController::UpdateReloadStopState(bool is_loading,
1462                                                      bool force) {
1463   if (is_locked_fullscreen_)
1464     return;
1465 
1466   window()->UpdateReloadStopState(is_loading, force);
1467   command_updater_.UpdateCommandEnabled(IDC_STOP, is_loading);
1468   UpdateCloseFindOrStop();
1469 }
1470 
UpdateTabRestoreCommandState()1471 void BrowserCommandController::UpdateTabRestoreCommandState() {
1472   if (is_locked_fullscreen_)
1473     return;
1474 
1475   sessions::TabRestoreService* tab_restore_service =
1476       TabRestoreServiceFactory::GetForProfile(profile());
1477   // The command is enabled if the service hasn't loaded yet to trigger loading.
1478   // The command is updated once the load completes.
1479   command_updater_.UpdateCommandEnabled(
1480       IDC_RESTORE_TAB,
1481       tab_restore_service && (!tab_restore_service->IsLoaded() ||
1482                               !tab_restore_service->entries().empty()));
1483 }
1484 
UpdateCommandsForFind()1485 void BrowserCommandController::UpdateCommandsForFind() {
1486   TabStripModel* model = browser_->tab_strip_model();
1487   bool enabled = !model->IsTabBlocked(model->active_index()) &&
1488                  !browser_->is_type_devtools();
1489 
1490   command_updater_.UpdateCommandEnabled(IDC_FIND, enabled);
1491   command_updater_.UpdateCommandEnabled(IDC_FIND_NEXT, enabled);
1492   command_updater_.UpdateCommandEnabled(IDC_FIND_PREVIOUS, enabled);
1493 }
1494 
UpdateCloseFindOrStop()1495 void BrowserCommandController::UpdateCloseFindOrStop() {
1496   bool enabled = CanCloseFind(browser_) || IsCommandEnabled(IDC_STOP);
1497   command_updater_.UpdateCommandEnabled(IDC_CLOSE_FIND_OR_STOP, enabled);
1498 }
1499 
UpdateCommandsForMediaRouter()1500 void BrowserCommandController::UpdateCommandsForMediaRouter() {
1501   if (is_locked_fullscreen_)
1502     return;
1503 
1504   command_updater_.UpdateCommandEnabled(IDC_ROUTE_MEDIA,
1505                                         CanRouteMedia(browser_));
1506 }
1507 
UpdateCommandsForTabKeyboardFocus(base::Optional<int> target_index)1508 void BrowserCommandController::UpdateCommandsForTabKeyboardFocus(
1509     base::Optional<int> target_index) {
1510   command_updater_.UpdateCommandEnabled(
1511       IDC_DUPLICATE_TARGET_TAB, !browser_->deprecated_is_app() &&
1512                                     target_index.has_value() &&
1513                                     CanDuplicateTabAt(browser_, *target_index));
1514   const bool normal_window = browser_->is_type_normal();
1515   command_updater_.UpdateCommandEnabled(
1516       IDC_MUTE_TARGET_SITE, normal_window && target_index.has_value());
1517   command_updater_.UpdateCommandEnabled(
1518       IDC_PIN_TARGET_TAB, normal_window && target_index.has_value());
1519   command_updater_.UpdateCommandEnabled(
1520       IDC_GROUP_TARGET_TAB, normal_window && target_index.has_value());
1521 }
1522 
UpdateCommandsForWebContentsFocus()1523 void BrowserCommandController::UpdateCommandsForWebContentsFocus() {
1524 #if defined(OS_MAC)
1525   // On Mac, toggling caret browsing changes whether it's enabled or not
1526   // based on web contents focus.
1527   command_updater_.UpdateCommandEnabled(IDC_CARET_BROWSING_TOGGLE,
1528                                         CanToggleCaretBrowsing(browser_));
1529 #endif  // defined(OS_MAC)
1530 }
1531 
window()1532 BrowserWindow* BrowserCommandController::window() {
1533   return browser_->window();
1534 }
1535 
profile()1536 Profile* BrowserCommandController::profile() {
1537   return browser_->profile();
1538 }
1539 
1540 }  // namespace chrome
1541