[iOS] Remove IDC_VOICE_SEARCH command.

Bug: 738881
Change-Id: Id0ead6ad3126294274e53cf58c94ee6e49602285
Reviewed-on: https://chromium-review.googlesource.com/589927
Reviewed-by: Mark Cogan <[email protected]>
Reviewed-by: Kurt Horimoto <[email protected]>
Commit-Queue: Jean-François Geyelin <[email protected]>
Cr-Commit-Position: refs/heads/master@{#490490}
diff --git a/ios/chrome/app/main_controller.mm b/ios/chrome/app/main_controller.mm
index bcb6041..457976d 100644
--- a/ios/chrome/app/main_controller.mm
+++ b/ios/chrome/app/main_controller.mm
@@ -109,6 +109,7 @@
 #import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
 #import "ios/chrome/browser/ui/commands/open_url_command.h"
 #import "ios/chrome/browser/ui/commands/show_signin_command.h"
+#import "ios/chrome/browser/ui/commands/start_voice_search_command.h"
 #import "ios/chrome/browser/ui/downloads/download_manager_controller.h"
 #import "ios/chrome/browser/ui/first_run/first_run_util.h"
 #import "ios/chrome/browser/ui/first_run/welcome_to_chrome_view_controller.h"
@@ -385,7 +386,7 @@
 // Shows the tab switcher UI.
 - (void)showTabSwitcher;
 // Starts a voice search on the current BVC.
-- (void)startVoiceSearch;
+- (void)startVoiceSearchInCurrentBVCWithOriginView:(UIView*)originView;
 // Dismisses the tab switcher UI without animation into the given model.
 - (void)dismissTabSwitcherWithoutAnimationInModel:(TabModel*)tabModel;
 // Dismisses and clears |signinInteractionController|.
@@ -1360,6 +1361,18 @@
   [self.currentBVC.dispatcher openNewTab:command];
 }
 
+- (void)startVoiceSearch:(StartVoiceSearchCommand*)command {
+  if (!_isProcessingTabSwitcherCommand) {
+    [self startVoiceSearchInCurrentBVCWithOriginView:command.originView];
+    _isProcessingVoiceSearchCommand = YES;
+    dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
+                                 kExpectedTransitionDurationInNanoSeconds),
+                   dispatch_get_main_queue(), ^{
+                     _isProcessingVoiceSearchCommand = NO;
+                   });
+  }
+}
+
 #pragma mark - chromeExecuteCommand
 
 - (IBAction)chromeExecuteCommand:(id)sender {
@@ -1418,15 +1431,9 @@
       [self.currentBVC chromeExecuteCommand:sender];
       break;
     case IDC_VOICE_SEARCH: {
-      if (!_isProcessingTabSwitcherCommand) {
-        [self startVoiceSearch];
-        _isProcessingVoiceSearchCommand = YES;
-        dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
-                                     kExpectedTransitionDurationInNanoSeconds),
-                       dispatch_get_main_queue(), ^{
-                         _isProcessingVoiceSearchCommand = NO;
-                       });
-      }
+      StartVoiceSearchCommand* command =
+          [[StartVoiceSearchCommand alloc] initWithOriginView:nil];
+      [self startVoiceSearch:command];
     } break;
 
     case IDC_CLEAR_BROWSING_DATA_IOS: {
@@ -1502,15 +1509,15 @@
   [self closeSettingsAnimated:YES completion:completion];
 }
 
-- (void)startVoiceSearch {
+- (void)startVoiceSearchInCurrentBVCWithOriginView:(UIView*)originView {
   // If the background (non-current) BVC is playing TTS audio, call
   // -startVoiceSearch on it to stop the TTS.
   BrowserViewController* backgroundBVC =
       self.mainBVC == self.currentBVC ? self.otrBVC : self.mainBVC;
   if (backgroundBVC.playingTTS)
-    [backgroundBVC startVoiceSearch];
+    [backgroundBVC startVoiceSearchWithOriginView:originView];
   else
-    [self.currentBVC startVoiceSearch];
+    [self.currentBVC startVoiceSearchWithOriginView:originView];
 }
 
 #pragma mark - Preferences Management
@@ -1829,7 +1836,7 @@
   // current BVC.
   if (self.startVoiceSearchAfterTabSwitcherDismissal) {
     self.startVoiceSearchAfterTabSwitcherDismissal = NO;
-    [self.currentBVC startVoiceSearch];
+    [self.currentBVC startVoiceSearchWithOriginView:nil];
   } else if (self.startQRScannerAfterTabSwitcherDismissal) {
     self.startQRScannerAfterTabSwitcherDismissal = NO;
     [self.currentBVC.dispatcher showQRScanner];
@@ -2190,7 +2197,7 @@
   ProceduralBlock tabOpenedCompletion;
   if ([_startupParameters launchVoiceSearch]) {
     tabOpenedCompletion = ^{
-      [self startVoiceSearch];
+      [self startVoiceSearchInCurrentBVCWithOriginView:nil];
     };
   }
   if ([_startupParameters launchQRScanner]) {
diff --git a/ios/chrome/browser/ui/browser_view_controller.h b/ios/chrome/browser/ui/browser_view_controller.h
index d9c0a89..0305dcf8 100644
--- a/ios/chrome/browser/ui/browser_view_controller.h
+++ b/ios/chrome/browser/ui/browser_view_controller.h
@@ -136,8 +136,9 @@
 // related to showing the previously selected tab.
 - (void)expectNewForegroundTab;
 
-// Shows the voice search UI.
-- (void)startVoiceSearch;
+// Shows the voice search UI. |originView|'s center is used for the presentation
+// and dismissal animations of the Voice Search UI. |originView| can be nil.
+- (void)startVoiceSearchWithOriginView:(UIView*)originView;
 
 // Focuses the omnibox.
 - (void)focusOmnibox;
diff --git a/ios/chrome/browser/ui/browser_view_controller.mm b/ios/chrome/browser/ui/browser_view_controller.mm
index 16311d42..4b4d7e8 100644
--- a/ios/chrome/browser/ui/browser_view_controller.mm
+++ b/ios/chrome/browser/ui/browser_view_controller.mm
@@ -110,6 +110,7 @@
 #import "ios/chrome/browser/ui/commands/open_url_command.h"
 #import "ios/chrome/browser/ui/commands/reading_list_add_command.h"
 #import "ios/chrome/browser/ui/commands/show_mail_composer_command.h"
+#import "ios/chrome/browser/ui/commands/start_voice_search_command.h"
 #import "ios/chrome/browser/ui/context_menu/context_menu_coordinator.h"
 #import "ios/chrome/browser/ui/dialogs/dialog_presenter.h"
 #import "ios/chrome/browser/ui/dialogs/java_script_dialog_presenter_impl.h"
@@ -1572,7 +1573,7 @@
   ProceduralBlock startVoiceSearchIfNecessaryBlock = ^void() {
     if (_startVoiceSearchAfterNewTabAnimation) {
       _startVoiceSearchAfterNewTabAnimation = NO;
-      [self startVoiceSearch];
+      [self startVoiceSearchWithOriginView:nil];
     }
   };
 
@@ -2355,7 +2356,7 @@
   CGRect frame = CGRectMake(0.0, y, width, kVoiceSearchBarHeight);
   _voiceSearchBar = ios::GetChromeBrowserProvider()
                         ->GetVoiceSearchProvider()
-                        ->BuildVoiceSearchBar(frame);
+                        ->BuildVoiceSearchBar(frame, self.dispatcher);
   [_voiceSearchBar setVoiceSearchBarDelegate:self];
   [_voiceSearchBar setHidden:YES];
   [_voiceSearchBar setAutoresizingMask:UIViewAutoresizingFlexibleTopMargin |
@@ -4223,13 +4224,13 @@
     case IDC_SHOW_READING_LIST:
       [self showReadingList];
       break;
-    case IDC_VOICE_SEARCH:
+    case IDC_VOICE_SEARCH: {
       // If the voice search command is coming from a UIView sender, store it
       // before sending the command up the responder chain.
-      if ([sender isKindOfClass:[UIView class]])
-        _voiceSearchButton = sender;
-      [super chromeExecuteCommand:sender];
-      break;
+      StartVoiceSearchCommand* command = [[StartVoiceSearchCommand alloc]
+          initWithOriginView:base::mac::ObjCCast<UIView>(sender)];
+      [self.dispatcher startVoiceSearch:command];
+    } break;
     default:
       // Unknown commands get sent up the responder chain.
       [super chromeExecuteCommand:sender];
@@ -4542,7 +4543,8 @@
 }
 #endif  // !defined(NDEBUG)
 
-- (void)startVoiceSearch {
+- (void)startVoiceSearchWithOriginView:(UIView*)originView {
+  _voiceSearchButton = originView;
   // Delay Voice Search until new tab animations have finished.
   if (self.inNewTabAnimation) {
     _startVoiceSearchAfterNewTabAnimation = YES;
diff --git a/ios/chrome/browser/ui/commands/BUILD.gn b/ios/chrome/browser/ui/commands/BUILD.gn
index 1da2ed3f..fb70574 100644
--- a/ios/chrome/browser/ui/commands/BUILD.gn
+++ b/ios/chrome/browser/ui/commands/BUILD.gn
@@ -24,6 +24,8 @@
     "show_mail_composer_command.mm",
     "show_signin_command.h",
     "show_signin_command.mm",
+    "start_voice_search_command.h",
+    "start_voice_search_command.mm",
   ]
   deps = [
     "//base",
diff --git a/ios/chrome/browser/ui/commands/application_commands.h b/ios/chrome/browser/ui/commands/application_commands.h
index 48eec6bc..f0bfd72a 100644
--- a/ios/chrome/browser/ui/commands/application_commands.h
+++ b/ios/chrome/browser/ui/commands/application_commands.h
@@ -8,6 +8,7 @@
 #import <Foundation/Foundation.h>
 
 @class OpenNewTabCommand;
+@class StartVoiceSearchCommand;
 
 // This protocol groups commands that are part of ApplicationCommands, but
 // may also be forwarded directly to a settings navigation controller.
@@ -35,6 +36,9 @@
 // the type of tab to open.
 - (void)switchModesAndOpenNewTab:(OpenNewTabCommand*)newTabCommand;
 
+// Starts a voice search on the current BVC.
+- (void)startVoiceSearch:(StartVoiceSearchCommand*)command;
+
 @end
 
 #endif  // IOS_CHROME_BROWSER_UI_COMMANDS_APPLICATION_COMMANDS_H_
diff --git a/ios/chrome/browser/ui/commands/start_voice_search_command.h b/ios/chrome/browser/ui/commands/start_voice_search_command.h
new file mode 100644
index 0000000..3d49385d
--- /dev/null
+++ b/ios/chrome/browser/ui/commands/start_voice_search_command.h
@@ -0,0 +1,24 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_CHROME_BROWSER_UI_COMMANDS_START_VOICE_SEARCH_COMMAND_H_
+#define IOS_CHROME_BROWSER_UI_COMMANDS_START_VOICE_SEARCH_COMMAND_H_
+
+#import <UIKit/UIKit.h>
+
+#import "ios/chrome/browser/ui/commands/generic_chrome_command.h"
+
+// Command sent to start a voice search, optionally including the view from
+// which the voice search present and dismiss animations will occur.
+@interface StartVoiceSearchCommand : GenericChromeCommand
+
+- (instancetype)initWithOriginView:(UIView*)view NS_DESIGNATED_INITIALIZER;
+
+- (instancetype)initWithTag:(NSInteger)tag NS_UNAVAILABLE;
+
+@property(nonatomic, readonly) UIView* originView;
+
+@end
+
+#endif  // IOS_CHROME_BROWSER_UI_COMMANDS_START_VOICE_SEARCH_COMMAND_H_
\ No newline at end of file
diff --git a/ios/chrome/browser/ui/commands/start_voice_search_command.mm b/ios/chrome/browser/ui/commands/start_voice_search_command.mm
new file mode 100644
index 0000000..b075bdb
--- /dev/null
+++ b/ios/chrome/browser/ui/commands/start_voice_search_command.mm
@@ -0,0 +1,22 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/chrome/browser/ui/commands/start_voice_search_command.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+@implementation StartVoiceSearchCommand
+
+@synthesize originView = _originView;
+
+- (instancetype)initWithOriginView:(UIView*)originView {
+  if ((self = [super initWithTag:0])) {
+    _originView = originView;
+  }
+  return self;
+}
+
+@end
\ No newline at end of file
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.mm
index ba8d52c..8280db87 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.mm
@@ -7,7 +7,6 @@
 #include "base/i18n/rtl.h"
 #include "base/logging.h"
 #include "components/strings/grit/components_strings.h"
-#include "ios/chrome/browser/ui/commands/ios_command_ids.h"
 #import "ios/chrome/browser/ui/content_suggestions/cells/content_suggestions_most_visited_cell.h"
 #import "ios/chrome/browser/ui/toolbar/web_toolbar_controller.h"
 #include "ios/chrome/browser/ui/ui_util.h"
@@ -172,7 +171,6 @@
 
   [voiceSearchButton setAdjustsImageWhenHighlighted:NO];
   [voiceSearchButton setImage:micImage forState:UIControlStateNormal];
-  [voiceSearchButton setTag:IDC_VOICE_SEARCH];
   [voiceSearchButton setAccessibilityLabel:l10n_util::GetNSString(
                                                IDS_IOS_ACCNAME_VOICE_SEARCH)];
   [voiceSearchButton setAccessibilityIdentifier:@"Voice Search"];
diff --git a/ios/chrome/browser/ui/key_commands_provider.mm b/ios/chrome/browser/ui/key_commands_provider.mm
index 8947b51..c907932 100644
--- a/ios/chrome/browser/ui/key_commands_provider.mm
+++ b/ios/chrome/browser/ui/key_commands_provider.mm
@@ -9,6 +9,7 @@
 #import "ios/chrome/browser/ui/commands/generic_chrome_command.h"
 #include "ios/chrome/browser/ui/commands/ios_command_ids.h"
 #import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
+#include "ios/chrome/browser/ui/commands/start_voice_search_command.h"
 #import "ios/chrome/browser/ui/keyboard/UIKeyCommand+Chrome.h"
 #include "ios/chrome/browser/ui/rtl_geometry.h"
 #include "ios/chrome/grit/ios_strings.h"
@@ -195,7 +196,10 @@
                    modifierFlags:UIKeyModifierCommand | UIKeyModifierShift
                            title:voiceSearchTitle
                           action:^{
-                            execute(IDC_VOICE_SEARCH);
+                            StartVoiceSearchCommand* command =
+                                [[StartVoiceSearchCommand alloc]
+                                    initWithOriginView:nil];
+                            [weakDispatcher startVoiceSearch:command];
                           }],
     ]];
   }
diff --git a/ios/chrome/browser/ui/ntp/google_landing_view_controller.h b/ios/chrome/browser/ui/ntp/google_landing_view_controller.h
index d44e4a2..6d72fa0 100644
--- a/ios/chrome/browser/ui/ntp/google_landing_view_controller.h
+++ b/ios/chrome/browser/ui/ntp/google_landing_view_controller.h
@@ -14,6 +14,7 @@
 #import "ios/chrome/browser/ui/toolbar/toolbar_owner.h"
 #import "ios/public/provider/chrome/browser/voice/logo_animation_controller.h"
 
+@protocol ApplicationCommands;
 @protocol BrowserCommands;
 @protocol GoogleLandingDataSource;
 @protocol OmniboxFocuser;
@@ -28,8 +29,9 @@
 
 @property(nonatomic, weak) id<GoogleLandingDataSource> dataSource;
 
-@property(nonatomic, weak) id<BrowserCommands, OmniboxFocuser, UrlLoader>
-    dispatcher;
+@property(nonatomic, weak)
+    id<ApplicationCommands, BrowserCommands, OmniboxFocuser, UrlLoader>
+        dispatcher;
 
 @end
 
diff --git a/ios/chrome/browser/ui/ntp/google_landing_view_controller.mm b/ios/chrome/browser/ui/ntp/google_landing_view_controller.mm
index 03c15fa..ef89bbd 100644
--- a/ios/chrome/browser/ui/ntp/google_landing_view_controller.mm
+++ b/ios/chrome/browser/ui/ntp/google_landing_view_controller.mm
@@ -11,10 +11,12 @@
 #include "base/strings/sys_string_conversions.h"
 #include "components/strings/grit/components_strings.h"
 #import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h"
+#import "ios/chrome/browser/ui/commands/application_commands.h"
 #import "ios/chrome/browser/ui/commands/browser_commands.h"
 #import "ios/chrome/browser/ui/commands/generic_chrome_command.h"
 #include "ios/chrome/browser/ui/commands/ios_command_ids.h"
 #import "ios/chrome/browser/ui/commands/open_new_tab_command.h"
+#import "ios/chrome/browser/ui/commands/start_voice_search_command.h"
 #import "ios/chrome/browser/ui/constraints_ui_util.h"
 #import "ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_utils.h"
 #import "ios/chrome/browser/ui/context_menu/context_menu_coordinator.h"
@@ -117,7 +119,8 @@
   NewTabPageHeaderView* _headerView;
   WhatsNewHeaderView* _promoHeaderView;
   __weak id<GoogleLandingDataSource> _dataSource;
-  __weak id<UrlLoader, OmniboxFocuser> _dispatcher;
+  __weak id<ApplicationCommands, BrowserCommands, UrlLoader, OmniboxFocuser>
+      _dispatcher;
 }
 
 // Whether the Google logo or doodle is being shown.
@@ -207,6 +210,7 @@
 
 @implementation GoogleLandingViewController
 
+@synthesize dispatcher = _dispatcher;
 @synthesize logoVendor = _logoVendor;
 // Property declared in NewTabPagePanelProtocol.
 @synthesize delegate = _delegate;
@@ -321,14 +325,6 @@
   _dataSource = dataSource;
 }
 
-- (id<UrlLoader, OmniboxFocuser>)dispatcher {
-  return _dispatcher;
-}
-
-- (void)setDispatcher:(id<UrlLoader, OmniboxFocuser>)dispatcher {
-  _dispatcher = dispatcher;
-}
-
 #pragma mark - Private
 
 - (CGSize)mostVisitedCellSize {
@@ -441,7 +437,10 @@
 - (void)loadVoiceSearch:(id)sender {
   DCHECK(self.voiceSearchIsEnabled);
   base::RecordAction(UserMetricsAction("MobileNTPMostVisitedVoiceSearch"));
-  [sender chromeExecuteCommand:sender];
+  UIView* view = base::mac::ObjCCastStrict<UIView>(sender);
+  StartVoiceSearchCommand* command =
+      [[StartVoiceSearchCommand alloc] initWithOriginView:view];
+  [self.dispatcher startVoiceSearch:command];
 }
 
 - (void)preloadVoiceSearch:(id)sender {
diff --git a/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm b/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm
index 0cf6521..8f75075d1 100644
--- a/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm
+++ b/ios/chrome/browser/ui/toolbar/web_toolbar_controller.mm
@@ -38,9 +38,11 @@
 #import "ios/chrome/browser/ui/animation_util.h"
 #import "ios/chrome/browser/ui/colors/MDCPalette+CrAdditions.h"
 #import "ios/chrome/browser/ui/commands/UIKit+ChromeExecuteCommand.h"
+#import "ios/chrome/browser/ui/commands/application_commands.h"
 #import "ios/chrome/browser/ui/commands/browser_commands.h"
 #import "ios/chrome/browser/ui/commands/generic_chrome_command.h"
 #include "ios/chrome/browser/ui/commands/ios_command_ids.h"
+#include "ios/chrome/browser/ui/commands/start_voice_search_command.h"
 #import "ios/chrome/browser/ui/history/tab_history_popup_controller.h"
 #import "ios/chrome/browser/ui/image_util.h"
 #include "ios/chrome/browser/ui/omnibox/location_bar_controller_impl.h"
@@ -508,6 +510,9 @@
     [_voiceSearchButton
         setAutoresizingMask:UIViewAutoresizingFlexibleBottomMargin |
                             UIViewAutoresizingFlexibleLeadingMargin()];
+    [_voiceSearchButton addTarget:self
+                           action:@selector(toolbarVoiceSearchButtonPressed:)
+                 forControlEvents:UIControlEventTouchUpInside];
 
     // Assign tags before calling -setUpButton, since only buttons with tags
     // have -chromeExecuteCommand added as a target.
@@ -1477,9 +1482,9 @@
           ->GetVoiceSearchProvider()
           ->IsVoiceSearchEnabled()) {
     base::RecordAction(UserMetricsAction("MobileCustomRowVoiceSearch"));
-    GenericChromeCommand* command =
-        [[GenericChromeCommand alloc] initWithTag:IDC_VOICE_SEARCH];
-    [view chromeExecuteCommand:command];
+    StartVoiceSearchCommand* command =
+        [[StartVoiceSearchCommand alloc] initWithOriginView:view];
+    [self.dispatcher startVoiceSearch:command];
   }
 }
 
@@ -1521,6 +1526,17 @@
   [self cancelOmniboxEdit];
 }
 
+- (void)toolbarVoiceSearchButtonPressed:(id)sender {
+  if (ios::GetChromeBrowserProvider()
+          ->GetVoiceSearchProvider()
+          ->IsVoiceSearchEnabled()) {
+    UIView* view = base::mac::ObjCCastStrict<UIView>(sender);
+    StartVoiceSearchCommand* command =
+        [[StartVoiceSearchCommand alloc] initWithOriginView:view];
+    [self.dispatcher startVoiceSearch:command];
+  }
+}
+
 - (void)layoutCancelButton {
   CGFloat height = CGRectGetHeight([self specificControlsArea]) -
                    kCancelButtonTopMargin - kCancelButtonBottomMargin;
diff --git a/ios/public/provider/chrome/browser/voice/voice_search_provider.h b/ios/public/provider/chrome/browser/voice/voice_search_provider.h
index 0e7eeea..b47ee07 100644
--- a/ios/public/provider/chrome/browser/voice/voice_search_provider.h
+++ b/ios/public/provider/chrome/browser/voice/voice_search_provider.h
@@ -11,6 +11,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 
+@protocol ApplicationCommands;
 class AudioSessionController;
 @protocol VoiceSearchBar;
 class VoiceSearchController;
@@ -43,6 +44,12 @@
   // Creates a new VoiceSearchBar.  Returns an autoreleased view.
   virtual UIView<VoiceSearchBar>* BuildVoiceSearchBar(CGRect frame) const;
 
+  // Creates a new VoiceSearchBar which uses |dispatcher| to send commands.
+  // Returns an autoreleased view.
+  virtual UIView<VoiceSearchBar>* BuildVoiceSearchBar(
+      CGRect frame,
+      id<ApplicationCommands> dispatcher) const;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(VoiceSearchProvider);
 };
diff --git a/ios/public/provider/chrome/browser/voice/voice_search_provider.mm b/ios/public/provider/chrome/browser/voice/voice_search_provider.mm
index 9bdb216..52d979d 100644
--- a/ios/public/provider/chrome/browser/voice/voice_search_provider.mm
+++ b/ios/public/provider/chrome/browser/voice/voice_search_provider.mm
@@ -32,3 +32,9 @@
     CGRect frame) const {
   return nil;
 }
+
+UIView<VoiceSearchBar>* VoiceSearchProvider::BuildVoiceSearchBar(
+    CGRect frame,
+    id<ApplicationCommands> dispatcher) const {
+  return BuildVoiceSearchBar(frame);
+}