Home | History | Annotate | Download | only in automation
      1 // Copyright (c) 2011 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/automation/testing_automation_provider.h"
      6 
      7 #include <map>
      8 #include <set>
      9 #include <string>
     10 #include <vector>
     11 
     12 #include "base/command_line.h"
     13 #include "base/file_path.h"
     14 #include "base/json/json_reader.h"
     15 #include "base/json/json_writer.h"
     16 #include "base/json/string_escape.h"
     17 #include "base/path_service.h"
     18 #include "base/process.h"
     19 #include "base/process_util.h"
     20 #include "base/stringprintf.h"
     21 #include "base/threading/thread_restrictions.h"
     22 #include "base/time.h"
     23 #include "base/utf_string_conversions.h"
     24 #include "chrome/app/chrome_command_ids.h"
     25 #include "chrome/browser/autocomplete/autocomplete.h"
     26 #include "chrome/browser/autocomplete/autocomplete_edit.h"
     27 #include "chrome/browser/autocomplete/autocomplete_match.h"
     28 #include "chrome/browser/autofill/autofill_manager.h"
     29 #include "chrome/browser/autofill/credit_card.h"
     30 #include "chrome/browser/autofill/personal_data_manager.h"
     31 #include "chrome/browser/automation/automation_autocomplete_edit_tracker.h"
     32 #include "chrome/browser/automation/automation_browser_tracker.h"
     33 #include "chrome/browser/automation/automation_provider_json.h"
     34 #include "chrome/browser/automation/automation_provider_list.h"
     35 #include "chrome/browser/automation/automation_provider_observers.h"
     36 #include "chrome/browser/automation/automation_tab_tracker.h"
     37 #include "chrome/browser/automation/automation_util.h"
     38 #include "chrome/browser/automation/automation_window_tracker.h"
     39 #include "chrome/browser/automation/ui_controls.h"
     40 #include "chrome/browser/blocked_content_container.h"
     41 #include "chrome/browser/bookmarks/bookmark_model.h"
     42 #include "chrome/browser/bookmarks/bookmark_storage.h"
     43 #include "chrome/browser/browser_process.h"
     44 #include "chrome/browser/browser_shutdown.h"
     45 #include "chrome/browser/debugger/devtools_manager.h"
     46 #include "chrome/browser/download/download_prefs.h"
     47 #include "chrome/browser/download/download_shelf.h"
     48 #include "chrome/browser/download/save_package.h"
     49 #include "chrome/browser/extensions/extension_host.h"
     50 #include "chrome/browser/extensions/extension_service.h"
     51 #include "chrome/browser/extensions/extension_updater.h"
     52 #include "chrome/browser/history/top_sites.h"
     53 #include "chrome/browser/importer/importer_host.h"
     54 #include "chrome/browser/instant/instant_controller.h"
     55 #include "chrome/browser/notifications/balloon.h"
     56 #include "chrome/browser/notifications/balloon_collection.h"
     57 #include "chrome/browser/notifications/notification.h"
     58 #include "chrome/browser/notifications/notification_ui_manager.h"
     59 #include "chrome/browser/password_manager/password_store.h"
     60 #include "chrome/browser/platform_util.h"
     61 #include "chrome/browser/prefs/pref_service.h"
     62 #include "chrome/browser/profiles/profile.h"
     63 #include "chrome/browser/profiles/profile_manager.h"
     64 #include "chrome/browser/search_engines/template_url.h"
     65 #include "chrome/browser/search_engines/template_url_model.h"
     66 #include "chrome/browser/tab_contents/confirm_infobar_delegate.h"
     67 #include "chrome/browser/tab_contents/link_infobar_delegate.h"
     68 #include "chrome/browser/themes/theme_service.h"
     69 #include "chrome/browser/themes/theme_service_factory.h"
     70 #include "chrome/browser/translate/translate_infobar_delegate.h"
     71 #include "chrome/browser/translate/translate_tab_helper.h"
     72 #include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog.h"
     73 #include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog_queue.h"
     74 #include "chrome/browser/ui/app_modal_dialogs/native_app_modal_dialog.h"
     75 #include "chrome/browser/ui/browser_window.h"
     76 #include "chrome/browser/ui/download/download_tab_helper.h"
     77 #include "chrome/browser/ui/find_bar/find_bar.h"
     78 #include "chrome/browser/ui/login/login_prompt.h"
     79 #include "chrome/browser/ui/omnibox/location_bar.h"
     80 #include "chrome/browser/ui/search_engines/keyword_editor_controller.h"
     81 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
     82 #include "chrome/browser/ui/webui/active_downloads_ui.h"
     83 #include "chrome/browser/ui/webui/shown_sections_handler.h"
     84 #include "chrome/common/automation_messages.h"
     85 #include "chrome/common/chrome_constants.h"
     86 #include "chrome/common/chrome_paths.h"
     87 #include "chrome/common/chrome_switches.h"
     88 #include "chrome/common/extensions/extension.h"
     89 #include "chrome/common/extensions/extension_extent.h"
     90 #include "chrome/common/extensions/url_pattern.h"
     91 #include "chrome/common/pref_names.h"
     92 #include "chrome/common/url_constants.h"
     93 #include "content/browser/renderer_host/render_process_host.h"
     94 #include "content/browser/renderer_host/render_view_host.h"
     95 #include "content/browser/tab_contents/interstitial_page.h"
     96 #include "content/common/common_param_traits.h"
     97 #include "content/common/notification_service.h"
     98 #include "net/base/cookie_store.h"
     99 #include "third_party/WebKit/Source/WebKit/chromium/public/WebInputEvent.h"
    100 #include "ui/base/events.h"
    101 #include "ui/base/message_box_flags.h"
    102 #include "webkit/plugins/npapi/plugin_list.h"
    103 
    104 namespace {
    105 
    106 void SendMouseClick(int flags) {
    107   ui_controls::MouseButton button = ui_controls::LEFT;
    108   if ((flags & ui::EF_LEFT_BUTTON_DOWN) ==
    109       ui::EF_LEFT_BUTTON_DOWN) {
    110     button = ui_controls::LEFT;
    111   } else if ((flags & ui::EF_RIGHT_BUTTON_DOWN) ==
    112              ui::EF_RIGHT_BUTTON_DOWN) {
    113     button = ui_controls::RIGHT;
    114   } else if ((flags & ui::EF_MIDDLE_BUTTON_DOWN) ==
    115              ui::EF_MIDDLE_BUTTON_DOWN) {
    116     button = ui_controls::MIDDLE;
    117   } else {
    118     NOTREACHED();
    119   }
    120 
    121   ui_controls::SendMouseClick(button);
    122 }
    123 
    124 class AutomationInterstitialPage : public InterstitialPage {
    125  public:
    126   AutomationInterstitialPage(TabContents* tab,
    127                              const GURL& url,
    128                              const std::string& contents)
    129       : InterstitialPage(tab, true, url),
    130         contents_(contents) {
    131   }
    132 
    133   virtual std::string GetHTMLContents() { return contents_; }
    134 
    135  private:
    136   const std::string contents_;
    137 
    138   DISALLOW_COPY_AND_ASSIGN(AutomationInterstitialPage);
    139 };
    140 
    141 }  // namespace
    142 
    143 TestingAutomationProvider::TestingAutomationProvider(Profile* profile)
    144     : AutomationProvider(profile),
    145 #if defined(TOOLKIT_VIEWS)
    146       popup_menu_waiter_(NULL),
    147 #endif
    148       redirect_query_(0) {
    149   BrowserList::AddObserver(this);
    150   registrar_.Add(this, NotificationType::SESSION_END,
    151                  NotificationService::AllSources());
    152 }
    153 
    154 TestingAutomationProvider::~TestingAutomationProvider() {
    155   BrowserList::RemoveObserver(this);
    156 }
    157 
    158 void TestingAutomationProvider::OnBrowserAdded(const Browser* browser) {
    159 }
    160 
    161 void TestingAutomationProvider::OnBrowserRemoved(const Browser* browser) {
    162   // For backwards compatibility with the testing automation interface, we
    163   // want the automation provider (and hence the process) to go away when the
    164   // last browser goes away.
    165   if (BrowserList::empty() && !CommandLine::ForCurrentProcess()->HasSwitch(
    166           switches::kKeepAliveForTest)) {
    167     // If you change this, update Observer for NotificationType::SESSION_END
    168     // below.
    169     MessageLoop::current()->PostTask(FROM_HERE,
    170         NewRunnableMethod(this, &TestingAutomationProvider::OnRemoveProvider));
    171   }
    172 }
    173 
    174 void TestingAutomationProvider::OnSourceProfilesLoaded() {
    175   DCHECK_NE(static_cast<ImporterList*>(NULL), importer_list_.get());
    176 
    177   // Get the correct profile based on the browser that the user provided.
    178   importer::SourceProfile source_profile;
    179   size_t i = 0;
    180   size_t importers_count = importer_list_->count();
    181   for ( ; i < importers_count; ++i) {
    182     importer::SourceProfile profile = importer_list_->GetSourceProfileAt(i);
    183     if (profile.importer_name == import_settings_data_.browser_name) {
    184       source_profile = profile;
    185       break;
    186     }
    187   }
    188   // If we made it to the end of the loop, then the input was bad.
    189   if (i == importers_count) {
    190     AutomationJSONReply(this, import_settings_data_.reply_message)
    191         .SendError("Invalid browser name string found.");
    192     return;
    193   }
    194 
    195   scoped_refptr<ImporterHost> importer_host(new ImporterHost);
    196   importer_host->SetObserver(
    197       new AutomationProviderImportSettingsObserver(
    198           this, import_settings_data_.reply_message));
    199 
    200   Profile* target_profile = import_settings_data_.browser->profile();
    201   importer_host->StartImportSettings(source_profile,
    202                                      target_profile,
    203                                      import_settings_data_.import_items,
    204                                      new ProfileWriter(target_profile),
    205                                      import_settings_data_.first_run);
    206 }
    207 
    208 void TestingAutomationProvider::Observe(NotificationType type,
    209                                         const NotificationSource& source,
    210                                         const NotificationDetails& details) {
    211   DCHECK(type == NotificationType::SESSION_END);
    212   // OnBrowserRemoved does a ReleaseLater. When session end is received we exit
    213   // before the task runs resulting in this object not being deleted. This
    214   // Release balance out the Release scheduled by OnBrowserRemoved.
    215   Release();
    216 }
    217 
    218 bool TestingAutomationProvider::OnMessageReceived(
    219     const IPC::Message& message) {
    220   bool handled = true;
    221   bool deserialize_success = true;
    222   IPC_BEGIN_MESSAGE_MAP_EX(TestingAutomationProvider,
    223                            message,
    224                            deserialize_success)
    225     IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_CloseBrowser, CloseBrowser)
    226     IPC_MESSAGE_HANDLER(AutomationMsg_CloseBrowserRequestAsync,
    227                         CloseBrowserAsync)
    228     IPC_MESSAGE_HANDLER(AutomationMsg_ActivateTab, ActivateTab)
    229     IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_AppendTab, AppendTab)
    230     IPC_MESSAGE_HANDLER(AutomationMsg_ActiveTabIndex, GetActiveTabIndex)
    231     IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_CloseTab, CloseTab)
    232     IPC_MESSAGE_HANDLER(AutomationMsg_GetCookies, GetCookies)
    233     IPC_MESSAGE_HANDLER(AutomationMsg_SetCookie, SetCookie)
    234     IPC_MESSAGE_HANDLER(AutomationMsg_DeleteCookie, DeleteCookie)
    235     IPC_MESSAGE_HANDLER(AutomationMsg_ShowCollectedCookiesDialog,
    236                         ShowCollectedCookiesDialog)
    237     IPC_MESSAGE_HANDLER_DELAY_REPLY(
    238         AutomationMsg_NavigateToURLBlockUntilNavigationsComplete,
    239         NavigateToURLBlockUntilNavigationsComplete)
    240     IPC_MESSAGE_HANDLER(AutomationMsg_NavigationAsync, NavigationAsync)
    241     IPC_MESSAGE_HANDLER(AutomationMsg_NavigationAsyncWithDisposition,
    242                         NavigationAsyncWithDisposition)
    243     IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_Reload, Reload)
    244     IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_SetAuth, SetAuth)
    245     IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_CancelAuth, CancelAuth)
    246     IPC_MESSAGE_HANDLER(AutomationMsg_NeedsAuth, NeedsAuth)
    247     IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_RedirectsFrom,
    248                                     GetRedirectsFrom)
    249     IPC_MESSAGE_HANDLER(AutomationMsg_BrowserWindowCount, GetBrowserWindowCount)
    250     IPC_MESSAGE_HANDLER(AutomationMsg_NormalBrowserWindowCount,
    251                         GetNormalBrowserWindowCount)
    252     IPC_MESSAGE_HANDLER(AutomationMsg_BrowserWindow, GetBrowserWindow)
    253     IPC_MESSAGE_HANDLER(AutomationMsg_GetBrowserLocale, GetBrowserLocale)
    254     IPC_MESSAGE_HANDLER(AutomationMsg_LastActiveBrowserWindow,
    255                         GetLastActiveBrowserWindow)
    256     IPC_MESSAGE_HANDLER(AutomationMsg_ActiveWindow, GetActiveWindow)
    257     IPC_MESSAGE_HANDLER(AutomationMsg_FindNormalBrowserWindow,
    258                         FindNormalBrowserWindow)
    259     IPC_MESSAGE_HANDLER(AutomationMsg_IsWindowActive, IsWindowActive)
    260     IPC_MESSAGE_HANDLER(AutomationMsg_ActivateWindow, ActivateWindow)
    261     IPC_MESSAGE_HANDLER(AutomationMsg_IsWindowMaximized, IsWindowMaximized)
    262     IPC_MESSAGE_HANDLER(AutomationMsg_WindowExecuteCommandAsync,
    263                         ExecuteBrowserCommandAsync)
    264     IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WindowExecuteCommand,
    265                         ExecuteBrowserCommand)
    266     IPC_MESSAGE_HANDLER(AutomationMsg_TerminateSession, TerminateSession)
    267     IPC_MESSAGE_HANDLER(AutomationMsg_WindowViewBounds, WindowGetViewBounds)
    268     IPC_MESSAGE_HANDLER(AutomationMsg_GetWindowBounds, GetWindowBounds)
    269     IPC_MESSAGE_HANDLER(AutomationMsg_SetWindowBounds, SetWindowBounds)
    270     IPC_MESSAGE_HANDLER(AutomationMsg_SetWindowVisible, SetWindowVisible)
    271     IPC_MESSAGE_HANDLER(AutomationMsg_WindowClick, WindowSimulateClick)
    272     IPC_MESSAGE_HANDLER(AutomationMsg_WindowMouseMove, WindowSimulateMouseMove)
    273     IPC_MESSAGE_HANDLER(AutomationMsg_WindowKeyPress, WindowSimulateKeyPress)
    274     IPC_MESSAGE_HANDLER(AutomationMsg_TabCount, GetTabCount)
    275     IPC_MESSAGE_HANDLER(AutomationMsg_Type, GetType)
    276     IPC_MESSAGE_HANDLER(AutomationMsg_Tab, GetTab)
    277     IPC_MESSAGE_HANDLER(AutomationMsg_TabProcessID, GetTabProcessID)
    278     IPC_MESSAGE_HANDLER(AutomationMsg_TabTitle, GetTabTitle)
    279     IPC_MESSAGE_HANDLER(AutomationMsg_TabIndex, GetTabIndex)
    280     IPC_MESSAGE_HANDLER(AutomationMsg_TabURL, GetTabURL)
    281     IPC_MESSAGE_HANDLER(AutomationMsg_ShelfVisibility, GetShelfVisibility)
    282     IPC_MESSAGE_HANDLER(AutomationMsg_IsFullscreen, IsFullscreen)
    283     IPC_MESSAGE_HANDLER(AutomationMsg_IsFullscreenBubbleVisible,
    284                         GetFullscreenBubbleVisibility)
    285     IPC_MESSAGE_HANDLER(AutomationMsg_AutocompleteEditForBrowser,
    286                         GetAutocompleteEditForBrowser)
    287     IPC_MESSAGE_HANDLER(AutomationMsg_AutocompleteEditGetText,
    288                         GetAutocompleteEditText)
    289     IPC_MESSAGE_HANDLER(AutomationMsg_AutocompleteEditSetText,
    290                         SetAutocompleteEditText)
    291     IPC_MESSAGE_HANDLER(AutomationMsg_AutocompleteEditIsQueryInProgress,
    292                         AutocompleteEditIsQueryInProgress)
    293     IPC_MESSAGE_HANDLER(AutomationMsg_AutocompleteEditGetMatches,
    294                         AutocompleteEditGetMatches)
    295     IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WaitForAutocompleteEditFocus,
    296                                     WaitForAutocompleteEditFocus)
    297     IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_DomOperation,
    298                                     ExecuteJavascript)
    299     IPC_MESSAGE_HANDLER(AutomationMsg_ConstrainedWindowCount,
    300                         GetConstrainedWindowCount)
    301 #if defined(TOOLKIT_VIEWS)
    302     IPC_MESSAGE_HANDLER(AutomationMsg_GetFocusedViewID, GetFocusedViewID)
    303     IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WaitForFocusedViewIDToChange,
    304                                     WaitForFocusedViewIDToChange)
    305     IPC_MESSAGE_HANDLER(AutomationMsg_StartTrackingPopupMenus,
    306                         StartTrackingPopupMenus)
    307     IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WaitForPopupMenuToOpen,
    308                                     WaitForPopupMenuToOpen)
    309 #endif  // defined(TOOLKIT_VIEWS)
    310     IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_InspectElement,
    311                                     HandleInspectElementRequest)
    312     IPC_MESSAGE_HANDLER(AutomationMsg_DownloadDirectory, GetDownloadDirectory)
    313     IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_OpenNewBrowserWindowOfType,
    314                                     OpenNewBrowserWindowOfType)
    315     IPC_MESSAGE_HANDLER(AutomationMsg_WindowForBrowser, GetWindowForBrowser)
    316     IPC_MESSAGE_HANDLER(AutomationMsg_BrowserForWindow, GetBrowserForWindow)
    317     IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_ShowInterstitialPage,
    318                                     ShowInterstitialPage)
    319     IPC_MESSAGE_HANDLER(AutomationMsg_HideInterstitialPage,
    320                         HideInterstitialPage)
    321     IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WaitForTabToBeRestored,
    322                                     WaitForTabToBeRestored)
    323     IPC_MESSAGE_HANDLER(AutomationMsg_GetSecurityState, GetSecurityState)
    324     IPC_MESSAGE_HANDLER(AutomationMsg_GetPageType, GetPageType)
    325     IPC_MESSAGE_HANDLER(AutomationMsg_GetMetricEventDuration,
    326                         GetMetricEventDuration)
    327     IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_ActionOnSSLBlockingPage,
    328                                     ActionOnSSLBlockingPage)
    329     IPC_MESSAGE_HANDLER(AutomationMsg_BringBrowserToFront, BringBrowserToFront)
    330     IPC_MESSAGE_HANDLER(AutomationMsg_IsMenuCommandEnabled,
    331                         IsMenuCommandEnabled)
    332     IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_PrintNow, PrintNow)
    333     IPC_MESSAGE_HANDLER(AutomationMsg_SavePage, SavePage)
    334     IPC_MESSAGE_HANDLER(AutomationMsg_OpenFindInPage,
    335                         HandleOpenFindInPageRequest)
    336     IPC_MESSAGE_HANDLER(AutomationMsg_FindWindowVisibility,
    337                         GetFindWindowVisibility)
    338     IPC_MESSAGE_HANDLER(AutomationMsg_FindWindowLocation,
    339                         HandleFindWindowLocationRequest)
    340     IPC_MESSAGE_HANDLER(AutomationMsg_BookmarkBarVisibility,
    341                         GetBookmarkBarVisibility)
    342     IPC_MESSAGE_HANDLER(AutomationMsg_GetBookmarksAsJSON,
    343                         GetBookmarksAsJSON)
    344     IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WaitForBookmarkModelToLoad,
    345                                     WaitForBookmarkModelToLoad)
    346     IPC_MESSAGE_HANDLER(AutomationMsg_AddBookmarkGroup,
    347                         AddBookmarkGroup)
    348     IPC_MESSAGE_HANDLER(AutomationMsg_AddBookmarkURL,
    349                         AddBookmarkURL)
    350     IPC_MESSAGE_HANDLER(AutomationMsg_ReparentBookmark,
    351                         ReparentBookmark)
    352     IPC_MESSAGE_HANDLER(AutomationMsg_SetBookmarkTitle,
    353                         SetBookmarkTitle)
    354     IPC_MESSAGE_HANDLER(AutomationMsg_SetBookmarkURL,
    355                         SetBookmarkURL)
    356     IPC_MESSAGE_HANDLER(AutomationMsg_RemoveBookmark,
    357                         RemoveBookmark)
    358     IPC_MESSAGE_HANDLER(AutomationMsg_GetInfoBarCount, GetInfoBarCount)
    359     IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_ClickInfoBarAccept,
    360                                     ClickInfoBarAccept)
    361     IPC_MESSAGE_HANDLER(AutomationMsg_GetLastNavigationTime,
    362                         GetLastNavigationTime)
    363     IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WaitForNavigation,
    364                                     WaitForNavigation)
    365     IPC_MESSAGE_HANDLER(AutomationMsg_SetIntPreference, SetIntPreference)
    366     IPC_MESSAGE_HANDLER(AutomationMsg_ShowingAppModalDialog,
    367                         GetShowingAppModalDialog)
    368     IPC_MESSAGE_HANDLER(AutomationMsg_ClickAppModalDialogButton,
    369                         ClickAppModalDialogButton)
    370     IPC_MESSAGE_HANDLER(AutomationMsg_SetStringPreference, SetStringPreference)
    371     IPC_MESSAGE_HANDLER(AutomationMsg_GetBooleanPreference,
    372                         GetBooleanPreference)
    373     IPC_MESSAGE_HANDLER(AutomationMsg_SetBooleanPreference,
    374                         SetBooleanPreference)
    375     IPC_MESSAGE_HANDLER_DELAY_REPLY(
    376         AutomationMsg_WaitForBrowserWindowCountToBecome,
    377         WaitForBrowserWindowCountToBecome)
    378     IPC_MESSAGE_HANDLER_DELAY_REPLY(
    379         AutomationMsg_WaitForAppModalDialogToBeShown,
    380         WaitForAppModalDialogToBeShown)
    381     IPC_MESSAGE_HANDLER_DELAY_REPLY(
    382         AutomationMsg_GoBackBlockUntilNavigationsComplete,
    383         GoBackBlockUntilNavigationsComplete)
    384     IPC_MESSAGE_HANDLER_DELAY_REPLY(
    385         AutomationMsg_GoForwardBlockUntilNavigationsComplete,
    386         GoForwardBlockUntilNavigationsComplete)
    387     IPC_MESSAGE_HANDLER(AutomationMsg_SavePackageShouldPromptUser,
    388                         SavePackageShouldPromptUser)
    389     IPC_MESSAGE_HANDLER(AutomationMsg_WindowTitle, GetWindowTitle)
    390     IPC_MESSAGE_HANDLER(AutomationMsg_SetShelfVisibility, SetShelfVisibility)
    391     IPC_MESSAGE_HANDLER(AutomationMsg_BlockedPopupCount, GetBlockedPopupCount)
    392     IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_SendJSONRequest,
    393                                     SendJSONRequest)
    394     IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WaitForTabCountToBecome,
    395                                     WaitForTabCountToBecome)
    396     IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WaitForInfoBarCount,
    397                                     WaitForInfoBarCount)
    398     IPC_MESSAGE_HANDLER(AutomationMsg_GetPageCurrentEncoding,
    399                         GetPageCurrentEncoding)
    400     IPC_MESSAGE_HANDLER(AutomationMsg_ShutdownSessionService,
    401                         ShutdownSessionService)
    402     IPC_MESSAGE_HANDLER(AutomationMsg_SetContentSetting, SetContentSetting)
    403     IPC_MESSAGE_HANDLER(AutomationMsg_LoadBlockedPlugins, LoadBlockedPlugins)
    404     IPC_MESSAGE_HANDLER(AutomationMsg_ResetToDefaultTheme, ResetToDefaultTheme)
    405     IPC_MESSAGE_HANDLER_DELAY_REPLY(
    406         AutomationMsg_WaitForProcessLauncherThreadToGoIdle,
    407         WaitForProcessLauncherThreadToGoIdle)
    408     IPC_MESSAGE_HANDLER(AutomationMsg_GetParentBrowserOfTab,
    409                         GetParentBrowserOfTab)
    410 
    411     IPC_MESSAGE_UNHANDLED(
    412         handled = AutomationProvider::OnMessageReceived(message))
    413   IPC_END_MESSAGE_MAP_EX()
    414   if (!deserialize_success)
    415     OnMessageDeserializationFailure();
    416   return handled;
    417 }
    418 
    419 void TestingAutomationProvider::OnChannelError() {
    420   if (!reinitialize_on_channel_error_ &&
    421       browser_shutdown::GetShutdownType() == browser_shutdown::NOT_VALID)
    422     BrowserList::CloseAllBrowsersAndExit();
    423   AutomationProvider::OnChannelError();
    424 }
    425 
    426 void TestingAutomationProvider::CloseBrowser(int browser_handle,
    427                                              IPC::Message* reply_message) {
    428   if (!browser_tracker_->ContainsHandle(browser_handle))
    429     return;
    430 
    431   Browser* browser = browser_tracker_->GetResource(browser_handle);
    432   new BrowserClosedNotificationObserver(browser, this, reply_message);
    433   browser->window()->Close();
    434 }
    435 
    436 void TestingAutomationProvider::CloseBrowserAsync(int browser_handle) {
    437   if (!browser_tracker_->ContainsHandle(browser_handle))
    438     return;
    439 
    440   Browser* browser = browser_tracker_->GetResource(browser_handle);
    441   browser->window()->Close();
    442 }
    443 
    444 void TestingAutomationProvider::ActivateTab(int handle,
    445                                             int at_index,
    446                                             int* status) {
    447   *status = -1;
    448   if (browser_tracker_->ContainsHandle(handle) && at_index > -1) {
    449     Browser* browser = browser_tracker_->GetResource(handle);
    450     if (at_index >= 0 && at_index < browser->tab_count()) {
    451       browser->ActivateTabAt(at_index, true);
    452       *status = 0;
    453     }
    454   }
    455 }
    456 
    457 void TestingAutomationProvider::AppendTab(int handle,
    458                                           const GURL& url,
    459                                           IPC::Message* reply_message) {
    460   int append_tab_response = -1;  // -1 is the error code
    461   NotificationObserver* observer = NULL;
    462 
    463   if (browser_tracker_->ContainsHandle(handle)) {
    464     Browser* browser = browser_tracker_->GetResource(handle);
    465     observer = new TabAppendedNotificationObserver(browser, this,
    466                                                    reply_message);
    467     TabContentsWrapper* contents =
    468         browser->AddSelectedTabWithURL(url, PageTransition::TYPED);
    469     if (contents) {
    470       append_tab_response =
    471           GetIndexForNavigationController(&contents->controller(), browser);
    472     }
    473   }
    474 
    475   if (append_tab_response < 0) {
    476     // Appending tab failed. Clean up and send failure response.
    477 
    478     if (observer)
    479       delete observer;
    480 
    481     AutomationMsg_AppendTab::WriteReplyParams(reply_message,
    482                                               append_tab_response);
    483     Send(reply_message);
    484   }
    485 }
    486 
    487 void TestingAutomationProvider::GetActiveTabIndex(int handle,
    488                                                   int* active_tab_index) {
    489   *active_tab_index = -1;  // -1 is the error code
    490   if (browser_tracker_->ContainsHandle(handle)) {
    491     Browser* browser = browser_tracker_->GetResource(handle);
    492     *active_tab_index = browser->active_index();
    493   }
    494 }
    495 
    496 void TestingAutomationProvider::CloseTab(int tab_handle,
    497                                          bool wait_until_closed,
    498                                          IPC::Message* reply_message) {
    499   if (tab_tracker_->ContainsHandle(tab_handle)) {
    500     NavigationController* controller = tab_tracker_->GetResource(tab_handle);
    501     int index;
    502     Browser* browser = Browser::GetBrowserForController(controller, &index);
    503     DCHECK(browser);
    504     new TabClosedNotificationObserver(this, wait_until_closed, reply_message);
    505     browser->CloseTabContents(controller->tab_contents());
    506     return;
    507   }
    508 
    509   AutomationMsg_CloseTab::WriteReplyParams(reply_message, false);
    510   Send(reply_message);
    511 }
    512 
    513 void TestingAutomationProvider::GetCookies(const GURL& url, int handle,
    514                                            int* value_size,
    515                                            std::string* value) {
    516   TabContents *contents = tab_tracker_->ContainsHandle(handle) ?
    517       tab_tracker_->GetResource(handle)->tab_contents() : NULL;
    518   automation_util::GetCookies(url, contents, value_size, value);
    519 }
    520 
    521 void TestingAutomationProvider::SetCookie(const GURL& url,
    522                                           const std::string& value,
    523                                           int handle,
    524                                           int* response_value) {
    525   TabContents *contents = tab_tracker_->ContainsHandle(handle) ?
    526       tab_tracker_->GetResource(handle)->tab_contents() : NULL;
    527   automation_util::SetCookie(url, value, contents, response_value);
    528 }
    529 
    530 void TestingAutomationProvider::DeleteCookie(const GURL& url,
    531                                              const std::string& cookie_name,
    532                                              int handle, bool* success) {
    533   TabContents *contents = tab_tracker_->ContainsHandle(handle) ?
    534       tab_tracker_->GetResource(handle)->tab_contents() : NULL;
    535   automation_util::DeleteCookie(url, cookie_name, contents, success);
    536 }
    537 
    538 void TestingAutomationProvider::ShowCollectedCookiesDialog(
    539     int handle, bool* success) {
    540   *success = false;
    541   if (tab_tracker_->ContainsHandle(handle)) {
    542     TabContents* tab_contents =
    543         tab_tracker_->GetResource(handle)->tab_contents();
    544     tab_contents->delegate()->ShowCollectedCookiesDialog(tab_contents);
    545     *success = true;
    546   }
    547 }
    548 
    549 void TestingAutomationProvider::NavigateToURLBlockUntilNavigationsComplete(
    550     int handle, const GURL& url, int number_of_navigations,
    551     IPC::Message* reply_message) {
    552   if (tab_tracker_->ContainsHandle(handle)) {
    553     NavigationController* tab = tab_tracker_->GetResource(handle);
    554 
    555     // Simulate what a user would do. Activate the tab and then navigate.
    556     // We could allow navigating in a background tab in future.
    557     Browser* browser = FindAndActivateTab(tab);
    558 
    559     if (browser) {
    560       new NavigationNotificationObserver(tab, this, reply_message,
    561                                          number_of_navigations, false, false);
    562 
    563       // TODO(darin): avoid conversion to GURL.
    564       browser->OpenURL(url, GURL(), CURRENT_TAB, PageTransition::TYPED);
    565       return;
    566     }
    567   }
    568 
    569   AutomationMsg_NavigateToURLBlockUntilNavigationsComplete::WriteReplyParams(
    570       reply_message, AUTOMATION_MSG_NAVIGATION_ERROR);
    571   Send(reply_message);
    572 }
    573 
    574 void TestingAutomationProvider::NavigationAsync(int handle,
    575                                                 const GURL& url,
    576                                                 bool* status) {
    577   NavigationAsyncWithDisposition(handle, url, CURRENT_TAB, status);
    578 }
    579 
    580 void TestingAutomationProvider::NavigationAsyncWithDisposition(
    581     int handle,
    582     const GURL& url,
    583     WindowOpenDisposition disposition,
    584     bool* status) {
    585   *status = false;
    586 
    587   if (tab_tracker_->ContainsHandle(handle)) {
    588     NavigationController* tab = tab_tracker_->GetResource(handle);
    589 
    590     // Simulate what a user would do. Activate the tab and then navigate.
    591     // We could allow navigating in a background tab in future.
    592     Browser* browser = FindAndActivateTab(tab);
    593 
    594     if (browser) {
    595       // Don't add any listener unless a callback mechanism is desired.
    596       // TODO(vibhor): Do this if such a requirement arises in future.
    597       browser->OpenURL(url, GURL(), disposition, PageTransition::TYPED);
    598       *status = true;
    599     }
    600   }
    601 }
    602 
    603 void TestingAutomationProvider::Reload(int handle,
    604                                        IPC::Message* reply_message) {
    605   if (tab_tracker_->ContainsHandle(handle)) {
    606     NavigationController* tab = tab_tracker_->GetResource(handle);
    607     Browser* browser = FindAndActivateTab(tab);
    608     if (browser && browser->command_updater()->IsCommandEnabled(IDC_RELOAD)) {
    609       new NavigationNotificationObserver(
    610           tab, this, reply_message, 1, false, false);
    611       browser->Reload(CURRENT_TAB);
    612       return;
    613     }
    614   }
    615 
    616   AutomationMsg_Reload::WriteReplyParams(
    617       reply_message, AUTOMATION_MSG_NAVIGATION_ERROR);
    618   Send(reply_message);
    619 }
    620 
    621 void TestingAutomationProvider::SetAuth(int tab_handle,
    622                                         const std::wstring& username,
    623                                         const std::wstring& password,
    624                                         IPC::Message* reply_message) {
    625   if (tab_tracker_->ContainsHandle(tab_handle)) {
    626     NavigationController* tab = tab_tracker_->GetResource(tab_handle);
    627     LoginHandlerMap::iterator iter = login_handler_map_.find(tab);
    628 
    629     if (iter != login_handler_map_.end()) {
    630       // If auth is needed again after this, assume login has failed.  This is
    631       // not strictly correct, because a navigation can require both proxy and
    632       // server auth, but it should be OK for now.
    633       LoginHandler* handler = iter->second;
    634       new NavigationNotificationObserver(
    635           tab, this, reply_message, 1, false, false);
    636       handler->SetAuth(WideToUTF16Hack(username), WideToUTF16Hack(password));
    637       return;
    638     }
    639   }
    640 
    641   AutomationMsg_SetAuth::WriteReplyParams(
    642       reply_message, AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED);
    643   Send(reply_message);
    644 }
    645 
    646 void TestingAutomationProvider::CancelAuth(int tab_handle,
    647                                            IPC::Message* reply_message) {
    648   if (tab_tracker_->ContainsHandle(tab_handle)) {
    649     NavigationController* tab = tab_tracker_->GetResource(tab_handle);
    650     LoginHandlerMap::iterator iter = login_handler_map_.find(tab);
    651 
    652     if (iter != login_handler_map_.end()) {
    653       // If auth is needed again after this, something is screwy.
    654       LoginHandler* handler = iter->second;
    655       new NavigationNotificationObserver(
    656           tab, this, reply_message, 1, false, false);
    657       handler->CancelAuth();
    658       return;
    659     }
    660   }
    661 
    662   AutomationMsg_CancelAuth::WriteReplyParams(
    663       reply_message, AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED);
    664   Send(reply_message);
    665 }
    666 
    667 void TestingAutomationProvider::NeedsAuth(int tab_handle, bool* needs_auth) {
    668   *needs_auth = false;
    669 
    670   if (tab_tracker_->ContainsHandle(tab_handle)) {
    671     NavigationController* tab = tab_tracker_->GetResource(tab_handle);
    672     LoginHandlerMap::iterator iter = login_handler_map_.find(tab);
    673 
    674     if (iter != login_handler_map_.end()) {
    675       // The LoginHandler will be in our map IFF the tab needs auth.
    676       *needs_auth = true;
    677     }
    678   }
    679 }
    680 
    681 void TestingAutomationProvider::GetRedirectsFrom(int tab_handle,
    682                                                  const GURL& source_url,
    683                                                  IPC::Message* reply_message) {
    684   if (redirect_query_) {
    685     LOG(ERROR) << "Can only handle one redirect query at once.";
    686   } else if (tab_tracker_->ContainsHandle(tab_handle)) {
    687     NavigationController* tab = tab_tracker_->GetResource(tab_handle);
    688     HistoryService* history_service =
    689         tab->profile()->GetHistoryService(Profile::EXPLICIT_ACCESS);
    690 
    691     DCHECK(history_service) << "Tab " << tab_handle << "'s profile " <<
    692                                "has no history service";
    693     if (history_service) {
    694       DCHECK(!reply_message_);
    695       reply_message_ = reply_message;
    696       // Schedule a history query for redirects. The response will be sent
    697       // asynchronously from the callback the history system uses to notify us
    698       // that it's done: OnRedirectQueryComplete.
    699       redirect_query_ = history_service->QueryRedirectsFrom(
    700           source_url, &consumer_,
    701           NewCallback(this,
    702                       &TestingAutomationProvider::OnRedirectQueryComplete));
    703       return;  // Response will be sent when query completes.
    704     }
    705   }
    706 
    707   // Send failure response.
    708   std::vector<GURL> empty;
    709   AutomationMsg_RedirectsFrom::WriteReplyParams(reply_message, false, empty);
    710   Send(reply_message);
    711 }
    712 
    713 void TestingAutomationProvider::GetBrowserWindowCount(int* window_count) {
    714   *window_count = static_cast<int>(BrowserList::size());
    715 }
    716 
    717 void TestingAutomationProvider::GetNormalBrowserWindowCount(int* window_count) {
    718   *window_count = static_cast<int>(
    719       BrowserList::GetBrowserCountForType(profile_, Browser::TYPE_NORMAL));
    720 }
    721 
    722 void TestingAutomationProvider::GetBrowserWindow(int index, int* handle) {
    723   *handle = 0;
    724   Browser* browser = automation_util::GetBrowserAt(index);
    725   if (browser)
    726     *handle = browser_tracker_->Add(browser);
    727 }
    728 
    729 void TestingAutomationProvider::FindNormalBrowserWindow(int* handle) {
    730   *handle = 0;
    731   Browser* browser = BrowserList::FindBrowserWithType(profile_,
    732                                                       Browser::TYPE_NORMAL,
    733                                                       false);
    734   if (browser)
    735     *handle = browser_tracker_->Add(browser);
    736 }
    737 
    738 void TestingAutomationProvider::GetLastActiveBrowserWindow(int* handle) {
    739   *handle = 0;
    740   Browser* browser = BrowserList::GetLastActive();
    741   if (browser)
    742     *handle = browser_tracker_->Add(browser);
    743 }
    744 
    745 void TestingAutomationProvider::GetActiveWindow(int* handle) {
    746   *handle = 0;
    747   Browser* browser = BrowserList::GetLastActive();
    748   if (browser) {
    749     gfx::NativeWindow window = browser->window()->GetNativeHandle();
    750     *handle = window_tracker_->Add(window);
    751   }
    752 }
    753 
    754 void TestingAutomationProvider::ExecuteBrowserCommandAsync(int handle,
    755                                                            int command,
    756                                                            bool* success) {
    757   *success = false;
    758   if (browser_tracker_->ContainsHandle(handle)) {
    759     Browser* browser = browser_tracker_->GetResource(handle);
    760     if (browser->command_updater()->SupportsCommand(command) &&
    761         browser->command_updater()->IsCommandEnabled(command)) {
    762       browser->ExecuteCommand(command);
    763       *success = true;
    764     }
    765   }
    766 }
    767 
    768 void TestingAutomationProvider::ExecuteBrowserCommand(
    769     int handle, int command, IPC::Message* reply_message) {
    770   // List of commands which just finish synchronously and don't require
    771   // setting up an observer.
    772   static const int kSynchronousCommands[] = {
    773     IDC_HOME,
    774     IDC_SELECT_NEXT_TAB,
    775     IDC_SELECT_PREVIOUS_TAB,
    776     IDC_SHOW_BOOKMARK_MANAGER,
    777   };
    778   if (browser_tracker_->ContainsHandle(handle)) {
    779     Browser* browser = browser_tracker_->GetResource(handle);
    780     if (browser->command_updater()->SupportsCommand(command) &&
    781         browser->command_updater()->IsCommandEnabled(command)) {
    782       // First check if we can handle the command without using an observer.
    783       for (size_t i = 0; i < arraysize(kSynchronousCommands); i++) {
    784         if (command == kSynchronousCommands[i]) {
    785           browser->ExecuteCommand(command);
    786           AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message,
    787                                                                true);
    788           Send(reply_message);
    789           return;
    790         }
    791       }
    792 
    793       // Use an observer if we have one, otherwise fail.
    794       if (ExecuteBrowserCommandObserver::CreateAndRegisterObserver(
    795           this, browser, command, reply_message)) {
    796         browser->ExecuteCommand(command);
    797         return;
    798       }
    799     }
    800   }
    801   AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message, false);
    802   Send(reply_message);
    803 }
    804 
    805 void TestingAutomationProvider::GetBrowserLocale(string16* locale) {
    806   *locale = ASCIIToUTF16(g_browser_process->GetApplicationLocale());
    807 }
    808 
    809 void TestingAutomationProvider::IsWindowActive(int handle,
    810                                                bool* success,
    811                                                bool* is_active) {
    812   if (window_tracker_->ContainsHandle(handle)) {
    813     *is_active =
    814         platform_util::IsWindowActive(window_tracker_->GetResource(handle));
    815     *success = true;
    816   } else {
    817     *success = false;
    818     *is_active = false;
    819   }
    820 }
    821 
    822 void TestingAutomationProvider::WindowSimulateClick(const IPC::Message& message,
    823                                                     int handle,
    824                                                     const gfx::Point& click,
    825                                                     int flags) {
    826   if (window_tracker_->ContainsHandle(handle)) {
    827     // TODO(phajdan.jr): This is flaky. We should wait for the final click.
    828     ui_controls::SendMouseMoveNotifyWhenDone(
    829         click.x(), click.y(), NewRunnableFunction(&SendMouseClick, flags));
    830   }
    831 }
    832 
    833 void TestingAutomationProvider::WindowSimulateMouseMove(
    834     const IPC::Message& message,
    835     int handle,
    836     const gfx::Point& location) {
    837   if (window_tracker_->ContainsHandle(handle))
    838     ui_controls::SendMouseMove(location.x(), location.y());
    839 }
    840 
    841 void TestingAutomationProvider::WindowSimulateKeyPress(
    842     const IPC::Message& message,
    843     int handle,
    844     int key,
    845     int flags) {
    846   if (!window_tracker_->ContainsHandle(handle))
    847     return;
    848 
    849   gfx::NativeWindow window = window_tracker_->GetResource(handle);
    850   // The key event is sent to whatever window is active.
    851   ui_controls::SendKeyPress(window, static_cast<ui::KeyboardCode>(key),
    852                             ((flags & ui::EF_CONTROL_DOWN) ==
    853                              ui::EF_CONTROL_DOWN),
    854                             ((flags & ui::EF_SHIFT_DOWN) ==
    855                              ui::EF_SHIFT_DOWN),
    856                             ((flags & ui::EF_ALT_DOWN) ==
    857                              ui::EF_ALT_DOWN),
    858                             ((flags & ui::EF_COMMAND_DOWN) ==
    859                              ui::EF_COMMAND_DOWN));
    860 }
    861 
    862 void TestingAutomationProvider::WebkitMouseClick(DictionaryValue* args,
    863                                                  IPC::Message* reply_message) {
    864   TabContents* tab_contents;
    865   std::string error;
    866   if (!GetTabFromJSONArgs(args, &tab_contents, &error)) {
    867     AutomationJSONReply(this, reply_message).SendError(error);
    868     return;
    869   }
    870 
    871   WebKit::WebMouseEvent mouse_event;
    872   if (!args->GetInteger("x", &mouse_event.x) ||
    873       !args->GetInteger("y", &mouse_event.y)) {
    874     AutomationJSONReply(this, reply_message)
    875         .SendError("(X,Y) coordinates missing or invalid");
    876     return;
    877   }
    878 
    879   int button;
    880   if (!args->GetInteger("button", &button)) {
    881     AutomationJSONReply(this, reply_message)
    882         .SendError("Mouse button missing or invalid");
    883     return;
    884   }
    885   if (button == automation::kLeftButton) {
    886     mouse_event.button = WebKit::WebMouseEvent::ButtonLeft;
    887   } else if (button == automation::kRightButton) {
    888     mouse_event.button = WebKit::WebMouseEvent::ButtonRight;
    889   } else if (button == automation::kMiddleButton) {
    890     mouse_event.button = WebKit::WebMouseEvent::ButtonMiddle;
    891   } else {
    892     AutomationJSONReply(this, reply_message)
    893         .SendError("Invalid button press requested");
    894     return;
    895   }
    896 
    897   mouse_event.type = WebKit::WebInputEvent::MouseDown;
    898   mouse_event.clickCount = 1;
    899 
    900   tab_contents->render_view_host()->ForwardMouseEvent(mouse_event);
    901 
    902   mouse_event.type = WebKit::WebInputEvent::MouseUp;
    903   new InputEventAckNotificationObserver(this, reply_message, mouse_event.type);
    904   tab_contents->render_view_host()->ForwardMouseEvent(mouse_event);
    905 }
    906 
    907 void TestingAutomationProvider::WebkitMouseMove(
    908     DictionaryValue* args, IPC::Message* reply_message) {
    909   TabContents* tab_contents;
    910   std::string error;
    911   if (!GetTabFromJSONArgs(args, &tab_contents, &error)) {
    912     AutomationJSONReply(this, reply_message).SendError(error);
    913     return;
    914   }
    915 
    916   WebKit::WebMouseEvent mouse_event;
    917   if (!args->GetInteger("x", &mouse_event.x) ||
    918       !args->GetInteger("y", &mouse_event.y)) {
    919     AutomationJSONReply(this, reply_message)
    920         .SendError("(X,Y) coordinates missing or invalid");
    921     return;
    922   }
    923 
    924   mouse_event.type = WebKit::WebInputEvent::MouseMove;
    925   new InputEventAckNotificationObserver(this, reply_message, mouse_event.type);
    926   tab_contents->render_view_host()->ForwardMouseEvent(mouse_event);
    927 }
    928 
    929 void TestingAutomationProvider::WebkitMouseDrag(DictionaryValue* args,
    930                                                 IPC::Message* reply_message) {
    931   TabContents* tab_contents;
    932   std::string error;
    933   if (!GetTabFromJSONArgs(args, &tab_contents, &error)) {
    934     AutomationJSONReply(this, reply_message).SendError(error);
    935     return;
    936   }
    937 
    938   WebKit::WebMouseEvent mouse_event;
    939   int start_x, start_y, end_x, end_y;
    940   if (!args->GetInteger("start_x", &start_x) ||
    941       !args->GetInteger("start_y", &start_y) ||
    942       !args->GetInteger("end_x", &end_x) ||
    943       !args->GetInteger("end_y", &end_y)) {
    944     AutomationJSONReply(this, reply_message)
    945         .SendError("Invalid start/end positions");
    946     return;
    947   }
    948 
    949   mouse_event.type = WebKit::WebInputEvent::MouseMove;
    950   // Step 1- Move the mouse to the start position.
    951   mouse_event.x = start_x;
    952   mouse_event.y = start_y;
    953   tab_contents->render_view_host()->ForwardMouseEvent(mouse_event);
    954 
    955   // Step 2- Left click mouse down, the mouse button is fixed.
    956   mouse_event.type = WebKit::WebInputEvent::MouseDown;
    957   mouse_event.button = WebKit::WebMouseEvent::ButtonLeft;
    958   mouse_event.clickCount = 1;
    959   tab_contents->render_view_host()->ForwardMouseEvent(mouse_event);
    960 
    961   // Step 3 - Move the mouse to the end position.
    962   // TODO(JMikhail): See if we should simulate the by not making such
    963   // a drastic jump by placing incrmental stops along the way.
    964   mouse_event.type = WebKit::WebInputEvent::MouseMove;
    965   mouse_event.x = end_x;
    966   mouse_event.y = end_y;
    967   mouse_event.clickCount = 0;
    968   tab_contents->render_view_host()->ForwardMouseEvent(mouse_event);
    969 
    970   // Step 4 - Release the left mouse button.
    971   mouse_event.type = WebKit::WebInputEvent::MouseUp;
    972   mouse_event.clickCount = 1;
    973   new InputEventAckNotificationObserver(this, reply_message, mouse_event.type);
    974   tab_contents->render_view_host()->ForwardMouseEvent(mouse_event);
    975 }
    976 
    977 void TestingAutomationProvider::GetTabCount(int handle, int* tab_count) {
    978   *tab_count = -1;  // -1 is the error code
    979 
    980   if (browser_tracker_->ContainsHandle(handle)) {
    981     Browser* browser = browser_tracker_->GetResource(handle);
    982     *tab_count = browser->tab_count();
    983   }
    984 }
    985 
    986 void TestingAutomationProvider::GetType(int handle, int* type_as_int) {
    987   *type_as_int = -1;  // -1 is the error code
    988 
    989   if (browser_tracker_->ContainsHandle(handle)) {
    990     Browser* browser = browser_tracker_->GetResource(handle);
    991     *type_as_int = static_cast<int>(browser->type());
    992   }
    993 }
    994 
    995 void TestingAutomationProvider::GetTab(int win_handle,
    996                                        int tab_index,
    997                                        int* tab_handle) {
    998   *tab_handle = 0;
    999   if (browser_tracker_->ContainsHandle(win_handle) && (tab_index >= 0)) {
   1000     Browser* browser = browser_tracker_->GetResource(win_handle);
   1001     if (tab_index < browser->tab_count()) {
   1002       TabContents* tab_contents = browser->GetTabContentsAt(tab_index);
   1003       *tab_handle = tab_tracker_->Add(&tab_contents->controller());
   1004     }
   1005   }
   1006 }
   1007 
   1008 void TestingAutomationProvider::GetTabProcessID(int handle, int* process_id) {
   1009   *process_id = -1;
   1010 
   1011   if (tab_tracker_->ContainsHandle(handle)) {
   1012     *process_id = 0;
   1013     TabContents* tab_contents =
   1014         tab_tracker_->GetResource(handle)->tab_contents();
   1015     RenderProcessHost* rph = tab_contents->GetRenderProcessHost();
   1016     if (rph)
   1017       *process_id = base::GetProcId(rph->GetHandle());
   1018   }
   1019 }
   1020 
   1021 void TestingAutomationProvider::GetTabTitle(int handle,
   1022                                             int* title_string_size,
   1023                                             std::wstring* title) {
   1024   *title_string_size = -1;  // -1 is the error code
   1025   if (tab_tracker_->ContainsHandle(handle)) {
   1026     NavigationController* tab = tab_tracker_->GetResource(handle);
   1027     NavigationEntry* entry = tab->GetActiveEntry();
   1028     if (entry != NULL) {
   1029       *title = UTF16ToWideHack(entry->GetTitleForDisplay(""));
   1030     } else {
   1031       *title = std::wstring();
   1032     }
   1033     *title_string_size = static_cast<int>(title->size());
   1034   }
   1035 }
   1036 
   1037 void TestingAutomationProvider::GetTabIndex(int handle, int* tabstrip_index) {
   1038   *tabstrip_index = -1;  // -1 is the error code
   1039 
   1040   if (tab_tracker_->ContainsHandle(handle)) {
   1041     NavigationController* tab = tab_tracker_->GetResource(handle);
   1042     Browser* browser = Browser::GetBrowserForController(tab, NULL);
   1043     *tabstrip_index = browser->tabstrip_model()->GetIndexOfController(tab);
   1044   }
   1045 }
   1046 
   1047 void TestingAutomationProvider::GetTabURL(int handle,
   1048                                           bool* success,
   1049                                           GURL* url) {
   1050   *success = false;
   1051   if (tab_tracker_->ContainsHandle(handle)) {
   1052     NavigationController* tab = tab_tracker_->GetResource(handle);
   1053     // Return what the user would see in the location bar.
   1054     *url = tab->GetActiveEntry()->virtual_url();
   1055     *success = true;
   1056   }
   1057 }
   1058 
   1059 void TestingAutomationProvider::GetShelfVisibility(int handle, bool* visible) {
   1060   *visible = false;
   1061 
   1062   if (browser_tracker_->ContainsHandle(handle)) {
   1063     Browser* browser = browser_tracker_->GetResource(handle);
   1064     if (browser) {
   1065 #if defined(OS_CHROMEOS)
   1066       *visible = ActiveDownloadsUI::GetPopup(browser->profile());
   1067 #else
   1068       *visible = browser->window()->IsDownloadShelfVisible();
   1069 #endif
   1070     }
   1071   }
   1072 }
   1073 
   1074 void TestingAutomationProvider::IsFullscreen(int handle, bool* visible) {
   1075   *visible = false;
   1076 
   1077   if (browser_tracker_->ContainsHandle(handle)) {
   1078     Browser* browser = browser_tracker_->GetResource(handle);
   1079     if (browser)
   1080       *visible = browser->window()->IsFullscreen();
   1081   }
   1082 }
   1083 
   1084 void TestingAutomationProvider::GetFullscreenBubbleVisibility(int handle,
   1085                                                               bool* visible) {
   1086   *visible = false;
   1087 
   1088   if (browser_tracker_->ContainsHandle(handle)) {
   1089     Browser* browser = browser_tracker_->GetResource(handle);
   1090     if (browser)
   1091       *visible = browser->window()->IsFullscreenBubbleVisible();
   1092   }
   1093 }
   1094 
   1095 void TestingAutomationProvider::GetAutocompleteEditText(
   1096     int autocomplete_edit_handle,
   1097     bool* success,
   1098     string16* text) {
   1099   *success = false;
   1100   if (autocomplete_edit_tracker_->ContainsHandle(autocomplete_edit_handle)) {
   1101     *text = autocomplete_edit_tracker_->GetResource(autocomplete_edit_handle)->
   1102         GetText();
   1103     *success = true;
   1104   }
   1105 }
   1106 
   1107 void TestingAutomationProvider::SetAutocompleteEditText(
   1108     int autocomplete_edit_handle,
   1109     const string16& text,
   1110     bool* success) {
   1111   *success = false;
   1112   if (autocomplete_edit_tracker_->ContainsHandle(autocomplete_edit_handle)) {
   1113     autocomplete_edit_tracker_->GetResource(autocomplete_edit_handle)->
   1114         SetUserText(text);
   1115     *success = true;
   1116   }
   1117 }
   1118 
   1119 void TestingAutomationProvider::AutocompleteEditGetMatches(
   1120     int autocomplete_edit_handle,
   1121     bool* success,
   1122     std::vector<AutocompleteMatchData>* matches) {
   1123   *success = false;
   1124   if (autocomplete_edit_tracker_->ContainsHandle(autocomplete_edit_handle)) {
   1125     const AutocompleteResult& result = autocomplete_edit_tracker_->
   1126         GetResource(autocomplete_edit_handle)->model()->result();
   1127     for (AutocompleteResult::const_iterator i = result.begin();
   1128         i != result.end(); ++i)
   1129       matches->push_back(AutocompleteMatchData(*i));
   1130     *success = true;
   1131   }
   1132 }
   1133 
   1134 // Waits for the autocomplete edit to receive focus
   1135 void  TestingAutomationProvider::WaitForAutocompleteEditFocus(
   1136     int autocomplete_edit_handle,
   1137     IPC::Message* reply_message) {
   1138   if (!autocomplete_edit_tracker_->ContainsHandle(autocomplete_edit_handle)) {
   1139     AutomationMsg_WaitForAutocompleteEditFocus::WriteReplyParams(
   1140         reply_message_, false);
   1141     Send(reply_message);
   1142     return;
   1143   }
   1144 
   1145   AutocompleteEditModel* model = autocomplete_edit_tracker_->
   1146       GetResource(autocomplete_edit_handle)-> model();
   1147   if (model->has_focus()) {
   1148     AutomationMsg_WaitForAutocompleteEditFocus::WriteReplyParams(
   1149         reply_message, true);
   1150     Send(reply_message);
   1151     return;
   1152   }
   1153 
   1154   // The observer deletes itself when the notification arrives.
   1155   new AutocompleteEditFocusedObserver(this, model, reply_message);
   1156 }
   1157 
   1158 void TestingAutomationProvider::GetAutocompleteEditForBrowser(
   1159     int browser_handle,
   1160     bool* success,
   1161     int* autocomplete_edit_handle) {
   1162   *success = false;
   1163   *autocomplete_edit_handle = 0;
   1164 
   1165   if (browser_tracker_->ContainsHandle(browser_handle)) {
   1166     Browser* browser = browser_tracker_->GetResource(browser_handle);
   1167     LocationBar* loc_bar = browser->window()->GetLocationBar();
   1168     AutocompleteEditView* edit_view = loc_bar->location_entry();
   1169     // Add() returns the existing handle for the resource if any.
   1170     *autocomplete_edit_handle = autocomplete_edit_tracker_->Add(edit_view);
   1171     *success = true;
   1172   }
   1173 }
   1174 
   1175 void TestingAutomationProvider::AutocompleteEditIsQueryInProgress(
   1176     int autocomplete_edit_handle,
   1177     bool* success,
   1178     bool* query_in_progress) {
   1179   *success = false;
   1180   *query_in_progress = false;
   1181   if (autocomplete_edit_tracker_->ContainsHandle(autocomplete_edit_handle)) {
   1182     *query_in_progress = !autocomplete_edit_tracker_->
   1183         GetResource(autocomplete_edit_handle)->model()->
   1184         autocomplete_controller()->done();
   1185     *success = true;
   1186   }
   1187 }
   1188 
   1189 void TestingAutomationProvider::ExecuteJavascript(
   1190     int handle,
   1191     const std::wstring& frame_xpath,
   1192     const std::wstring& script,
   1193     IPC::Message* reply_message) {
   1194   TabContents* tab_contents = GetTabContentsForHandle(handle, NULL);
   1195   if (!tab_contents) {
   1196     AutomationMsg_DomOperation::WriteReplyParams(reply_message, std::string());
   1197     Send(reply_message);
   1198     return;
   1199   }
   1200 
   1201   // Set the routing id of this message with the controller.
   1202   // This routing id needs to be remembered for the reverse
   1203   // communication while sending back the response of
   1204   // this javascript execution.
   1205   std::string set_automation_id;
   1206   base::SStringPrintf(&set_automation_id,
   1207                       "window.domAutomationController.setAutomationId(%d);",
   1208                       reply_message->routing_id());
   1209 
   1210   new DomOperationMessageSender(this, reply_message, false);
   1211   tab_contents->render_view_host()->ExecuteJavascriptInWebFrame(
   1212       WideToUTF16Hack(frame_xpath), UTF8ToUTF16(set_automation_id));
   1213   tab_contents->render_view_host()->ExecuteJavascriptInWebFrame(
   1214       WideToUTF16Hack(frame_xpath), WideToUTF16Hack(script));
   1215 }
   1216 
   1217 void TestingAutomationProvider::GetConstrainedWindowCount(int handle,
   1218                                                           int* count) {
   1219   *count = -1;  // -1 is the error code
   1220   if (tab_tracker_->ContainsHandle(handle)) {
   1221     NavigationController* nav_controller = tab_tracker_->GetResource(handle);
   1222     TabContents* tab_contents = nav_controller->tab_contents();
   1223     if (tab_contents)
   1224       *count = static_cast<int>(tab_contents->child_windows_.size());
   1225   }
   1226 }
   1227 
   1228 void TestingAutomationProvider::HandleInspectElementRequest(
   1229     int handle, int x, int y, IPC::Message* reply_message) {
   1230   TabContents* tab_contents = GetTabContentsForHandle(handle, NULL);
   1231   if (tab_contents) {
   1232     DCHECK(!reply_message_);
   1233     reply_message_ = reply_message;
   1234 
   1235     DevToolsManager::GetInstance()->InspectElement(
   1236         tab_contents->render_view_host(), x, y);
   1237   } else {
   1238     AutomationMsg_InspectElement::WriteReplyParams(reply_message, -1);
   1239     Send(reply_message);
   1240   }
   1241 }
   1242 
   1243 void TestingAutomationProvider::GetDownloadDirectory(
   1244     int handle, FilePath* download_directory) {
   1245   if (tab_tracker_->ContainsHandle(handle)) {
   1246     NavigationController* tab = tab_tracker_->GetResource(handle);
   1247     DownloadManager* dlm = tab->profile()->GetDownloadManager();
   1248     *download_directory = dlm->download_prefs()->download_path();
   1249   }
   1250 }
   1251 
   1252 void TestingAutomationProvider::OpenNewBrowserWindowOfType(
   1253     int type, bool show, IPC::Message* reply_message) {
   1254   new BrowserOpenedNotificationObserver(this, reply_message);
   1255   // We may have no current browser windows open so don't rely on
   1256   // asking an existing browser to execute the IDC_NEWWINDOW command
   1257   Browser* browser = new Browser(static_cast<Browser::Type>(type), profile_);
   1258   browser->InitBrowserWindow();
   1259   browser->AddBlankTab(true);
   1260   if (show)
   1261     browser->window()->Show();
   1262 }
   1263 
   1264 void TestingAutomationProvider::GetWindowForBrowser(int browser_handle,
   1265                                                     bool* success,
   1266                                                     int* handle) {
   1267   *success = false;
   1268   *handle = 0;
   1269 
   1270   if (browser_tracker_->ContainsHandle(browser_handle)) {
   1271     Browser* browser = browser_tracker_->GetResource(browser_handle);
   1272     gfx::NativeWindow win = browser->window()->GetNativeHandle();
   1273     // Add() returns the existing handle for the resource if any.
   1274     *handle = window_tracker_->Add(win);
   1275     *success = true;
   1276   }
   1277 }
   1278 
   1279 void TestingAutomationProvider::GetBrowserForWindow(int window_handle,
   1280                                                     bool* success,
   1281                                                     int* browser_handle) {
   1282   *success = false;
   1283   *browser_handle = 0;
   1284 
   1285   gfx::NativeWindow window = window_tracker_->GetResource(window_handle);
   1286   if (!window)
   1287     return;
   1288 
   1289   BrowserList::const_iterator iter = BrowserList::begin();
   1290   for (;iter != BrowserList::end(); ++iter) {
   1291     gfx::NativeWindow this_window = (*iter)->window()->GetNativeHandle();
   1292     if (window == this_window) {
   1293       // Add() returns the existing handle for the resource if any.
   1294       *browser_handle = browser_tracker_->Add(*iter);
   1295       *success = true;
   1296       return;
   1297     }
   1298   }
   1299 }
   1300 
   1301 void TestingAutomationProvider::ShowInterstitialPage(
   1302     int tab_handle,
   1303     const std::string& html_text,
   1304     IPC::Message* reply_message) {
   1305   if (tab_tracker_->ContainsHandle(tab_handle)) {
   1306     NavigationController* controller = tab_tracker_->GetResource(tab_handle);
   1307     TabContents* tab_contents = controller->tab_contents();
   1308 
   1309     new NavigationNotificationObserver(controller, this, reply_message, 1,
   1310                                        false, false);
   1311 
   1312     AutomationInterstitialPage* interstitial =
   1313         new AutomationInterstitialPage(tab_contents,
   1314                                        GURL("about:interstitial"),
   1315                                        html_text);
   1316     interstitial->Show();
   1317     return;
   1318   }
   1319 
   1320   AutomationMsg_ShowInterstitialPage::WriteReplyParams(
   1321       reply_message, AUTOMATION_MSG_NAVIGATION_ERROR);
   1322   Send(reply_message);
   1323 }
   1324 
   1325 void TestingAutomationProvider::HideInterstitialPage(int tab_handle,
   1326                                                      bool* success) {
   1327   *success = false;
   1328   TabContents* tab_contents = GetTabContentsForHandle(tab_handle, NULL);
   1329   if (tab_contents && tab_contents->interstitial_page()) {
   1330     tab_contents->interstitial_page()->DontProceed();
   1331     *success = true;
   1332   }
   1333 }
   1334 
   1335 void TestingAutomationProvider::WaitForTabToBeRestored(
   1336     int tab_handle,
   1337     IPC::Message* reply_message) {
   1338   if (tab_tracker_->ContainsHandle(tab_handle)) {
   1339     NavigationController* tab = tab_tracker_->GetResource(tab_handle);
   1340     restore_tracker_.reset(
   1341         new NavigationControllerRestoredObserver(this, tab, reply_message));
   1342   } else {
   1343     AutomationMsg_WaitForTabToBeRestored::WriteReplyParams(
   1344         reply_message, false);
   1345     Send(reply_message);
   1346   }
   1347 }
   1348 
   1349 void TestingAutomationProvider::GetSecurityState(int handle,
   1350                                                  bool* success,
   1351                                                  SecurityStyle* security_style,
   1352                                                  int* ssl_cert_status,
   1353                                                  int* insecure_content_status) {
   1354   if (tab_tracker_->ContainsHandle(handle)) {
   1355     NavigationController* tab = tab_tracker_->GetResource(handle);
   1356     NavigationEntry* entry = tab->GetActiveEntry();
   1357     *success = true;
   1358     *security_style = entry->ssl().security_style();
   1359     *ssl_cert_status = entry->ssl().cert_status();
   1360     *insecure_content_status = entry->ssl().content_status();
   1361   } else {
   1362     *success = false;
   1363     *security_style = SECURITY_STYLE_UNKNOWN;
   1364     *ssl_cert_status = 0;
   1365     *insecure_content_status = 0;
   1366   }
   1367 }
   1368 
   1369 void TestingAutomationProvider::GetPageType(
   1370     int handle,
   1371     bool* success,
   1372     PageType* page_type) {
   1373   if (tab_tracker_->ContainsHandle(handle)) {
   1374     NavigationController* tab = tab_tracker_->GetResource(handle);
   1375     NavigationEntry* entry = tab->GetActiveEntry();
   1376     *page_type = entry->page_type();
   1377     *success = true;
   1378     // In order to return the proper result when an interstitial is shown and
   1379     // no navigation entry were created for it we need to ask the TabContents.
   1380     if (*page_type == NORMAL_PAGE &&
   1381         tab->tab_contents()->showing_interstitial_page())
   1382       *page_type = INTERSTITIAL_PAGE;
   1383   } else {
   1384     *success = false;
   1385     *page_type = NORMAL_PAGE;
   1386   }
   1387 }
   1388 
   1389 void TestingAutomationProvider::GetMetricEventDuration(
   1390     const std::string& event_name,
   1391     int* duration_ms) {
   1392   *duration_ms = metric_event_duration_observer_->GetEventDurationMs(
   1393       event_name);
   1394 }
   1395 
   1396 void TestingAutomationProvider::ActionOnSSLBlockingPage(
   1397     int handle,
   1398     bool proceed,
   1399     IPC::Message* reply_message) {
   1400   if (tab_tracker_->ContainsHandle(handle)) {
   1401     NavigationController* tab = tab_tracker_->GetResource(handle);
   1402     NavigationEntry* entry = tab->GetActiveEntry();
   1403     if (entry->page_type() == INTERSTITIAL_PAGE) {
   1404       TabContents* tab_contents = tab->tab_contents();
   1405       InterstitialPage* ssl_blocking_page =
   1406           InterstitialPage::GetInterstitialPage(tab_contents);
   1407       if (ssl_blocking_page) {
   1408         if (proceed) {
   1409           new NavigationNotificationObserver(tab, this, reply_message, 1,
   1410                                              false, false);
   1411           ssl_blocking_page->Proceed();
   1412           return;
   1413         }
   1414         ssl_blocking_page->DontProceed();
   1415         AutomationMsg_ActionOnSSLBlockingPage::WriteReplyParams(
   1416             reply_message, AUTOMATION_MSG_NAVIGATION_SUCCESS);
   1417         Send(reply_message);
   1418         return;
   1419       }
   1420     }
   1421   }
   1422   // We failed.
   1423   AutomationMsg_ActionOnSSLBlockingPage::WriteReplyParams(
   1424       reply_message, AUTOMATION_MSG_NAVIGATION_ERROR);
   1425   Send(reply_message);
   1426 }
   1427 
   1428 void TestingAutomationProvider::BringBrowserToFront(int browser_handle,
   1429                                                     bool* success) {
   1430   *success = false;
   1431   if (browser_tracker_->ContainsHandle(browser_handle)) {
   1432     Browser* browser = browser_tracker_->GetResource(browser_handle);
   1433     browser->window()->Activate();
   1434     *success = true;
   1435   }
   1436 }
   1437 
   1438 void TestingAutomationProvider::IsMenuCommandEnabled(int browser_handle,
   1439                                                      int message_num,
   1440                                                      bool* menu_item_enabled) {
   1441   *menu_item_enabled = false;
   1442   if (browser_tracker_->ContainsHandle(browser_handle)) {
   1443     Browser* browser = browser_tracker_->GetResource(browser_handle);
   1444     *menu_item_enabled =
   1445         browser->command_updater()->IsCommandEnabled(message_num);
   1446   }
   1447 }
   1448 
   1449 void TestingAutomationProvider::PrintNow(int tab_handle,
   1450                                          IPC::Message* reply_message) {
   1451   NavigationController* tab = NULL;
   1452   TabContents* tab_contents = GetTabContentsForHandle(tab_handle, &tab);
   1453   if (tab_contents) {
   1454     FindAndActivateTab(tab);
   1455 
   1456     NotificationObserver* observer =
   1457         new DocumentPrintedNotificationObserver(this, reply_message);
   1458 
   1459     TabContentsWrapper* wrapper =
   1460         TabContentsWrapper::GetCurrentWrapperForContents(tab_contents);
   1461     if (!wrapper->print_view_manager()->PrintNow()) {
   1462       // Clean up the observer. It will send the reply message.
   1463       delete observer;
   1464     }
   1465 
   1466     // Return now to avoid sending reply message twice.
   1467     return;
   1468   }
   1469 
   1470   AutomationMsg_PrintNow::WriteReplyParams(reply_message, false);
   1471   Send(reply_message);
   1472 }
   1473 
   1474 void TestingAutomationProvider::SavePage(int tab_handle,
   1475                                          const FilePath& file_name,
   1476                                          const FilePath& dir_path,
   1477                                          int type,
   1478                                          bool* success) {
   1479   SavePackage::SavePackageType save_type =
   1480       static_cast<SavePackage::SavePackageType>(type);
   1481   if (save_type < SavePackage::SAVE_AS_ONLY_HTML ||
   1482       save_type > SavePackage::SAVE_AS_COMPLETE_HTML) {
   1483     *success = false;
   1484     return;
   1485   }
   1486 
   1487   if (!tab_tracker_->ContainsHandle(tab_handle)) {
   1488     *success = false;
   1489     return;
   1490   }
   1491 
   1492   NavigationController* nav = tab_tracker_->GetResource(tab_handle);
   1493   Browser* browser = FindAndActivateTab(nav);
   1494   if (!browser->command_updater()->IsCommandEnabled(IDC_SAVE_PAGE)) {
   1495     *success = false;
   1496     return;
   1497   }
   1498 
   1499   TabContentsWrapper* wrapper =
   1500       TabContentsWrapper::GetCurrentWrapperForContents(nav->tab_contents());
   1501   wrapper->download_tab_helper()->SavePage(file_name, dir_path, save_type);
   1502   *success = true;
   1503 }
   1504 
   1505 void TestingAutomationProvider::HandleOpenFindInPageRequest(
   1506     const IPC::Message& message, int handle) {
   1507   if (browser_tracker_->ContainsHandle(handle)) {
   1508     Browser* browser = browser_tracker_->GetResource(handle);
   1509     browser->FindInPage(false, false);
   1510   }
   1511 }
   1512 
   1513 void TestingAutomationProvider::GetFindWindowVisibility(int handle,
   1514                                                         bool* visible) {
   1515   *visible = false;
   1516   Browser* browser = browser_tracker_->GetResource(handle);
   1517   if (browser) {
   1518     FindBarTesting* find_bar =
   1519         browser->GetFindBarController()->find_bar()->GetFindBarTesting();
   1520     find_bar->GetFindBarWindowInfo(NULL, visible);
   1521   }
   1522 }
   1523 
   1524 void TestingAutomationProvider::HandleFindWindowLocationRequest(int handle,
   1525                                                                 int* x,
   1526                                                                 int* y) {
   1527   gfx::Point position(0, 0);
   1528   bool visible = false;
   1529   if (browser_tracker_->ContainsHandle(handle)) {
   1530      Browser* browser = browser_tracker_->GetResource(handle);
   1531      FindBarTesting* find_bar =
   1532        browser->GetFindBarController()->find_bar()->GetFindBarTesting();
   1533      find_bar->GetFindBarWindowInfo(&position, &visible);
   1534   }
   1535 
   1536   *x = position.x();
   1537   *y = position.y();
   1538 }
   1539 
   1540 // Bookmark bar visibility is based on the pref (e.g. is it in the toolbar).
   1541 // Presence in the NTP is NOT considered visible by this call.
   1542 void TestingAutomationProvider::GetBookmarkBarVisibility(int handle,
   1543                                                          bool* visible,
   1544                                                          bool* animating) {
   1545   *visible = false;
   1546   *animating = false;
   1547 
   1548   if (browser_tracker_->ContainsHandle(handle)) {
   1549     Browser* browser = browser_tracker_->GetResource(handle);
   1550     if (browser) {
   1551 #if 0  // defined(TOOLKIT_VIEWS) && defined(OS_LINUX)
   1552       // TODO(jrg): Was removed in rev43789 for perf. Need to investigate.
   1553 
   1554       // IsBookmarkBarVisible() line looks correct but is not
   1555       // consistent across platforms.  Specifically, on Mac/Linux, it
   1556       // returns false if the bar is hidden in a pref (even if visible
   1557       // on the NTP).  On ChromeOS, it returned true if on NTP
   1558       // independent of the pref.  Making the code more consistent
   1559       // caused a perf bot regression on Windows (which shares views).
   1560       // See http://crbug.com/40225
   1561       *visible = browser->profile()->GetPrefs()->GetBoolean(
   1562           prefs::kShowBookmarkBar);
   1563 #else
   1564       *visible = browser->window()->IsBookmarkBarVisible();
   1565 #endif
   1566       *animating = browser->window()->IsBookmarkBarAnimating();
   1567     }
   1568   }
   1569 }
   1570 
   1571 void TestingAutomationProvider::GetBookmarksAsJSON(
   1572     int handle,
   1573     std::string* bookmarks_as_json,
   1574     bool *success) {
   1575   *success = false;
   1576   if (browser_tracker_->ContainsHandle(handle)) {
   1577     Browser* browser = browser_tracker_->GetResource(handle);
   1578     if (browser) {
   1579       if (!browser->profile()->GetBookmarkModel()->IsLoaded()) {
   1580         return;
   1581       }
   1582       scoped_refptr<BookmarkStorage> storage(new BookmarkStorage(
   1583           browser->profile(),
   1584           browser->profile()->GetBookmarkModel()));
   1585       *success = storage->SerializeData(bookmarks_as_json);
   1586     }
   1587   }
   1588 }
   1589 
   1590 void TestingAutomationProvider::WaitForBookmarkModelToLoad(
   1591     int handle,
   1592     IPC::Message* reply_message) {
   1593   if (browser_tracker_->ContainsHandle(handle)) {
   1594     Browser* browser = browser_tracker_->GetResource(handle);
   1595     BookmarkModel* model = browser->profile()->GetBookmarkModel();
   1596     if (model->IsLoaded()) {
   1597       AutomationMsg_WaitForBookmarkModelToLoad::WriteReplyParams(
   1598           reply_message, true);
   1599       Send(reply_message);
   1600     } else {
   1601       // The observer will delete itself when done.
   1602       new AutomationProviderBookmarkModelObserver(this, reply_message,
   1603                                                   model);
   1604     }
   1605   }
   1606 }
   1607 
   1608 void TestingAutomationProvider::AddBookmarkGroup(int handle,
   1609                                                  int64 parent_id,
   1610                                                  int index,
   1611                                                  std::wstring title,
   1612                                                  bool* success) {
   1613   if (browser_tracker_->ContainsHandle(handle)) {
   1614     Browser* browser = browser_tracker_->GetResource(handle);
   1615     if (browser) {
   1616       BookmarkModel* model = browser->profile()->GetBookmarkModel();
   1617       if (!model->IsLoaded()) {
   1618         *success = false;
   1619         return;
   1620       }
   1621       const BookmarkNode* parent = model->GetNodeByID(parent_id);
   1622       DCHECK(parent);
   1623       if (parent) {
   1624         const BookmarkNode* child = model->AddFolder(parent, index,
   1625                                                      WideToUTF16Hack(title));
   1626         DCHECK(child);
   1627         if (child)
   1628           *success = true;
   1629       }
   1630     }
   1631   }
   1632   *success = false;
   1633 }
   1634 
   1635 void TestingAutomationProvider::AddBookmarkURL(int handle,
   1636                                                int64 parent_id,
   1637                                                int index,
   1638                                                std::wstring title,
   1639                                                const GURL& url,
   1640                                                bool* success) {
   1641   if (browser_tracker_->ContainsHandle(handle)) {
   1642     Browser* browser = browser_tracker_->GetResource(handle);
   1643     if (browser) {
   1644       BookmarkModel* model = browser->profile()->GetBookmarkModel();
   1645       if (!model->IsLoaded()) {
   1646         *success = false;
   1647         return;
   1648       }
   1649       const BookmarkNode* parent = model->GetNodeByID(parent_id);
   1650       DCHECK(parent);
   1651       if (parent) {
   1652         const BookmarkNode* child = model->AddURL(parent, index,
   1653                                                   WideToUTF16Hack(title), url);
   1654         DCHECK(child);
   1655         if (child)
   1656           *success = true;
   1657       }
   1658     }
   1659   }
   1660   *success = false;
   1661 }
   1662 
   1663 void TestingAutomationProvider::ReparentBookmark(int handle,
   1664                                                  int64 id,
   1665                                                  int64 new_parent_id,
   1666                                                  int index,
   1667                                                  bool* success) {
   1668   if (browser_tracker_->ContainsHandle(handle)) {
   1669     Browser* browser = browser_tracker_->GetResource(handle);
   1670     if (browser) {
   1671       BookmarkModel* model = browser->profile()->GetBookmarkModel();
   1672       if (!model->IsLoaded()) {
   1673         *success = false;
   1674         return;
   1675       }
   1676       const BookmarkNode* node = model->GetNodeByID(id);
   1677       DCHECK(node);
   1678       const BookmarkNode* new_parent = model->GetNodeByID(new_parent_id);
   1679       DCHECK(new_parent);
   1680       if (node && new_parent) {
   1681         model->Move(node, new_parent, index);
   1682         *success = true;
   1683       }
   1684     }
   1685   }
   1686   *success = false;
   1687 }
   1688 
   1689 void TestingAutomationProvider::SetBookmarkTitle(int handle,
   1690                                                  int64 id,
   1691                                                  std::wstring title,
   1692                                                  bool* success) {
   1693   if (browser_tracker_->ContainsHandle(handle)) {
   1694     Browser* browser = browser_tracker_->GetResource(handle);
   1695     if (browser) {
   1696       BookmarkModel* model = browser->profile()->GetBookmarkModel();
   1697       if (!model->IsLoaded()) {
   1698         *success = false;
   1699         return;
   1700       }
   1701       const BookmarkNode* node = model->GetNodeByID(id);
   1702       DCHECK(node);
   1703       if (node) {
   1704         model->SetTitle(node, WideToUTF16Hack(title));
   1705         *success = true;
   1706       }
   1707     }
   1708   }
   1709   *success = false;
   1710 }
   1711 
   1712 void TestingAutomationProvider::SetBookmarkURL(int handle,
   1713                                                int64 id,
   1714                                                const GURL& url,
   1715                                                bool* success) {
   1716   if (browser_tracker_->ContainsHandle(handle)) {
   1717     Browser* browser = browser_tracker_->GetResource(handle);
   1718     if (browser) {
   1719       BookmarkModel* model = browser->profile()->GetBookmarkModel();
   1720       if (!model->IsLoaded()) {
   1721         *success = false;
   1722         return;
   1723       }
   1724       const BookmarkNode* node = model->GetNodeByID(id);
   1725       DCHECK(node);
   1726       if (node) {
   1727         model->SetURL(node, url);
   1728         *success = true;
   1729       }
   1730     }
   1731   }
   1732   *success = false;
   1733 }
   1734 
   1735 void TestingAutomationProvider::RemoveBookmark(int handle,
   1736                                                int64 id,
   1737                                                bool* success) {
   1738   if (browser_tracker_->ContainsHandle(handle)) {
   1739     Browser* browser = browser_tracker_->GetResource(handle);
   1740     if (browser) {
   1741       BookmarkModel* model = browser->profile()->GetBookmarkModel();
   1742       if (!model->IsLoaded()) {
   1743         *success = false;
   1744         return;
   1745       }
   1746       const BookmarkNode* node = model->GetNodeByID(id);
   1747       DCHECK(node);
   1748       if (node) {
   1749         const BookmarkNode* parent = node->parent();
   1750         DCHECK(parent);
   1751         model->Remove(parent, parent->GetIndexOf(node));
   1752         *success = true;
   1753       }
   1754     }
   1755   }
   1756   *success = false;
   1757 }
   1758 
   1759 void TestingAutomationProvider::GetInfoBarCount(int handle, size_t* count) {
   1760   *count = static_cast<size_t>(-1);  // -1 means error.
   1761   if (tab_tracker_->ContainsHandle(handle)) {
   1762     NavigationController* nav_controller = tab_tracker_->GetResource(handle);
   1763     if (nav_controller)
   1764       *count = nav_controller->tab_contents()->infobar_count();
   1765   }
   1766 }
   1767 
   1768 void TestingAutomationProvider::ClickInfoBarAccept(
   1769     int handle,
   1770     size_t info_bar_index,
   1771     bool wait_for_navigation,
   1772     IPC::Message* reply_message) {
   1773   bool success = false;
   1774   if (tab_tracker_->ContainsHandle(handle)) {
   1775     NavigationController* nav_controller = tab_tracker_->GetResource(handle);
   1776     if (nav_controller) {
   1777       if (info_bar_index < nav_controller->tab_contents()->infobar_count()) {
   1778         if (wait_for_navigation) {
   1779           new NavigationNotificationObserver(nav_controller, this,
   1780                                              reply_message, 1, false, false);
   1781         }
   1782         InfoBarDelegate* delegate =
   1783             nav_controller->tab_contents()->GetInfoBarDelegateAt(
   1784                 info_bar_index);
   1785         if (delegate->AsConfirmInfoBarDelegate())
   1786           delegate->AsConfirmInfoBarDelegate()->Accept();
   1787         success = true;
   1788       }
   1789     }
   1790   }
   1791 
   1792   // This "!wait_for_navigation || !success condition" logic looks suspicious.
   1793   // It will send a failure message when success is true but
   1794   // |wait_for_navigation| is false.
   1795   // TODO(phajdan.jr): investgate whether the reply param (currently
   1796   // AUTOMATION_MSG_NAVIGATION_ERROR) should depend on success.
   1797   if (!wait_for_navigation || !success)
   1798     AutomationMsg_ClickInfoBarAccept::WriteReplyParams(
   1799         reply_message, AUTOMATION_MSG_NAVIGATION_ERROR);
   1800 }
   1801 
   1802 void TestingAutomationProvider::GetLastNavigationTime(
   1803     int handle,
   1804     int64* last_navigation_time) {
   1805   base::Time time(tab_tracker_->GetLastNavigationTime(handle));
   1806   *last_navigation_time = time.ToInternalValue();
   1807 }
   1808 
   1809 void TestingAutomationProvider::WaitForNavigation(int handle,
   1810                                                   int64 last_navigation_time,
   1811                                                   IPC::Message* reply_message) {
   1812   NavigationController* controller = tab_tracker_->GetResource(handle);
   1813   base::Time time(tab_tracker_->GetLastNavigationTime(handle));
   1814 
   1815   if (time.ToInternalValue() > last_navigation_time || !controller) {
   1816     AutomationMsg_WaitForNavigation::WriteReplyParams(reply_message,
   1817         controller == NULL ? AUTOMATION_MSG_NAVIGATION_ERROR :
   1818                              AUTOMATION_MSG_NAVIGATION_SUCCESS);
   1819     Send(reply_message);
   1820     return;
   1821   }
   1822 
   1823   new NavigationNotificationObserver(
   1824       controller, this, reply_message, 1, true, false);
   1825 }
   1826 
   1827 void TestingAutomationProvider::SetIntPreference(int handle,
   1828                                                  const std::string& name,
   1829                                                  int value,
   1830                                                  bool* success) {
   1831   *success = false;
   1832   if (browser_tracker_->ContainsHandle(handle)) {
   1833     Browser* browser = browser_tracker_->GetResource(handle);
   1834     browser->profile()->GetPrefs()->SetInteger(name.c_str(), value);
   1835     *success = true;
   1836   }
   1837 }
   1838 
   1839 void TestingAutomationProvider::SetStringPreference(int handle,
   1840                                                     const std::string& name,
   1841                                                     const std::string& value,
   1842                                                     bool* success) {
   1843   *success = false;
   1844   if (browser_tracker_->ContainsHandle(handle)) {
   1845     Browser* browser = browser_tracker_->GetResource(handle);
   1846     browser->profile()->GetPrefs()->SetString(name.c_str(), value);
   1847     *success = true;
   1848   }
   1849 }
   1850 
   1851 void TestingAutomationProvider::GetBooleanPreference(int handle,
   1852                                                      const std::string& name,
   1853                                                      bool* success,
   1854                                                      bool* value) {
   1855   *success = false;
   1856   *value = false;
   1857   if (browser_tracker_->ContainsHandle(handle)) {
   1858     Browser* browser = browser_tracker_->GetResource(handle);
   1859     *value = browser->profile()->GetPrefs()->GetBoolean(name.c_str());
   1860     *success = true;
   1861   }
   1862 }
   1863 
   1864 void TestingAutomationProvider::SetBooleanPreference(int handle,
   1865                                                      const std::string& name,
   1866                                                      bool value,
   1867                                                      bool* success) {
   1868   *success = false;
   1869   if (browser_tracker_->ContainsHandle(handle)) {
   1870     Browser* browser = browser_tracker_->GetResource(handle);
   1871     browser->profile()->GetPrefs()->SetBoolean(name.c_str(), value);
   1872     *success = true;
   1873   }
   1874 }
   1875 
   1876 void TestingAutomationProvider::GetShowingAppModalDialog(bool* showing_dialog,
   1877                                                          int* dialog_button) {
   1878   AppModalDialog* active_dialog =
   1879       AppModalDialogQueue::GetInstance()->active_dialog();
   1880   if (!active_dialog) {
   1881     *showing_dialog = false;
   1882     *dialog_button = ui::MessageBoxFlags::DIALOGBUTTON_NONE;
   1883     return;
   1884   }
   1885   NativeAppModalDialog* native_dialog = active_dialog->native_dialog();
   1886   *showing_dialog = (native_dialog != NULL);
   1887   if (*showing_dialog)
   1888     *dialog_button = native_dialog->GetAppModalDialogButtons();
   1889   else
   1890     *dialog_button = ui::MessageBoxFlags::DIALOGBUTTON_NONE;
   1891 }
   1892 
   1893 void TestingAutomationProvider::ClickAppModalDialogButton(int button,
   1894                                                           bool* success) {
   1895   *success = false;
   1896 
   1897   NativeAppModalDialog* native_dialog =
   1898       AppModalDialogQueue::GetInstance()->active_dialog()->native_dialog();
   1899   if (native_dialog &&
   1900       (native_dialog->GetAppModalDialogButtons() & button) == button) {
   1901     if ((button & ui::MessageBoxFlags::DIALOGBUTTON_OK) ==
   1902         ui::MessageBoxFlags::DIALOGBUTTON_OK) {
   1903       native_dialog->AcceptAppModalDialog();
   1904       *success =  true;
   1905     }
   1906     if ((button & ui::MessageBoxFlags::DIALOGBUTTON_CANCEL) ==
   1907         ui::MessageBoxFlags::DIALOGBUTTON_CANCEL) {
   1908       DCHECK(!*success) << "invalid param, OK and CANCEL specified";
   1909       native_dialog->CancelAppModalDialog();
   1910       *success =  true;
   1911     }
   1912   }
   1913 }
   1914 
   1915 void TestingAutomationProvider::WaitForBrowserWindowCountToBecome(
   1916     int target_count,
   1917     IPC::Message* reply_message) {
   1918   if (static_cast<int>(BrowserList::size()) == target_count) {
   1919     AutomationMsg_WaitForBrowserWindowCountToBecome::WriteReplyParams(
   1920         reply_message, true);
   1921     Send(reply_message);
   1922     return;
   1923   }
   1924 
   1925   // Set up an observer (it will delete itself).
   1926   new BrowserCountChangeNotificationObserver(target_count, this, reply_message);
   1927 }
   1928 
   1929 void TestingAutomationProvider::WaitForAppModalDialogToBeShown(
   1930     IPC::Message* reply_message) {
   1931   if (AppModalDialogQueue::GetInstance()->HasActiveDialog()) {
   1932     AutomationMsg_WaitForAppModalDialogToBeShown::WriteReplyParams(
   1933         reply_message, true);
   1934     Send(reply_message);
   1935     return;
   1936   }
   1937 
   1938   // Set up an observer (it will delete itself).
   1939   new AppModalDialogShownObserver(this, reply_message);
   1940 }
   1941 
   1942 void TestingAutomationProvider::GoBackBlockUntilNavigationsComplete(
   1943     int handle, int number_of_navigations, IPC::Message* reply_message) {
   1944   if (tab_tracker_->ContainsHandle(handle)) {
   1945     NavigationController* tab = tab_tracker_->GetResource(handle);
   1946     Browser* browser = FindAndActivateTab(tab);
   1947     if (browser && browser->command_updater()->IsCommandEnabled(IDC_BACK)) {
   1948       new NavigationNotificationObserver(tab, this, reply_message,
   1949                                          number_of_navigations, false, false);
   1950       browser->GoBack(CURRENT_TAB);
   1951       return;
   1952     }
   1953   }
   1954 
   1955   AutomationMsg_GoBackBlockUntilNavigationsComplete::WriteReplyParams(
   1956       reply_message, AUTOMATION_MSG_NAVIGATION_ERROR);
   1957   Send(reply_message);
   1958 }
   1959 
   1960 void TestingAutomationProvider::GoForwardBlockUntilNavigationsComplete(
   1961     int handle, int number_of_navigations, IPC::Message* reply_message) {
   1962   if (tab_tracker_->ContainsHandle(handle)) {
   1963     NavigationController* tab = tab_tracker_->GetResource(handle);
   1964     Browser* browser = FindAndActivateTab(tab);
   1965     if (browser && browser->command_updater()->IsCommandEnabled(IDC_FORWARD)) {
   1966       new NavigationNotificationObserver(tab, this, reply_message,
   1967                                          number_of_navigations, false, false);
   1968       browser->GoForward(CURRENT_TAB);
   1969       return;
   1970     }
   1971   }
   1972 
   1973   AutomationMsg_GoForwardBlockUntilNavigationsComplete::WriteReplyParams(
   1974       reply_message, AUTOMATION_MSG_NAVIGATION_ERROR);
   1975   Send(reply_message);
   1976 }
   1977 
   1978 void TestingAutomationProvider::SavePackageShouldPromptUser(
   1979     bool should_prompt) {
   1980   SavePackage::SetShouldPromptUser(should_prompt);
   1981 }
   1982 
   1983 void TestingAutomationProvider::SetShelfVisibility(int handle, bool visible) {
   1984   if (browser_tracker_->ContainsHandle(handle)) {
   1985     Browser* browser = browser_tracker_->GetResource(handle);
   1986     if (browser) {
   1987 #if defined(OS_CHROMEOS)
   1988       Browser* popup_browser =
   1989           ActiveDownloadsUI::GetPopup(browser->profile());
   1990       if (!popup_browser && visible)
   1991         ActiveDownloadsUI::OpenPopup(browser->profile());
   1992       if (popup_browser && !visible)
   1993         popup_browser->CloseWindow();
   1994 #else
   1995       if (visible)
   1996         browser->window()->GetDownloadShelf()->Show();
   1997       else
   1998         browser->window()->GetDownloadShelf()->Close();
   1999 #endif
   2000     }
   2001   }
   2002 }
   2003 
   2004 void TestingAutomationProvider::GetBlockedPopupCount(int handle, int* count) {
   2005   *count = -1;  // -1 is the error code
   2006   if (tab_tracker_->ContainsHandle(handle)) {
   2007       NavigationController* nav_controller = tab_tracker_->GetResource(handle);
   2008       TabContents* tab_contents = nav_controller->tab_contents();
   2009       if (tab_contents) {
   2010         BlockedContentContainer* container =
   2011             tab_contents->blocked_content_container();
   2012         if (container) {
   2013           *count = static_cast<int>(container->GetBlockedContentsCount());
   2014         } else {
   2015           // If we don't have a container, we don't have any blocked popups to
   2016           // contain!
   2017           *count = 0;
   2018         }
   2019       }
   2020   }
   2021 }
   2022 
   2023 void TestingAutomationProvider::SendJSONRequest(int handle,
   2024                                                 const std::string& json_request,
   2025                                                 IPC::Message* reply_message) {
   2026   scoped_ptr<Value> values;
   2027   base::JSONReader reader;
   2028   std::string error;
   2029   values.reset(reader.ReadAndReturnError(json_request, true, NULL, &error));
   2030   if (!error.empty()) {
   2031     AutomationJSONReply(this, reply_message).SendError(error);
   2032     return;
   2033   }
   2034 
   2035   // Make sure input is a dict with a string command.
   2036   std::string command;
   2037   DictionaryValue* dict_value = NULL;
   2038   if (values->GetType() != Value::TYPE_DICTIONARY) {
   2039     AutomationJSONReply(this, reply_message).SendError("not a dict");
   2040     return;
   2041   }
   2042   // Ownership remains with "values" variable.
   2043   dict_value = static_cast<DictionaryValue*>(values.get());
   2044   if (!dict_value->GetStringASCII(std::string("command"), &command)) {
   2045     AutomationJSONReply(this, reply_message)
   2046         .SendError("no command key in dict or not a string command");
   2047     return;
   2048   }
   2049 
   2050   // Map json commands to their handlers.
   2051   std::map<std::string, JsonHandler> handler_map;
   2052   handler_map["WaitForAllTabsToStopLoading"] =
   2053       &TestingAutomationProvider::WaitForAllTabsToStopLoading;
   2054   handler_map["GetIndicesFromTab"] =
   2055       &TestingAutomationProvider::GetIndicesFromTab;
   2056   handler_map["NavigateToURL"] =
   2057       &TestingAutomationProvider::NavigateToURL;
   2058   handler_map["ExecuteJavascript"] =
   2059       &TestingAutomationProvider::ExecuteJavascriptJSON;
   2060   handler_map["GoForward"] =
   2061       &TestingAutomationProvider::GoForward;
   2062   handler_map["GoBack"] =
   2063       &TestingAutomationProvider::GoBack;
   2064   handler_map["Reload"] =
   2065       &TestingAutomationProvider::ReloadJSON;
   2066   handler_map["GetTabURL"] =
   2067       &TestingAutomationProvider::GetTabURLJSON;
   2068   handler_map["GetTabTitle"] =
   2069       &TestingAutomationProvider::GetTabTitleJSON;
   2070   handler_map["CaptureEntirePage"] =
   2071       &TestingAutomationProvider::CaptureEntirePageJSON;
   2072   handler_map["GetCookies"] =
   2073       &TestingAutomationProvider::GetCookiesJSON;
   2074   handler_map["DeleteCookie"] =
   2075       &TestingAutomationProvider::DeleteCookieJSON;
   2076   handler_map["SetCookie"] =
   2077       &TestingAutomationProvider::SetCookieJSON;
   2078   handler_map["GetTabIds"] =
   2079       &TestingAutomationProvider::GetTabIds;
   2080   handler_map["IsTabIdValid"] =
   2081       &TestingAutomationProvider::IsTabIdValid;
   2082   handler_map["CloseTab"] =
   2083       &TestingAutomationProvider::CloseTabJSON;
   2084   handler_map["WebkitMouseMove"] =
   2085       &TestingAutomationProvider::WebkitMouseMove;
   2086   handler_map["WebkitMouseClick"] =
   2087       &TestingAutomationProvider::WebkitMouseClick;
   2088   handler_map["WebkitMouseDrag"] =
   2089       &TestingAutomationProvider::WebkitMouseDrag;
   2090   handler_map["SendWebkitKeyEvent"] =
   2091       &TestingAutomationProvider::SendWebkitKeyEvent;
   2092   handler_map["SendOSLevelKeyEventToTab"] =
   2093       &TestingAutomationProvider::SendOSLevelKeyEventToTab;
   2094   handler_map["ActivateTab"] =
   2095       &TestingAutomationProvider::ActivateTabJSON;
   2096   handler_map["UpdateExtensionsNow"] =
   2097       &TestingAutomationProvider::UpdateExtensionsNow;
   2098   handler_map["GetChromeDriverAutomationVersion"] =
   2099       &TestingAutomationProvider::GetChromeDriverAutomationVersion;
   2100 #if defined(OS_CHROMEOS)
   2101   handler_map["GetLoginInfo"] = &TestingAutomationProvider::GetLoginInfo;
   2102   handler_map["LoginAsGuest"] = &TestingAutomationProvider::LoginAsGuest;
   2103   handler_map["Login"] = &TestingAutomationProvider::Login;
   2104 
   2105   handler_map["LockScreen"] = &TestingAutomationProvider::LockScreen;
   2106   handler_map["UnlockScreen"] = &TestingAutomationProvider::UnlockScreen;
   2107   handler_map["SignoutInScreenLocker"] =
   2108       &TestingAutomationProvider::SignoutInScreenLocker;
   2109 
   2110   handler_map["GetBatteryInfo"] = &TestingAutomationProvider::GetBatteryInfo;
   2111 
   2112   handler_map["GetNetworkInfo"] = &TestingAutomationProvider::GetNetworkInfo;
   2113   handler_map["NetworkScan"] = &TestingAutomationProvider::NetworkScan;
   2114   handler_map["GetProxySettings"] =
   2115       &TestingAutomationProvider::GetProxySettings;
   2116   handler_map["SetProxySettings"] =
   2117       &TestingAutomationProvider::SetProxySettings;
   2118   handler_map["ConnectToWifiNetwork"] =
   2119       &TestingAutomationProvider::ConnectToWifiNetwork;
   2120   handler_map["ConnectToHiddenWifiNetwork"] =
   2121       &TestingAutomationProvider::ConnectToHiddenWifiNetwork;
   2122   handler_map["DisconnectFromWifiNetwork"] =
   2123       &TestingAutomationProvider::DisconnectFromWifiNetwork;
   2124 
   2125   handler_map["GetUpdateInfo"] = &TestingAutomationProvider::GetUpdateInfo;
   2126   handler_map["UpdateCheck"] = &TestingAutomationProvider::UpdateCheck;
   2127   handler_map["SetReleaseTrack"] = &TestingAutomationProvider::SetReleaseTrack;
   2128 #endif  // defined(OS_CHROMEOS)
   2129 
   2130   std::map<std::string, BrowserJsonHandler> browser_handler_map;
   2131   browser_handler_map["DisablePlugin"] =
   2132       &TestingAutomationProvider::DisablePlugin;
   2133   browser_handler_map["EnablePlugin"] =
   2134       &TestingAutomationProvider::EnablePlugin;
   2135   browser_handler_map["GetPluginsInfo"] =
   2136       &TestingAutomationProvider::GetPluginsInfo;
   2137 
   2138   browser_handler_map["GetBrowserInfo"] =
   2139       &TestingAutomationProvider::GetBrowserInfo;
   2140 
   2141   browser_handler_map["GetNavigationInfo"] =
   2142       &TestingAutomationProvider::GetNavigationInfo;
   2143 
   2144   browser_handler_map["PerformActionOnInfobar"] =
   2145       &TestingAutomationProvider::PerformActionOnInfobar;
   2146 
   2147   browser_handler_map["GetHistoryInfo"] =
   2148       &TestingAutomationProvider::GetHistoryInfo;
   2149   browser_handler_map["AddHistoryItem"] =
   2150       &TestingAutomationProvider::AddHistoryItem;
   2151 
   2152   browser_handler_map["GetOmniboxInfo"] =
   2153       &TestingAutomationProvider::GetOmniboxInfo;
   2154   browser_handler_map["SetOmniboxText"] =
   2155       &TestingAutomationProvider::SetOmniboxText;
   2156   browser_handler_map["OmniboxAcceptInput"] =
   2157       &TestingAutomationProvider::OmniboxAcceptInput;
   2158   browser_handler_map["OmniboxMovePopupSelection"] =
   2159       &TestingAutomationProvider::OmniboxMovePopupSelection;
   2160 
   2161   browser_handler_map["GetInstantInfo"] =
   2162       &TestingAutomationProvider::GetInstantInfo;
   2163 
   2164   browser_handler_map["LoadSearchEngineInfo"] =
   2165       &TestingAutomationProvider::LoadSearchEngineInfo;
   2166   browser_handler_map["GetSearchEngineInfo"] =
   2167       &TestingAutomationProvider::GetSearchEngineInfo;
   2168   browser_handler_map["AddOrEditSearchEngine"] =
   2169       &TestingAutomationProvider::AddOrEditSearchEngine;
   2170   browser_handler_map["PerformActionOnSearchEngine"] =
   2171       &TestingAutomationProvider::PerformActionOnSearchEngine;
   2172 
   2173   browser_handler_map["GetPrefsInfo"] =
   2174       &TestingAutomationProvider::GetPrefsInfo;
   2175   browser_handler_map["SetPrefs"] = &TestingAutomationProvider::SetPrefs;
   2176 
   2177   browser_handler_map["SetWindowDimensions"] =
   2178       &TestingAutomationProvider::SetWindowDimensions;
   2179 
   2180   browser_handler_map["GetDownloadsInfo"] =
   2181       &TestingAutomationProvider::GetDownloadsInfo;
   2182   browser_handler_map["WaitForAllDownloadsToComplete"] =
   2183       &TestingAutomationProvider::WaitForDownloadsToComplete;
   2184   browser_handler_map["PerformActionOnDownload"] =
   2185       &TestingAutomationProvider::PerformActionOnDownload;
   2186 
   2187   browser_handler_map["GetInitialLoadTimes"] =
   2188       &TestingAutomationProvider::GetInitialLoadTimes;
   2189 
   2190   browser_handler_map["SaveTabContents"] =
   2191       &TestingAutomationProvider::SaveTabContents;
   2192 
   2193   browser_handler_map["ImportSettings"] =
   2194       &TestingAutomationProvider::ImportSettings;
   2195 
   2196   browser_handler_map["AddSavedPassword"] =
   2197       &TestingAutomationProvider::AddSavedPassword;
   2198   browser_handler_map["RemoveSavedPassword"] =
   2199       &TestingAutomationProvider::RemoveSavedPassword;
   2200   browser_handler_map["GetSavedPasswords"] =
   2201       &TestingAutomationProvider::GetSavedPasswords;
   2202 
   2203   browser_handler_map["ClearBrowsingData"] =
   2204       &TestingAutomationProvider::ClearBrowsingData;
   2205 
   2206   browser_handler_map["GetBlockedPopupsInfo"] =
   2207       &TestingAutomationProvider::GetBlockedPopupsInfo;
   2208   browser_handler_map["UnblockAndLaunchBlockedPopup"] =
   2209       &TestingAutomationProvider::UnblockAndLaunchBlockedPopup;
   2210 
   2211   // SetTheme() implemented using InstallExtension().
   2212   browser_handler_map["GetThemeInfo"] =
   2213       &TestingAutomationProvider::GetThemeInfo;
   2214 
   2215   // InstallExtension() present in pyauto.py.
   2216   browser_handler_map["GetExtensionsInfo"] =
   2217       &TestingAutomationProvider::GetExtensionsInfo;
   2218   browser_handler_map["UninstallExtensionById"] =
   2219       &TestingAutomationProvider::UninstallExtensionById;
   2220 
   2221   browser_handler_map["FindInPage"] = &TestingAutomationProvider::FindInPage;
   2222 
   2223   browser_handler_map["SelectTranslateOption"] =
   2224       &TestingAutomationProvider::SelectTranslateOption;
   2225   browser_handler_map["GetTranslateInfo"] =
   2226       &TestingAutomationProvider::GetTranslateInfo;
   2227 
   2228   browser_handler_map["GetAutofillProfile"] =
   2229       &TestingAutomationProvider::GetAutofillProfile;
   2230   browser_handler_map["FillAutofillProfile"] =
   2231       &TestingAutomationProvider::FillAutofillProfile;
   2232 
   2233   browser_handler_map["GetActiveNotifications"] =
   2234       &TestingAutomationProvider::GetActiveNotifications;
   2235   browser_handler_map["CloseNotification"] =
   2236       &TestingAutomationProvider::CloseNotification;
   2237   browser_handler_map["WaitForNotificationCount"] =
   2238       &TestingAutomationProvider::WaitForNotificationCount;
   2239 
   2240   browser_handler_map["SignInToSync"] =
   2241       &TestingAutomationProvider::SignInToSync;
   2242   browser_handler_map["GetSyncInfo"] = &TestingAutomationProvider::GetSyncInfo;
   2243   browser_handler_map["AwaitSyncCycleCompletion"] =
   2244       &TestingAutomationProvider::AwaitSyncCycleCompletion;
   2245   browser_handler_map["EnableSyncForDatatypes"] =
   2246       &TestingAutomationProvider::EnableSyncForDatatypes;
   2247   browser_handler_map["DisableSyncForDatatypes"] =
   2248       &TestingAutomationProvider::DisableSyncForDatatypes;
   2249 
   2250   browser_handler_map["GetNTPInfo"] =
   2251       &TestingAutomationProvider::GetNTPInfo;
   2252   browser_handler_map["MoveNTPMostVisitedThumbnail"] =
   2253       &TestingAutomationProvider::MoveNTPMostVisitedThumbnail;
   2254   browser_handler_map["RemoveNTPMostVisitedThumbnail"] =
   2255       &TestingAutomationProvider::RemoveNTPMostVisitedThumbnail;
   2256   browser_handler_map["UnpinNTPMostVisitedThumbnail"] =
   2257       &TestingAutomationProvider::UnpinNTPMostVisitedThumbnail;
   2258   browser_handler_map["RestoreAllNTPMostVisitedThumbnails"] =
   2259       &TestingAutomationProvider::RestoreAllNTPMostVisitedThumbnails;
   2260 
   2261   browser_handler_map["KillRendererProcess"] =
   2262       &TestingAutomationProvider::KillRendererProcess;
   2263 
   2264   browser_handler_map["GetNTPThumbnailMode"] =
   2265       &TestingAutomationProvider::GetNTPThumbnailMode;
   2266   browser_handler_map["SetNTPThumbnailMode"] =
   2267       &TestingAutomationProvider::SetNTPThumbnailMode;
   2268   browser_handler_map["GetNTPMenuMode"] =
   2269       &TestingAutomationProvider::GetNTPMenuMode;
   2270   browser_handler_map["SetNTPMenuMode"] =
   2271       &TestingAutomationProvider::SetNTPMenuMode;
   2272 
   2273   browser_handler_map["LaunchApp"] = &TestingAutomationProvider::LaunchApp;
   2274   browser_handler_map["SetAppLaunchType"] =
   2275       &TestingAutomationProvider::SetAppLaunchType;
   2276 
   2277   if (handler_map.find(std::string(command)) != handler_map.end()) {
   2278     (this->*handler_map[command])(dict_value, reply_message);
   2279   } else if (browser_handler_map.find(std::string(command)) !=
   2280              browser_handler_map.end()) {
   2281     Browser* browser = NULL;
   2282     if (!browser_tracker_->ContainsHandle(handle) ||
   2283         !(browser = browser_tracker_->GetResource(handle))) {
   2284       AutomationJSONReply(this, reply_message).SendError("No browser object.");
   2285       return;
   2286     }
   2287     (this->*browser_handler_map[command])(browser, dict_value, reply_message);
   2288   } else {
   2289     std::string error_string = "Unknown command. Options: ";
   2290     for (std::map<std::string, JsonHandler>::const_iterator it =
   2291          handler_map.begin(); it != handler_map.end(); ++it) {
   2292       error_string += it->first + ", ";
   2293     }
   2294     for (std::map<std::string, BrowserJsonHandler>::const_iterator it =
   2295          browser_handler_map.begin(); it != browser_handler_map.end(); ++it) {
   2296       error_string += it->first + ", ";
   2297     }
   2298     AutomationJSONReply(this, reply_message).SendError(error_string);
   2299   }
   2300 }
   2301 
   2302 // Sample json input: { "command": "SetWindowDimensions",
   2303 //                      "x": 20,         # optional
   2304 //                      "y": 20,         # optional
   2305 //                      "width": 800,    # optional
   2306 //                      "height": 600 }  # optional
   2307 void TestingAutomationProvider::SetWindowDimensions(
   2308     Browser* browser,
   2309     DictionaryValue* args,
   2310     IPC::Message* reply_message) {
   2311   gfx::Rect rect = browser->window()->GetRestoredBounds();
   2312   int x, y, width, height;
   2313   if (args->GetInteger("x", &x))
   2314     rect.set_x(x);
   2315   if (args->GetInteger("y", &y))
   2316     rect.set_y(y);
   2317   if (args->GetInteger("width", &width))
   2318     rect.set_width(width);
   2319   if (args->GetInteger("height", &height))
   2320     rect.set_height(height);
   2321   browser->window()->SetBounds(rect);
   2322   AutomationJSONReply(this, reply_message).SendSuccess(NULL);
   2323 }
   2324 
   2325 ListValue* TestingAutomationProvider::GetInfobarsInfo(TabContents* tc) {
   2326   // Each infobar may have different properties depending on the type.
   2327   ListValue* infobars = new ListValue;
   2328   for (size_t i = 0; i < tc->infobar_count(); ++i) {
   2329     DictionaryValue* infobar_item = new DictionaryValue;
   2330     InfoBarDelegate* infobar = tc->GetInfoBarDelegateAt(i);
   2331     if (infobar->AsConfirmInfoBarDelegate()) {
   2332       // Also covers ThemeInstalledInfoBarDelegate.
   2333       infobar_item->SetString("type", "confirm_infobar");
   2334       ConfirmInfoBarDelegate* confirm_infobar =
   2335         infobar->AsConfirmInfoBarDelegate();
   2336       infobar_item->SetString("text", confirm_infobar->GetMessageText());
   2337       infobar_item->SetString("link_text", confirm_infobar->GetLinkText());
   2338       ListValue* buttons_list = new ListValue;
   2339       int buttons = confirm_infobar->GetButtons();
   2340       if (buttons & ConfirmInfoBarDelegate::BUTTON_OK) {
   2341         StringValue* button_label = new StringValue(
   2342             confirm_infobar->GetButtonLabel(
   2343               ConfirmInfoBarDelegate::BUTTON_OK));
   2344         buttons_list->Append(button_label);
   2345       }
   2346       if (buttons & ConfirmInfoBarDelegate::BUTTON_CANCEL) {
   2347         StringValue* button_label = new StringValue(
   2348             confirm_infobar->GetButtonLabel(
   2349               ConfirmInfoBarDelegate::BUTTON_CANCEL));
   2350         buttons_list->Append(button_label);
   2351       }
   2352       infobar_item->Set("buttons", buttons_list);
   2353     } else if (infobar->AsLinkInfoBarDelegate()) {
   2354       infobar_item->SetString("type", "link_infobar");
   2355       LinkInfoBarDelegate* link_infobar = infobar->AsLinkInfoBarDelegate();
   2356       infobar_item->SetString("link_text", link_infobar->GetLinkText());
   2357     } else if (infobar->AsTranslateInfoBarDelegate()) {
   2358       infobar_item->SetString("type", "translate_infobar");
   2359       TranslateInfoBarDelegate* translate_infobar =
   2360           infobar->AsTranslateInfoBarDelegate();
   2361       infobar_item->SetString("original_lang_code",
   2362                               translate_infobar->GetOriginalLanguageCode());
   2363       infobar_item->SetString("target_lang_code",
   2364                               translate_infobar->GetTargetLanguageCode());
   2365     } else if (infobar->AsExtensionInfoBarDelegate()) {
   2366       infobar_item->SetString("type", "extension_infobar");
   2367     } else {
   2368       infobar_item->SetString("type", "unknown_infobar");
   2369     }
   2370     infobars->Append(infobar_item);
   2371   }
   2372   return infobars;
   2373 }
   2374 
   2375 // Sample json input: { "command": "PerformActionOnInfobar",
   2376 //                      "action": "dismiss",
   2377 //                      "infobar_index": 0,
   2378 //                      "tab_index": 0 }
   2379 // Sample output: {}
   2380 void TestingAutomationProvider::PerformActionOnInfobar(
   2381     Browser* browser,
   2382     DictionaryValue* args,
   2383     IPC::Message* reply_message) {
   2384   AutomationJSONReply reply(this, reply_message);
   2385   int tab_index;
   2386   int infobar_index_int;
   2387   std::string action;
   2388   if (!args->GetInteger("tab_index", &tab_index) ||
   2389       !args->GetInteger("infobar_index", &infobar_index_int) ||
   2390       !args->GetString("action", &action)) {
   2391     reply.SendError("Invalid or missing args");
   2392     return;
   2393   }
   2394   TabContents* tab_contents = browser->GetTabContentsAt(tab_index);
   2395   if (!tab_contents) {
   2396     reply.SendError(StringPrintf("No such tab at index %d", tab_index));
   2397     return;
   2398   }
   2399   InfoBarDelegate* infobar = NULL;
   2400   size_t infobar_index = static_cast<size_t>(infobar_index_int);
   2401   if (infobar_index >= tab_contents->infobar_count() ||
   2402       !(infobar = tab_contents->GetInfoBarDelegateAt(infobar_index))) {
   2403     reply.SendError(StringPrintf("No such infobar at index %" PRIuS,
   2404                                  infobar_index));
   2405     return;
   2406   }
   2407   if ("dismiss" == action) {
   2408     infobar->InfoBarDismissed();
   2409     tab_contents->RemoveInfoBar(infobar);
   2410     reply.SendSuccess(NULL);
   2411     return;
   2412   }
   2413   if ("accept" == action || "cancel" == action) {
   2414     ConfirmInfoBarDelegate* confirm_infobar;
   2415     if (!(confirm_infobar = infobar->AsConfirmInfoBarDelegate())) {
   2416       reply.SendError("Not a confirm infobar");
   2417       return;
   2418     }
   2419     if ("accept" == action) {
   2420       if (confirm_infobar->Accept())
   2421         tab_contents->RemoveInfoBar(infobar);
   2422     } else if ("cancel" == action) {
   2423       if (confirm_infobar->Cancel())
   2424         tab_contents->RemoveInfoBar(infobar);
   2425     }
   2426     reply.SendSuccess(NULL);
   2427     return;
   2428   }
   2429   reply.SendError("Invalid action");
   2430 }
   2431 
   2432 namespace {
   2433 
   2434 // Task to get info about BrowserChildProcessHost. Must run on IO thread to
   2435 // honor the semantics of BrowserChildProcessHost.
   2436 // Used by AutomationProvider::GetBrowserInfo().
   2437 class GetChildProcessHostInfoTask : public Task {
   2438  public:
   2439   GetChildProcessHostInfoTask(base::WaitableEvent* event,
   2440                               ListValue* child_processes)
   2441     : event_(event),
   2442       child_processes_(child_processes) {}
   2443 
   2444   virtual void Run() {
   2445     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
   2446     for (BrowserChildProcessHost::Iterator iter; !iter.Done(); ++iter) {
   2447       // Only add processes which are already started,
   2448       // since we need their handle.
   2449       if ((*iter)->handle() == base::kNullProcessHandle) {
   2450         continue;
   2451       }
   2452       ChildProcessInfo* info = *iter;
   2453       DictionaryValue* item = new DictionaryValue;
   2454       item->SetString("name", WideToUTF16Hack(info->name()));
   2455       item->SetString("type",
   2456                       ChildProcessInfo::GetTypeNameInEnglish(info->type()));
   2457       item->SetInteger("pid", base::GetProcId(info->handle()));
   2458       child_processes_->Append(item);
   2459     }
   2460     event_->Signal();
   2461   }
   2462 
   2463  private:
   2464   base::WaitableEvent* const event_;  // weak
   2465   ListValue* child_processes_;
   2466 
   2467   DISALLOW_COPY_AND_ASSIGN(GetChildProcessHostInfoTask);
   2468 };
   2469 
   2470 }  // namespace
   2471 
   2472 // Sample json input: { "command": "GetBrowserInfo" }
   2473 // Refer to GetBrowserInfo() in chrome/test/pyautolib/pyauto.py for
   2474 // sample json output.
   2475 void TestingAutomationProvider::GetBrowserInfo(
   2476     Browser* browser,
   2477     DictionaryValue* args,
   2478     IPC::Message* reply_message) {
   2479   base::ThreadRestrictions::ScopedAllowIO allow_io;  // needed for PathService
   2480   DictionaryValue* properties = new DictionaryValue;
   2481   properties->SetString("ChromeVersion", chrome::kChromeVersion);
   2482   properties->SetString("BrowserProcessExecutableName",
   2483                         chrome::kBrowserProcessExecutableName);
   2484   properties->SetString("HelperProcessExecutableName",
   2485                         chrome::kHelperProcessExecutableName);
   2486   properties->SetString("BrowserProcessExecutablePath",
   2487                         chrome::kBrowserProcessExecutablePath);
   2488   properties->SetString("HelperProcessExecutablePath",
   2489                         chrome::kHelperProcessExecutablePath);
   2490   properties->SetString("command_line_string",
   2491       CommandLine::ForCurrentProcess()->command_line_string());
   2492   FilePath dumps_path;
   2493   PathService::Get(chrome::DIR_CRASH_DUMPS, &dumps_path);
   2494   properties->SetString("DIR_CRASH_DUMPS", dumps_path.value());
   2495 
   2496   std::string branding;
   2497 #if defined(GOOGLE_CHROME_BUILD)
   2498   branding = "Google Chrome";
   2499 #elif defined(CHROMIUM_BUILD)
   2500   branding = "Chromium";
   2501 #else
   2502   branding = "Unknown Branding";
   2503 #endif
   2504   properties->SetString("branding", branding);
   2505 
   2506   scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
   2507   return_value->Set("properties", properties);
   2508 
   2509   return_value->SetInteger("browser_pid", base::GetCurrentProcId());
   2510   // Add info about all windows in a list of dictionaries, one dictionary
   2511   // item per window.
   2512   ListValue* windows = new ListValue;
   2513   int windex = 0;
   2514   for (BrowserList::const_iterator it = BrowserList::begin();
   2515        it != BrowserList::end();
   2516        ++it, ++windex) {
   2517     DictionaryValue* browser_item = new DictionaryValue;
   2518     browser = *it;
   2519     browser_item->SetInteger("index", windex);
   2520     // Window properties
   2521     gfx::Rect rect = browser->window()->GetRestoredBounds();
   2522     browser_item->SetInteger("x", rect.x());
   2523     browser_item->SetInteger("y", rect.y());
   2524     browser_item->SetInteger("width", rect.width());
   2525     browser_item->SetInteger("height", rect.height());
   2526     browser_item->SetBoolean("fullscreen",
   2527                              browser->window()->IsFullscreen());
   2528     browser_item->SetInteger("selected_tab", browser->active_index());
   2529     browser_item->SetBoolean("incognito",
   2530                              browser->profile()->IsOffTheRecord());
   2531     // For each window, add info about all tabs in a list of dictionaries,
   2532     // one dictionary item per tab.
   2533     ListValue* tabs = new ListValue;
   2534     for (int i = 0; i < browser->tab_count(); ++i) {
   2535       TabContents* tc = browser->GetTabContentsAt(i);
   2536       DictionaryValue* tab = new DictionaryValue;
   2537       tab->SetInteger("index", i);
   2538       tab->SetString("url", tc->GetURL().spec());
   2539       tab->SetInteger("renderer_pid",
   2540                       base::GetProcId(tc->GetRenderProcessHost()->GetHandle()));
   2541       tab->Set("infobars", GetInfobarsInfo(tc));
   2542       tab->SetBoolean("pinned", browser->IsTabPinned(i));
   2543       tabs->Append(tab);
   2544     }
   2545     browser_item->Set("tabs", tabs);
   2546 
   2547     windows->Append(browser_item);
   2548   }
   2549   return_value->Set("windows", windows);
   2550 
   2551   return_value->SetString("child_process_path",
   2552                           ChildProcessHost::GetChildPath(true).value());
   2553   // Child processes are the processes for plugins and other workers.
   2554   // Add all child processes in a list of dictionaries, one dictionary item
   2555   // per child process.
   2556   ListValue* child_processes = new ListValue;
   2557   base::WaitableEvent event(true   /* manual reset */,
   2558                             false  /* not initially signaled */);
   2559   CHECK(BrowserThread::PostTask(
   2560       BrowserThread::IO, FROM_HERE,
   2561       new GetChildProcessHostInfoTask(&event, child_processes)));
   2562   event.Wait();
   2563   return_value->Set("child_processes", child_processes);
   2564 
   2565   // Add all extension processes in a list of dictionaries, one dictionary
   2566   // item per extension process.
   2567   ListValue* extension_processes = new ListValue;
   2568   ProfileManager* profile_manager = g_browser_process->profile_manager();
   2569   std::vector<Profile*> profiles(profile_manager->GetLoadedProfiles());
   2570   for (size_t i = 0; i < profiles.size(); ++i) {
   2571     ExtensionProcessManager* process_manager =
   2572         profiles[i]->GetExtensionProcessManager();
   2573     if (!process_manager)
   2574       continue;
   2575     ExtensionProcessManager::const_iterator jt;
   2576     for (jt = process_manager->begin(); jt != process_manager->end(); ++jt) {
   2577       ExtensionHost* ex_host = *jt;
   2578       // Don't add dead extension processes.
   2579       if (!ex_host->IsRenderViewLive())
   2580         continue;
   2581       DictionaryValue* item = new DictionaryValue;
   2582       item->SetString("name", ex_host->extension()->name());
   2583       item->SetInteger(
   2584           "pid",
   2585           base::GetProcId(ex_host->render_process_host()->GetHandle()));
   2586       extension_processes->Append(item);
   2587     }
   2588   }
   2589   return_value->Set("extension_processes", extension_processes);
   2590   AutomationJSONReply(this, reply_message).SendSuccess(return_value.get());
   2591 }
   2592 
   2593 // Sample json input: { "command": "GetNavigationInfo" }
   2594 // Refer to GetNavigationInfo() in chrome/test/pyautolib/pyauto.py for
   2595 // sample json output.
   2596 void TestingAutomationProvider::GetNavigationInfo(
   2597     Browser* browser,
   2598     DictionaryValue* args,
   2599     IPC::Message* reply_message) {
   2600   AutomationJSONReply reply(this, reply_message);
   2601   int tab_index;
   2602   TabContents* tab_contents = NULL;
   2603   if (!args->GetInteger("tab_index", &tab_index) ||
   2604       !(tab_contents = browser->GetTabContentsAt(tab_index))) {
   2605     reply.SendError("tab_index missing or invalid.");
   2606     return;
   2607   }
   2608   scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
   2609   const NavigationController& controller = tab_contents->controller();
   2610   NavigationEntry* nav_entry = controller.GetActiveEntry();
   2611   DCHECK(nav_entry);
   2612 
   2613   // Security info.
   2614   DictionaryValue* ssl = new DictionaryValue;
   2615   std::map<SecurityStyle, std::string> style_to_string;
   2616   style_to_string[SECURITY_STYLE_UNKNOWN] = "SECURITY_STYLE_UNKNOWN";
   2617   style_to_string[SECURITY_STYLE_UNAUTHENTICATED] =
   2618       "SECURITY_STYLE_UNAUTHENTICATED";
   2619   style_to_string[SECURITY_STYLE_AUTHENTICATION_BROKEN] =
   2620       "SECURITY_STYLE_AUTHENTICATION_BROKEN";
   2621   style_to_string[SECURITY_STYLE_AUTHENTICATED] =
   2622       "SECURITY_STYLE_AUTHENTICATED";
   2623 
   2624   NavigationEntry::SSLStatus ssl_status = nav_entry->ssl();
   2625   ssl->SetString("security_style",
   2626                  style_to_string[ssl_status.security_style()]);
   2627   ssl->SetBoolean("ran_insecure_content", ssl_status.ran_insecure_content());
   2628   ssl->SetBoolean("displayed_insecure_content",
   2629                   ssl_status.displayed_insecure_content());
   2630   return_value->Set("ssl", ssl);
   2631 
   2632   // Page type.
   2633   std::map<PageType, std::string> pagetype_to_string;
   2634   pagetype_to_string[NORMAL_PAGE] = "NORMAL_PAGE";
   2635   pagetype_to_string[ERROR_PAGE] = "ERROR_PAGE";
   2636   pagetype_to_string[INTERSTITIAL_PAGE] = "INTERSTITIAL_PAGE";
   2637   return_value->SetString("page_type",
   2638                           pagetype_to_string[nav_entry->page_type()]);
   2639 
   2640   return_value->SetString("favicon_url", nav_entry->favicon().url().spec());
   2641   reply.SendSuccess(return_value.get());
   2642 }
   2643 
   2644 // Sample json input: { "command": "GetHistoryInfo",
   2645 //                      "search_text": "some text" }
   2646 // Refer chrome/test/pyautolib/history_info.py for sample json output.
   2647 void TestingAutomationProvider::GetHistoryInfo(Browser* browser,
   2648                                                DictionaryValue* args,
   2649                                                IPC::Message* reply_message) {
   2650   consumer_.CancelAllRequests();
   2651 
   2652   string16 search_text;
   2653   args->GetString("search_text", &search_text);
   2654 
   2655   // Fetch history.
   2656   HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
   2657   history::QueryOptions options;
   2658   // The observer owns itself.  It deletes itself after it fetches history.
   2659   AutomationProviderHistoryObserver* history_observer =
   2660       new AutomationProviderHistoryObserver(this, reply_message);
   2661   hs->QueryHistory(
   2662       search_text,
   2663       options,
   2664       &consumer_,
   2665       NewCallback(history_observer,
   2666                   &AutomationProviderHistoryObserver::HistoryQueryComplete));
   2667 }
   2668 
   2669 // Sample json input: { "command": "AddHistoryItem",
   2670 //                      "item": { "URL": "http://www.google.com",
   2671 //                                "title": "Google",   # optional
   2672 //                                "time": 12345        # optional (time_t)
   2673 //                               } }
   2674 // Refer chrome/test/pyautolib/pyauto.py for details on input.
   2675 void TestingAutomationProvider::AddHistoryItem(Browser* browser,
   2676                                                DictionaryValue* args,
   2677                                                IPC::Message* reply_message) {
   2678   DictionaryValue* item = NULL;
   2679   args->GetDictionary("item", &item);
   2680   string16 url_text;
   2681   string16 title;
   2682   base::Time time = base::Time::Now();
   2683   AutomationJSONReply reply(this, reply_message);
   2684 
   2685   if (!item->GetString("url", &url_text)) {
   2686     reply.SendError("bad args (no URL in dict?)");
   2687     return;
   2688   }
   2689   GURL gurl(url_text);
   2690   item->GetString("title", &title);  // Don't care if it fails.
   2691   int it;
   2692   double dt;
   2693   if (item->GetInteger("time", &it))
   2694     time = base::Time::FromTimeT(it);
   2695   else if (item->GetDouble("time", &dt))
   2696     time = base::Time::FromDoubleT(dt);
   2697 
   2698   // Ideas for "dummy" values (e.g. id_scope) came from
   2699   // chrome/browser/autocomplete/history_contents_provider_unittest.cc
   2700   HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
   2701   const void* id_scope = reinterpret_cast<void*>(1);
   2702   hs->AddPage(gurl, time,
   2703               id_scope,
   2704               0,
   2705               GURL(),
   2706               PageTransition::LINK,
   2707               history::RedirectList(),
   2708               history::SOURCE_BROWSED,
   2709               false);
   2710   if (title.length())
   2711     hs->SetPageTitle(gurl, title);
   2712   reply.SendSuccess(NULL);
   2713 }
   2714 
   2715 // Sample json input: { "command": "GetDownloadsInfo" }
   2716 // Refer chrome/test/pyautolib/download_info.py for sample json output.
   2717 void TestingAutomationProvider::GetDownloadsInfo(Browser* browser,
   2718                                                  DictionaryValue* args,
   2719                                                  IPC::Message* reply_message) {
   2720   AutomationJSONReply reply(this, reply_message);
   2721   scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
   2722   ListValue* list_of_downloads = new ListValue;
   2723 
   2724   if (browser->profile()->HasCreatedDownloadManager()) {
   2725     std::vector<DownloadItem*> downloads;
   2726     browser->profile()->GetDownloadManager()->
   2727         GetAllDownloads(FilePath(), &downloads);
   2728 
   2729     for (std::vector<DownloadItem*>::iterator it = downloads.begin();
   2730          it != downloads.end();
   2731          it++) {  // Fill info about each download item.
   2732       list_of_downloads->Append(GetDictionaryFromDownloadItem(*it));
   2733     }
   2734   }
   2735   return_value->Set("downloads", list_of_downloads);
   2736   reply.SendSuccess(return_value.get());
   2737 }
   2738 
   2739 void TestingAutomationProvider::WaitForDownloadsToComplete(
   2740     Browser* browser,
   2741     DictionaryValue* args,
   2742     IPC::Message* reply_message) {
   2743 
   2744   // Look for a quick return.
   2745   if (!browser->profile()->HasCreatedDownloadManager()) {
   2746     // No download manager.
   2747     AutomationJSONReply(this, reply_message).SendSuccess(NULL);
   2748     return;
   2749   }
   2750   std::vector<DownloadItem*> downloads;
   2751   browser->profile()->GetDownloadManager()->
   2752       GetCurrentDownloads(FilePath(), &downloads);
   2753   if (downloads.empty()) {
   2754     AutomationJSONReply(this, reply_message).SendSuccess(NULL);
   2755     return;
   2756   }
   2757   // The observer owns itself.  When the last observed item pings, it
   2758   // deletes itself.
   2759   AutomationProviderDownloadItemObserver* item_observer =
   2760       new AutomationProviderDownloadItemObserver(
   2761           this, reply_message, downloads.size());
   2762   for (std::vector<DownloadItem*>::iterator i = downloads.begin();
   2763        i != downloads.end();
   2764        i++) {
   2765     (*i)->AddObserver(item_observer);
   2766   }
   2767 }
   2768 
   2769 namespace {
   2770 
   2771 DownloadItem* GetDownloadItemFromId(int id, DownloadManager* download_manager) {
   2772   std::vector<DownloadItem*> downloads;
   2773   download_manager->GetAllDownloads(FilePath(), &downloads);
   2774   DownloadItem* selected_item = NULL;
   2775 
   2776   for (std::vector<DownloadItem*>::iterator it = downloads.begin();
   2777        it != downloads.end();
   2778        it++) {
   2779     DownloadItem* curr_item = *it;
   2780     if (curr_item->id() == id) {
   2781       selected_item = curr_item;
   2782       break;
   2783     }
   2784   }
   2785   return selected_item;
   2786 }
   2787 
   2788 }  // namespace
   2789 
   2790 // See PerformActionOnDownload() in chrome/test/pyautolib/pyauto.py for sample
   2791 // json input and output.
   2792 void TestingAutomationProvider::PerformActionOnDownload(
   2793     Browser* browser,
   2794     DictionaryValue* args,
   2795     IPC::Message* reply_message) {
   2796   int id;
   2797   std::string action;
   2798 
   2799   if (!browser->profile()->HasCreatedDownloadManager()) {
   2800     AutomationJSONReply(this, reply_message).SendError("No download manager.");
   2801     return;
   2802   }
   2803   if (!args->GetInteger("id", &id) || !args->GetString("action", &action)) {
   2804     AutomationJSONReply(this, reply_message)
   2805         .SendError("Must include int id and string action.");
   2806     return;
   2807   }
   2808 
   2809   DownloadManager* download_manager = browser->profile()->GetDownloadManager();
   2810   DownloadItem* selected_item = GetDownloadItemFromId(id, download_manager);
   2811   if (!selected_item) {
   2812     AutomationJSONReply(this, reply_message)
   2813         .SendError(StringPrintf("No download with an id of %d\n", id));
   2814     return;
   2815   }
   2816 
   2817   if (action == "open") {
   2818     selected_item->AddObserver(
   2819         new AutomationProviderDownloadUpdatedObserver(
   2820             this, reply_message, true));
   2821     selected_item->OpenDownload();
   2822   } else if (action == "toggle_open_files_like_this") {
   2823     selected_item->OpenFilesBasedOnExtension(
   2824         !selected_item->ShouldOpenFileBasedOnExtension());
   2825     AutomationJSONReply(this, reply_message).SendSuccess(NULL);
   2826   } else if (action == "remove") {
   2827     download_manager->AddObserver(
   2828         new AutomationProviderDownloadModelChangedObserver(
   2829             this, reply_message, download_manager));
   2830     selected_item->Remove();
   2831   } else if (action == "decline_dangerous_download") {
   2832     download_manager->AddObserver(
   2833         new AutomationProviderDownloadModelChangedObserver(
   2834             this, reply_message, download_manager));
   2835     selected_item->Delete(DownloadItem::DELETE_DUE_TO_USER_DISCARD);
   2836   } else if (action == "save_dangerous_download") {
   2837     selected_item->AddObserver(new AutomationProviderDownloadUpdatedObserver(
   2838         this, reply_message, false));
   2839     selected_item->DangerousDownloadValidated();
   2840   } else if (action == "toggle_pause") {
   2841     selected_item->AddObserver(new AutomationProviderDownloadUpdatedObserver(
   2842         this, reply_message, false));
   2843     // This will still return if download has already completed.
   2844     selected_item->TogglePause();
   2845   } else if (action == "cancel") {
   2846     selected_item->AddObserver(new AutomationProviderDownloadUpdatedObserver(
   2847         this, reply_message, false));
   2848     selected_item->Cancel(true);
   2849   } else {
   2850     AutomationJSONReply(this, reply_message)
   2851         .SendError(StringPrintf("Invalid action '%s' given.", action.c_str()));
   2852   }
   2853 }
   2854 
   2855 // Sample JSON input { "command": "LoadSearchEngineInfo" }
   2856 void TestingAutomationProvider::LoadSearchEngineInfo(
   2857     Browser* browser,
   2858     DictionaryValue* args,
   2859     IPC::Message* reply_message) {
   2860   TemplateURLModel* url_model(profile_->GetTemplateURLModel());
   2861   if (url_model->loaded()) {
   2862     AutomationJSONReply(this, reply_message).SendSuccess(NULL);
   2863     return;
   2864   }
   2865   url_model->AddObserver(new AutomationProviderSearchEngineObserver(
   2866       this, reply_message));
   2867   url_model->Load();
   2868 }
   2869 
   2870 // Sample JSON input { "command": "GetSearchEngineInfo" }
   2871 // Refer to pyauto.py for sample output.
   2872 void TestingAutomationProvider::GetSearchEngineInfo(
   2873     Browser* browser,
   2874     DictionaryValue* args,
   2875     IPC::Message* reply_message) {
   2876   TemplateURLModel* url_model(profile_->GetTemplateURLModel());
   2877   scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
   2878   ListValue* search_engines = new ListValue;
   2879   std::vector<const TemplateURL*> template_urls = url_model->GetTemplateURLs();
   2880   for (std::vector<const TemplateURL*>::const_iterator it =
   2881        template_urls.begin(); it != template_urls.end(); ++it) {
   2882     DictionaryValue* search_engine = new DictionaryValue;
   2883     search_engine->SetString("short_name", UTF16ToUTF8((*it)->short_name()));
   2884     search_engine->SetString("description", UTF16ToUTF8((*it)->description()));
   2885     search_engine->SetString("keyword", UTF16ToUTF8((*it)->keyword()));
   2886     search_engine->SetBoolean("in_default_list", (*it)->ShowInDefaultList());
   2887     search_engine->SetBoolean("is_default",
   2888         (*it) == url_model->GetDefaultSearchProvider());
   2889     search_engine->SetBoolean("is_valid", (*it)->url()->IsValid());
   2890     search_engine->SetBoolean("supports_replacement",
   2891                               (*it)->url()->SupportsReplacement());
   2892     search_engine->SetString("url", (*it)->url()->url());
   2893     search_engine->SetString("host", (*it)->url()->GetHost());
   2894     search_engine->SetString("path", (*it)->url()->GetPath());
   2895     search_engine->SetString("display_url",
   2896                              UTF16ToUTF8((*it)->url()->DisplayURL()));
   2897     search_engines->Append(search_engine);
   2898   }
   2899   return_value->Set("search_engines", search_engines);
   2900   AutomationJSONReply(this, reply_message).SendSuccess(return_value.get());
   2901 }
   2902 
   2903 // Refer to pyauto.py for sample JSON input.
   2904 void TestingAutomationProvider::AddOrEditSearchEngine(
   2905     Browser* browser,
   2906     DictionaryValue* args,
   2907     IPC::Message* reply_message) {
   2908   TemplateURLModel* url_model(profile_->GetTemplateURLModel());
   2909   const TemplateURL* template_url;
   2910   string16 new_title;
   2911   string16 new_keyword;
   2912   std::string new_url;
   2913   std::string keyword;
   2914   if (!args->GetString("new_title", &new_title) ||
   2915       !args->GetString("new_keyword", &new_keyword) ||
   2916       !args->GetString("new_url", &new_url)) {
   2917     AutomationJSONReply(this, reply_message)
   2918         .SendError("One or more inputs invalid");
   2919     return;
   2920   }
   2921   std::string new_ref_url = TemplateURLRef::DisplayURLToURLRef(
   2922       UTF8ToUTF16(new_url));
   2923   scoped_ptr<KeywordEditorController> controller(
   2924       new KeywordEditorController(profile_));
   2925   if (args->GetString("keyword", &keyword)) {
   2926     template_url = url_model->GetTemplateURLForKeyword(UTF8ToUTF16(keyword));
   2927     if (template_url == NULL) {
   2928       AutomationJSONReply(this, reply_message)
   2929           .SendError(StringPrintf("No match for keyword: %s", keyword.c_str()));
   2930       return;
   2931     }
   2932     url_model->AddObserver(new AutomationProviderSearchEngineObserver(
   2933         this, reply_message));
   2934     controller->ModifyTemplateURL(template_url, new_title, new_keyword,
   2935                                   new_ref_url);
   2936   } else {
   2937     url_model->AddObserver(new AutomationProviderSearchEngineObserver(
   2938         this, reply_message));
   2939     controller->AddTemplateURL(new_title, new_keyword, new_ref_url);
   2940   }
   2941 }
   2942 
   2943 // Sample json input: { "command": "PerformActionOnSearchEngine",
   2944 //                      "keyword": keyword, "action": action }
   2945 void TestingAutomationProvider::PerformActionOnSearchEngine(
   2946     Browser* browser,
   2947     DictionaryValue* args,
   2948     IPC::Message* reply_message) {
   2949   TemplateURLModel* url_model(profile_->GetTemplateURLModel());
   2950   std::string keyword;
   2951   std::string action;
   2952   if (!args->GetString("keyword", &keyword) ||
   2953       !args->GetString("action", &action)) {
   2954     AutomationJSONReply(this, reply_message).SendError(
   2955         "One or more inputs invalid");
   2956     return;
   2957   }
   2958   const TemplateURL* template_url(
   2959       url_model->GetTemplateURLForKeyword(UTF8ToUTF16(keyword)));
   2960   if (template_url == NULL) {
   2961     AutomationJSONReply(this, reply_message)
   2962         .SendError(StringPrintf("No match for keyword: %s", keyword.c_str()));
   2963     return;
   2964   }
   2965   if (action == "delete") {
   2966     url_model->AddObserver(new AutomationProviderSearchEngineObserver(
   2967       this, reply_message));
   2968     url_model->Remove(template_url);
   2969   } else if (action == "default") {
   2970     url_model->AddObserver(new AutomationProviderSearchEngineObserver(
   2971       this, reply_message));
   2972     url_model->SetDefaultSearchProvider(template_url);
   2973   } else {
   2974     AutomationJSONReply(this, reply_message)
   2975         .SendError(StringPrintf("Invalid action: %s", action.c_str()));
   2976   }
   2977 }
   2978 
   2979 // Sample json input: { "command": "GetPrefsInfo" }
   2980 // Refer chrome/test/pyautolib/prefs_info.py for sample json output.
   2981 void TestingAutomationProvider::GetPrefsInfo(Browser* browser,
   2982                                              DictionaryValue* args,
   2983                                              IPC::Message* reply_message) {
   2984   DictionaryValue* items = profile_->GetPrefs()->GetPreferenceValues();
   2985 
   2986   scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
   2987   return_value->Set("prefs", items);  // return_value owns items.
   2988   AutomationJSONReply(this, reply_message).SendSuccess(return_value.get());
   2989 }
   2990 
   2991 // Sample json input: { "command": "SetPrefs", "path": path, "value": value }
   2992 void TestingAutomationProvider::SetPrefs(Browser* browser,
   2993                                          DictionaryValue* args,
   2994                                          IPC::Message* reply_message) {
   2995   std::string path;
   2996   Value* val;
   2997   AutomationJSONReply reply(this, reply_message);
   2998   if (args->GetString("path", &path) && args->Get("value", &val)) {
   2999     PrefService* pref_service = profile_->GetPrefs();
   3000     const PrefService::Preference* pref =
   3001         pref_service->FindPreference(path.c_str());
   3002     if (!pref) {  // Not a registered pref.
   3003       reply.SendError("pref not registered.");
   3004       return;
   3005     } else if (pref->IsManaged()) {  // Do not attempt to change a managed pref.
   3006       reply.SendError("pref is managed. cannot be changed.");
   3007       return;
   3008     } else {  // Set the pref.
   3009       pref_service->Set(path.c_str(), *val);
   3010     }
   3011   } else {
   3012     reply.SendError("no pref path or value given.");
   3013     return;
   3014   }
   3015 
   3016   reply.SendSuccess(NULL);
   3017 }
   3018 
   3019 // Sample json input: { "command": "GetOmniboxInfo" }
   3020 // Refer chrome/test/pyautolib/omnibox_info.py for sample json output.
   3021 void TestingAutomationProvider::GetOmniboxInfo(Browser* browser,
   3022                                                DictionaryValue* args,
   3023                                                IPC::Message* reply_message) {
   3024   scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
   3025 
   3026   LocationBar* loc_bar = browser->window()->GetLocationBar();
   3027   AutocompleteEditView* edit_view = loc_bar->location_entry();
   3028   AutocompleteEditModel* model = edit_view->model();
   3029 
   3030   // Fill up matches.
   3031   ListValue* matches = new ListValue;
   3032   const AutocompleteResult& result = model->result();
   3033   for (AutocompleteResult::const_iterator i = result.begin();
   3034        i != result.end(); ++i) {
   3035     const AutocompleteMatch& match = *i;
   3036     DictionaryValue* item = new DictionaryValue;  // owned by return_value
   3037     item->SetString("type", AutocompleteMatch::TypeToString(match.type));
   3038     item->SetBoolean("starred", match.starred);
   3039     item->SetString("destination_url", match.destination_url.spec());
   3040     item->SetString("contents", match.contents);
   3041     item->SetString("description", match.description);
   3042     matches->Append(item);
   3043   }
   3044   return_value->Set("matches", matches);
   3045 
   3046   // Fill up other properties.
   3047   DictionaryValue* properties = new DictionaryValue;  // owned by return_value
   3048   properties->SetBoolean("has_focus", model->has_focus());
   3049   properties->SetBoolean("query_in_progress",
   3050                          !model->autocomplete_controller()->done());
   3051   properties->SetString("keyword", model->keyword());
   3052   properties->SetString("text", edit_view->GetText());
   3053   return_value->Set("properties", properties);
   3054 
   3055   AutomationJSONReply(this, reply_message).SendSuccess(return_value.get());
   3056 }
   3057 
   3058 // Sample json input: { "command": "SetOmniboxText",
   3059 //                      "text": "goog" }
   3060 void TestingAutomationProvider::SetOmniboxText(Browser* browser,
   3061                                                DictionaryValue* args,
   3062                                                IPC::Message* reply_message) {
   3063   string16 text;
   3064   AutomationJSONReply reply(this, reply_message);
   3065   if (!args->GetString("text", &text)) {
   3066     reply.SendError("text missing");
   3067     return;
   3068   }
   3069   browser->FocusLocationBar();
   3070   LocationBar* loc_bar = browser->window()->GetLocationBar();
   3071   AutocompleteEditView* edit_view = loc_bar->location_entry();
   3072   edit_view->model()->OnSetFocus(false);
   3073   edit_view->SetUserText(text);
   3074   reply.SendSuccess(NULL);
   3075 }
   3076 
   3077 // Sample json input: { "command": "OmniboxMovePopupSelection",
   3078 //                      "count": 1 }
   3079 // Negative count implies up, positive implies down. Count values will be
   3080 // capped by the size of the popup list.
   3081 void TestingAutomationProvider::OmniboxMovePopupSelection(
   3082     Browser* browser,
   3083     DictionaryValue* args,
   3084     IPC::Message* reply_message) {
   3085   int count;
   3086   AutomationJSONReply reply(this, reply_message);
   3087   if (!args->GetInteger("count", &count)) {
   3088     reply.SendError("count missing");
   3089     return;
   3090   }
   3091   LocationBar* loc_bar = browser->window()->GetLocationBar();
   3092   AutocompleteEditModel* model = loc_bar->location_entry()->model();
   3093   model->OnUpOrDownKeyPressed(count);
   3094   reply.SendSuccess(NULL);
   3095 }
   3096 
   3097 // Sample json input: { "command": "OmniboxAcceptInput" }
   3098 void TestingAutomationProvider::OmniboxAcceptInput(
   3099     Browser* browser,
   3100     DictionaryValue* args,
   3101     IPC::Message* reply_message) {
   3102   NavigationController& controller =
   3103       browser->GetSelectedTabContents()->controller();
   3104   new OmniboxAcceptNotificationObserver(&controller, this, reply_message);
   3105   browser->window()->GetLocationBar()->AcceptInput();
   3106 }
   3107 
   3108 // Sample json input: { "command": "GetInstantInfo" }
   3109 void TestingAutomationProvider::GetInstantInfo(Browser* browser,
   3110                                                DictionaryValue* args,
   3111                                                IPC::Message* reply_message) {
   3112   DictionaryValue* info = new DictionaryValue;
   3113   if (browser->instant()) {
   3114     InstantController* instant = browser->instant();
   3115     info->SetBoolean("enabled", true);
   3116     info->SetBoolean("showing", instant->IsShowingInstant());
   3117     info->SetBoolean("active", instant->is_active());
   3118     info->SetBoolean("current", instant->IsCurrent());
   3119     if (instant->GetPreviewContents() &&
   3120         instant->GetPreviewContents()->tab_contents()) {
   3121       TabContents* contents = instant->GetPreviewContents()->tab_contents();
   3122       info->SetBoolean("loading", contents->is_loading());
   3123       info->SetString("location", contents->GetURL().spec());
   3124       info->SetString("title", contents->GetTitle());
   3125     }
   3126   } else {
   3127     info->SetBoolean("enabled", false);
   3128   }
   3129   scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
   3130   return_value->Set("instant", info);
   3131   AutomationJSONReply(this, reply_message).SendSuccess(return_value.get());
   3132 }
   3133 
   3134 // Sample json input: { "command": "GetInitialLoadTimes" }
   3135 // Refer to InitialLoadObserver::GetTimingInformation() for sample output.
   3136 void TestingAutomationProvider::GetInitialLoadTimes(
   3137     Browser*,
   3138     DictionaryValue*,
   3139     IPC::Message* reply_message) {
   3140   scoped_ptr<DictionaryValue> return_value(
   3141       initial_load_observer_->GetTimingInformation());
   3142 
   3143   std::string json_return;
   3144   base::JSONWriter::Write(return_value.get(), false, &json_return);
   3145   AutomationMsg_SendJSONRequest::WriteReplyParams(
   3146       reply_message, json_return, true);
   3147   Send(reply_message);
   3148 }
   3149 
   3150 // Sample json input: { "command": "GetPluginsInfo" }
   3151 // Refer chrome/test/pyautolib/plugins_info.py for sample json output.
   3152 void TestingAutomationProvider::GetPluginsInfo(
   3153     Browser* browser,
   3154     DictionaryValue* args,
   3155     IPC::Message* reply_message) {
   3156   std::vector<webkit::npapi::WebPluginInfo> plugins;
   3157   webkit::npapi::PluginList::Singleton()->GetPlugins(false, &plugins);
   3158   ListValue* items = new ListValue;
   3159   for (std::vector<webkit::npapi::WebPluginInfo>::const_iterator it =
   3160            plugins.begin();
   3161        it != plugins.end();
   3162        ++it) {
   3163     DictionaryValue* item = new DictionaryValue;
   3164     item->SetString("name", it->name);
   3165     item->SetString("path", it->path.value());
   3166     item->SetString("version", it->version);
   3167     item->SetString("desc", it->desc);
   3168     item->SetBoolean("enabled", webkit::npapi::IsPluginEnabled(*it));
   3169     // Add info about mime types.
   3170     ListValue* mime_types = new ListValue();
   3171     for (std::vector<webkit::npapi::WebPluginMimeType>::const_iterator type_it =
   3172              it->mime_types.begin();
   3173          type_it != it->mime_types.end();
   3174          ++type_it) {
   3175       DictionaryValue* mime_type = new DictionaryValue();
   3176       mime_type->SetString("mimeType", type_it->mime_type);
   3177       mime_type->SetString("description", type_it->description);
   3178 
   3179       ListValue* file_extensions = new ListValue();
   3180       for (std::vector<std::string>::const_iterator ext_it =
   3181                type_it->file_extensions.begin();
   3182            ext_it != type_it->file_extensions.end();
   3183            ++ext_it) {
   3184         file_extensions->Append(new StringValue(*ext_it));
   3185       }
   3186       mime_type->Set("fileExtensions", file_extensions);
   3187 
   3188       mime_types->Append(mime_type);
   3189     }
   3190     item->Set("mimeTypes", mime_types);
   3191     items->Append(item);
   3192   }
   3193   scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
   3194   return_value->Set("plugins", items);  // return_value owns items.
   3195 
   3196   AutomationJSONReply(this, reply_message).SendSuccess(return_value.get());
   3197 }
   3198 
   3199 // Sample json input:
   3200 //    { "command": "EnablePlugin",
   3201 //      "path": "/Library/Internet Plug-Ins/Flash Player.plugin" }
   3202 void TestingAutomationProvider::EnablePlugin(Browser* browser,
   3203                                              DictionaryValue* args,
   3204                                              IPC::Message* reply_message) {
   3205   FilePath::StringType path;
   3206   AutomationJSONReply reply(this, reply_message);
   3207   if (!args->GetString("path", &path)) {
   3208     reply.SendError("path not specified.");
   3209     return;
   3210   } else if (!webkit::npapi::PluginList::Singleton()->EnablePlugin(
   3211         FilePath(path))) {
   3212     reply.SendError(StringPrintf("Could not enable plugin for path %s.",
   3213                                  path.c_str()));
   3214     return;
   3215   }
   3216   reply.SendSuccess(NULL);
   3217 }
   3218 
   3219 // Sample json input:
   3220 //    { "command": "DisablePlugin",
   3221 //      "path": "/Library/Internet Plug-Ins/Flash Player.plugin" }
   3222 void TestingAutomationProvider::DisablePlugin(Browser* browser,
   3223                                               DictionaryValue* args,
   3224                                               IPC::Message* reply_message) {
   3225   FilePath::StringType path;
   3226   AutomationJSONReply reply(this, reply_message);
   3227   if (!args->GetString("path", &path)) {
   3228     reply.SendError("path not specified.");
   3229     return;
   3230   } else if (!webkit::npapi::PluginList::Singleton()->DisablePlugin(
   3231         FilePath(path))) {
   3232     reply.SendError(StringPrintf("Could not disable plugin for path %s.",
   3233                                  path.c_str()));
   3234     return;
   3235   }
   3236   reply.SendSuccess(NULL);
   3237 }
   3238 
   3239 // Sample json input:
   3240 //    { "command": "SaveTabContents",
   3241 //      "tab_index": 0,
   3242 //      "filename": <a full pathname> }
   3243 // Sample json output:
   3244 //    {}
   3245 void TestingAutomationProvider::SaveTabContents(
   3246     Browser* browser,
   3247     DictionaryValue* args,
   3248     IPC::Message* reply_message) {
   3249   int tab_index = 0;
   3250   FilePath::StringType filename;
   3251   FilePath::StringType parent_directory;
   3252   TabContentsWrapper* tab_contents = NULL;
   3253 
   3254   if (!args->GetInteger("tab_index", &tab_index) ||
   3255       !args->GetString("filename", &filename)) {
   3256     AutomationJSONReply(this, reply_message)
   3257         .SendError("tab_index or filename param missing");
   3258     return;
   3259   } else {
   3260     tab_contents = browser->GetTabContentsWrapperAt(tab_index);
   3261     if (!tab_contents) {
   3262       AutomationJSONReply(this, reply_message).SendError("no tab at tab_index");
   3263       return;
   3264     }
   3265   }
   3266   // We're doing a SAVE_AS_ONLY_HTML so the the directory path isn't
   3267   // used.  Nevertheless, SavePackage requires it be valid.  Sigh.
   3268   parent_directory = FilePath(filename).DirName().value();
   3269   if (!tab_contents->download_tab_helper()->SavePage(
   3270           FilePath(filename),
   3271           FilePath(parent_directory),
   3272           SavePackage::SAVE_AS_ONLY_HTML)) {
   3273     AutomationJSONReply(this, reply_message).SendError(
   3274         "Could not initiate SavePage");
   3275     return;
   3276   }
   3277   // The observer will delete itself when done.
   3278   new SavePackageNotificationObserver(
   3279       tab_contents->download_tab_helper()->save_package(), this, reply_message);
   3280 }
   3281 
   3282 // Refer to ImportSettings() in chrome/test/pyautolib/pyauto.py for sample
   3283 // json input.
   3284 // Sample json output: "{}"
   3285 void TestingAutomationProvider::ImportSettings(Browser* browser,
   3286                                                DictionaryValue* args,
   3287                                                IPC::Message* reply_message) {
   3288   // Map from the json string passed over to the import item masks.
   3289   std::map<std::string, importer::ImportItem> string_to_import_item;
   3290   string_to_import_item["HISTORY"] = importer::HISTORY;
   3291   string_to_import_item["FAVORITES"] = importer::FAVORITES;
   3292   string_to_import_item["COOKIES"] = importer::COOKIES;
   3293   string_to_import_item["PASSWORDS"] = importer::PASSWORDS;
   3294   string_to_import_item["SEARCH_ENGINES"] = importer::SEARCH_ENGINES;
   3295   string_to_import_item["HOME_PAGE"] = importer::HOME_PAGE;
   3296   string_to_import_item["ALL"] = importer::ALL;
   3297 
   3298   ListValue* import_items_list = NULL;
   3299   if (!args->GetString("import_from", &import_settings_data_.browser_name) ||
   3300       !args->GetBoolean("first_run", &import_settings_data_.first_run) ||
   3301       !args->GetList("import_items", &import_items_list)) {
   3302     AutomationJSONReply(this, reply_message)
   3303         .SendError("Incorrect type for one or more of the arguments.");
   3304     return;
   3305   }
   3306 
   3307   import_settings_data_.import_items = 0;
   3308   int num_items = import_items_list->GetSize();
   3309   for (int i = 0; i < num_items; i++) {
   3310     std::string item;
   3311     import_items_list->GetString(i, &item);
   3312     // If the provided string is not part of the map, error out.
   3313     if (!ContainsKey(string_to_import_item, item)) {
   3314       AutomationJSONReply(this, reply_message)
   3315           .SendError("Invalid item string found in import_items.");
   3316       return;
   3317     }
   3318     import_settings_data_.import_items |= string_to_import_item[item];
   3319   }
   3320 
   3321   import_settings_data_.browser = browser;
   3322   import_settings_data_.reply_message = reply_message;
   3323 
   3324   importer_list_ = new ImporterList;
   3325   importer_list_->DetectSourceProfiles(this);
   3326 }
   3327 
   3328 namespace {
   3329 
   3330 // Translates a dictionary password to a PasswordForm struct.
   3331 webkit_glue::PasswordForm GetPasswordFormFromDict(
   3332     const DictionaryValue& password_dict) {
   3333 
   3334   // If the time is specified, change time to the specified time.
   3335   base::Time time = base::Time::Now();
   3336   int it;
   3337   double dt;
   3338   if (password_dict.GetInteger("time", &it))
   3339     time = base::Time::FromTimeT(it);
   3340   else if (password_dict.GetDouble("time", &dt))
   3341     time = base::Time::FromDoubleT(dt);
   3342 
   3343   std::string signon_realm;
   3344   string16 username_value;
   3345   string16 password_value;
   3346   string16 origin_url_text;
   3347   string16 username_element;
   3348   string16 password_element;
   3349   string16 submit_element;
   3350   string16 action_target_text;
   3351   bool blacklist = false;
   3352   string16 old_password_element;
   3353   string16 old_password_value;
   3354 
   3355   // We don't care if any of these fail - they are either optional or checked
   3356   // before this function is called.
   3357   password_dict.GetString("signon_realm", &signon_realm);
   3358   password_dict.GetString("username_value", &username_value);
   3359   password_dict.GetString("password_value", &password_value);
   3360   password_dict.GetString("origin_url", &origin_url_text);
   3361   password_dict.GetString("username_element", &username_element);
   3362   password_dict.GetString("password_element", &password_element);
   3363   password_dict.GetString("submit_element", &submit_element);
   3364   password_dict.GetString("action_target", &action_target_text);
   3365   password_dict.GetBoolean("blacklist", &blacklist);
   3366 
   3367   GURL origin_gurl(origin_url_text);
   3368   GURL action_target(action_target_text);
   3369 
   3370   webkit_glue::PasswordForm password_form;
   3371   password_form.signon_realm = signon_realm;
   3372   password_form.username_value = username_value;
   3373   password_form.password_value = password_value;
   3374   password_form.origin = origin_gurl;
   3375   password_form.username_element = username_element;
   3376   password_form.password_element = password_element;
   3377   password_form.submit_element = submit_element;
   3378   password_form.action = action_target;
   3379   password_form.blacklisted_by_user = blacklist;
   3380   password_form.date_created = time;
   3381 
   3382   return password_form;
   3383 }
   3384 
   3385 }  // namespace
   3386 
   3387 // See AddSavedPassword() in chrome/test/functional/pyauto.py for sample json
   3388 // input.
   3389 // Sample json output: { "password_added": true }
   3390 void TestingAutomationProvider::AddSavedPassword(
   3391     Browser* browser,
   3392     DictionaryValue* args,
   3393     IPC::Message* reply_message) {
   3394   AutomationJSONReply reply(this, reply_message);
   3395   DictionaryValue* password_dict = NULL;
   3396 
   3397   if (!args->GetDictionary("password", &password_dict)) {
   3398     reply.SendError("Password must be a dictionary.");
   3399     return;
   3400   }
   3401 
   3402   // The signon realm is effectively the primary key and must be included.
   3403   // Check here before calling GetPasswordFormFromDict.
   3404   if (!password_dict->HasKey("signon_realm")) {
   3405     reply.SendError("Password must include signon_realm.");
   3406     return;
   3407   }
   3408   webkit_glue::PasswordForm new_password =
   3409       GetPasswordFormFromDict(*password_dict);
   3410 
   3411   Profile* profile = browser->profile();
   3412   // Use IMPLICIT_ACCESS since new passwords aren't added in incognito mode.
   3413   PasswordStore* password_store =
   3414       profile->GetPasswordStore(Profile::IMPLICIT_ACCESS);
   3415 
   3416   // Set the return based on whether setting the password succeeded.
   3417   scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
   3418 
   3419   // It will be null if it's accessed in an incognito window.
   3420   if (password_store != NULL) {
   3421     password_store->AddLogin(new_password);
   3422     return_value->SetBoolean("password_added", true);
   3423   } else {
   3424     return_value->SetBoolean("password_added", false);
   3425   }
   3426 
   3427   reply.SendSuccess(return_value.get());
   3428 }
   3429 
   3430 // See RemoveSavedPassword() in chrome/test/functional/pyauto.py for sample
   3431 // json input.
   3432 // Sample json output: {}
   3433 void TestingAutomationProvider::RemoveSavedPassword(
   3434     Browser* browser,
   3435     DictionaryValue* args,
   3436     IPC::Message* reply_message) {
   3437   AutomationJSONReply reply(this, reply_message);
   3438   DictionaryValue* password_dict = NULL;
   3439 
   3440   if (!args->GetDictionary("password", &password_dict)) {
   3441     reply.SendError("Password must be a dictionary.");
   3442     return;
   3443   }
   3444 
   3445   // The signon realm is effectively the primary key and must be included.
   3446   // Check here before calling GetPasswordFormFromDict.
   3447   if (!password_dict->HasKey("signon_realm")) {
   3448     reply.SendError("Password must include signon_realm.");
   3449     return;
   3450   }
   3451   webkit_glue::PasswordForm to_remove =
   3452       GetPasswordFormFromDict(*password_dict);
   3453 
   3454   Profile* profile = browser->profile();
   3455   // Use EXPLICIT_ACCESS since passwords can be removed in incognito mode.
   3456   PasswordStore* password_store =
   3457       profile->GetPasswordStore(Profile::EXPLICIT_ACCESS);
   3458 
   3459   password_store->RemoveLogin(to_remove);
   3460   reply.SendSuccess(NULL);
   3461 }
   3462 
   3463 // Sample json input: { "command": "GetSavedPasswords" }
   3464 // Refer to GetSavedPasswords() in chrome/test/pyautolib/pyauto.py for sample
   3465 // json output.
   3466 void TestingAutomationProvider::GetSavedPasswords(
   3467     Browser* browser,
   3468     DictionaryValue* args,
   3469     IPC::Message* reply_message) {
   3470   Profile* profile = browser->profile();
   3471   // Use EXPLICIT_ACCESS since saved passwords can be retrieved in
   3472   // incognito mode.
   3473   PasswordStore* password_store =
   3474       profile->GetPasswordStore(Profile::EXPLICIT_ACCESS);
   3475   password_store->GetAutofillableLogins(
   3476       new AutomationProviderGetPasswordsObserver(this, reply_message));
   3477   // Observer deletes itself after returning.
   3478 }
   3479 
   3480 // Refer to ClearBrowsingData() in chrome/test/pyautolib/pyauto.py for sample
   3481 // json input.
   3482 // Sample json output: {}
   3483 void TestingAutomationProvider::ClearBrowsingData(
   3484     Browser* browser,
   3485     DictionaryValue* args,
   3486     IPC::Message* reply_message) {
   3487   std::map<std::string, BrowsingDataRemover::TimePeriod> string_to_time_period;
   3488   string_to_time_period["LAST_HOUR"] = BrowsingDataRemover::LAST_HOUR;
   3489   string_to_time_period["LAST_DAY"] = BrowsingDataRemover::LAST_DAY;
   3490   string_to_time_period["LAST_WEEK"] = BrowsingDataRemover::LAST_WEEK;
   3491   string_to_time_period["FOUR_WEEKS"] = BrowsingDataRemover::FOUR_WEEKS;
   3492   string_to_time_period["EVERYTHING"] = BrowsingDataRemover::EVERYTHING;
   3493 
   3494   std::map<std::string, int> string_to_mask_value;
   3495   string_to_mask_value["HISTORY"] = BrowsingDataRemover::REMOVE_HISTORY;
   3496   string_to_mask_value["DOWNLOADS"] = BrowsingDataRemover::REMOVE_DOWNLOADS;
   3497   string_to_mask_value["COOKIES"] = BrowsingDataRemover::REMOVE_COOKIES;
   3498   string_to_mask_value["PASSWORDS"] = BrowsingDataRemover::REMOVE_PASSWORDS;
   3499   string_to_mask_value["FORM_DATA"] = BrowsingDataRemover::REMOVE_FORM_DATA;
   3500   string_to_mask_value["CACHE"] = BrowsingDataRemover::REMOVE_CACHE;
   3501 
   3502   std::string time_period;
   3503   ListValue* to_remove;
   3504   if (!args->GetString("time_period", &time_period) ||
   3505       !args->GetList("to_remove", &to_remove)) {
   3506     AutomationJSONReply(this, reply_message)
   3507         .SendError("time_period must be a string and to_remove a list.");
   3508     return;
   3509   }
   3510 
   3511   int remove_mask = 0;
   3512   int num_removals = to_remove->GetSize();
   3513   for (int i = 0; i < num_removals; i++) {
   3514     std::string removal;
   3515     to_remove->GetString(i, &removal);
   3516     // If the provided string is not part of the map, then error out.
   3517     if (!ContainsKey(string_to_mask_value, removal)) {
   3518       AutomationJSONReply(this, reply_message)
   3519           .SendError("Invalid browsing data string found in to_remove.");
   3520       return;
   3521     }
   3522     remove_mask |= string_to_mask_value[removal];
   3523   }
   3524 
   3525   if (!ContainsKey(string_to_time_period, time_period)) {
   3526     AutomationJSONReply(this, reply_message)
   3527         .SendError("Invalid string for time_period.");
   3528     return;
   3529   }
   3530 
   3531   BrowsingDataRemover* remover = new BrowsingDataRemover(
   3532       profile(), string_to_time_period[time_period], base::Time());
   3533 
   3534   remover->AddObserver(
   3535       new AutomationProviderBrowsingDataObserver(this, reply_message));
   3536   remover->Remove(remove_mask);
   3537   // BrowsingDataRemover deletes itself using DeleteTask.
   3538   // The observer also deletes itself after sending the reply.
   3539 }
   3540 
   3541 namespace {
   3542 
   3543   // Get the TabContents from a dictionary of arguments.
   3544   TabContents* GetTabContentsFromDict(const Browser* browser,
   3545                                       const DictionaryValue* args,
   3546                                       std::string* error_message) {
   3547     int tab_index;
   3548     if (!args->GetInteger("tab_index", &tab_index)) {
   3549       *error_message = "Must include tab_index.";
   3550       return NULL;
   3551     }
   3552 
   3553     TabContents* tab_contents = browser->GetTabContentsAt(tab_index);
   3554     if (!tab_contents) {
   3555       *error_message = StringPrintf("No tab at index %d.", tab_index);
   3556       return NULL;
   3557     }
   3558     return tab_contents;
   3559   }
   3560 
   3561   // Get the TranslateInfoBarDelegate from TabContents.
   3562   TranslateInfoBarDelegate* GetTranslateInfoBarDelegate(
   3563       TabContents* tab_contents) {
   3564     for (size_t i = 0; i < tab_contents->infobar_count(); i++) {
   3565       InfoBarDelegate* infobar = tab_contents->GetInfoBarDelegateAt(i);
   3566       if (infobar->AsTranslateInfoBarDelegate())
   3567         return infobar->AsTranslateInfoBarDelegate();
   3568     }
   3569     // No translate infobar.
   3570     return NULL;
   3571   }
   3572 }  // namespace
   3573 
   3574 void TestingAutomationProvider::FindInPage(
   3575     Browser* browser,
   3576     DictionaryValue* args,
   3577     IPC::Message* reply_message) {
   3578   std::string error_message;
   3579   TabContents* tab_contents = GetTabContentsFromDict(browser, args,
   3580                                                      &error_message);
   3581   if (!tab_contents) {
   3582     AutomationJSONReply(this, reply_message).SendError(error_message);
   3583     return;
   3584   }
   3585   string16 search_string;
   3586   bool forward;
   3587   bool match_case;
   3588   bool find_next;
   3589   if (!args->GetString("search_string", &search_string)) {
   3590     AutomationJSONReply(this, reply_message).
   3591         SendError("Must include search_string string.");
   3592     return;
   3593   }
   3594   if (!args->GetBoolean("forward", &forward)) {
   3595     AutomationJSONReply(this, reply_message).
   3596         SendError("Must include forward boolean.");
   3597     return;
   3598   }
   3599   if (!args->GetBoolean("match_case", &match_case)) {
   3600     AutomationJSONReply(this, reply_message).
   3601         SendError("Must include match_case boolean.");
   3602     return;
   3603   }
   3604   if (!args->GetBoolean("find_next", &find_next)) {
   3605     AutomationJSONReply(this, reply_message).
   3606         SendError("Must include find_next boolean.");
   3607     return;
   3608   }
   3609   SendFindRequest(tab_contents,
   3610                   true,
   3611                   search_string,
   3612                   forward,
   3613                   match_case,
   3614                   find_next,
   3615                   reply_message);
   3616 }
   3617 
   3618 // See GetTranslateInfo() in chrome/test/pyautolib/pyauto.py for sample json
   3619 // input and output.
   3620 void TestingAutomationProvider::GetTranslateInfo(
   3621     Browser* browser,
   3622     DictionaryValue* args,
   3623     IPC::Message* reply_message) {
   3624   std::string error_message;
   3625   TabContents* tab_contents = GetTabContentsFromDict(browser, args,
   3626                                                      &error_message);
   3627   if (!tab_contents) {
   3628     AutomationJSONReply(this, reply_message).SendError(error_message);
   3629     return;
   3630   }
   3631 
   3632   // Get the translate bar if there is one and pass it to the observer.
   3633   // The observer will check for null and populate the information accordingly.
   3634   TranslateInfoBarDelegate* translate_bar =
   3635       GetTranslateInfoBarDelegate(tab_contents);
   3636 
   3637   TabLanguageDeterminedObserver* observer = new TabLanguageDeterminedObserver(
   3638       this, reply_message, tab_contents, translate_bar);
   3639   // If the language for the page hasn't been loaded yet, then just make
   3640   // the observer, otherwise call observe directly.
   3641   TranslateTabHelper* helper = TabContentsWrapper::GetCurrentWrapperForContents(
   3642       tab_contents)->translate_tab_helper();
   3643   std::string language = helper->language_state().original_language();
   3644   if (!language.empty()) {
   3645     observer->Observe(NotificationType::TAB_LANGUAGE_DETERMINED,
   3646                       Source<TabContents>(tab_contents),
   3647                       Details<std::string>(&language));
   3648   }
   3649 }
   3650 
   3651 // See SelectTranslateOption() in chrome/test/pyautolib/pyauto.py for sample
   3652 // json input.
   3653 // Sample json output: {}
   3654 void TestingAutomationProvider::SelectTranslateOption(
   3655     Browser* browser,
   3656     DictionaryValue* args,
   3657     IPC::Message* reply_message) {
   3658   std::string option;
   3659   std::string error_message;
   3660   TabContents* tab_contents = GetTabContentsFromDict(browser, args,
   3661                                                      &error_message);
   3662   if (!tab_contents) {
   3663     AutomationJSONReply(this, reply_message).SendError(error_message);
   3664     return;
   3665   }
   3666 
   3667   TranslateInfoBarDelegate* translate_bar =
   3668       GetTranslateInfoBarDelegate(tab_contents);
   3669   if (!translate_bar) {
   3670     AutomationJSONReply(this, reply_message)
   3671         .SendError("There is no translate bar open.");
   3672     return;
   3673   }
   3674 
   3675   if (!args->GetString("option", &option)) {
   3676     AutomationJSONReply(this, reply_message).SendError("Must include option");
   3677     return;
   3678   }
   3679 
   3680   if (option == "translate_page") {
   3681     // Make a new notification observer which will send the reply.
   3682     new PageTranslatedObserver(this, reply_message, tab_contents);
   3683     translate_bar->Translate();
   3684     return;
   3685   } else if (option == "set_target_language") {
   3686     string16 target_language;
   3687     if (!args->GetString("target_language", &target_language)) {
   3688        AutomationJSONReply(this, reply_message)
   3689            .SendError("Must include target_language string.");
   3690       return;
   3691     }
   3692     // Get the target language index based off of the language name.
   3693     size_t target_language_index = TranslateInfoBarDelegate::kNoIndex;
   3694     for (size_t i = 0; i < translate_bar->GetLanguageCount(); i++) {
   3695       if (translate_bar->GetLanguageDisplayableNameAt(i) == target_language) {
   3696         target_language_index = i;
   3697         break;
   3698       }
   3699     }
   3700     if (target_language_index == TranslateInfoBarDelegate::kNoIndex) {
   3701        AutomationJSONReply(this, reply_message)
   3702            .SendError("Invalid target language string.");
   3703        return;
   3704     }
   3705     // If the page has already been translated it will be translated again to
   3706     // the new language. The observer will wait until the page has been
   3707     // translated to reply.
   3708     if (translate_bar->type() == TranslateInfoBarDelegate::AFTER_TRANSLATE) {
   3709       new PageTranslatedObserver(this, reply_message, tab_contents);
   3710       translate_bar->SetTargetLanguage(target_language_index);
   3711       return;
   3712     }
   3713     // Otherwise just send the reply back immediately.
   3714     translate_bar->SetTargetLanguage(target_language_index);
   3715     scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
   3716     return_value->SetBoolean("translation_success", true);
   3717     AutomationJSONReply(this, reply_message).SendSuccess(return_value.get());
   3718     return;
   3719   } else if (option == "click_always_translate_lang_button") {
   3720     if (!translate_bar->ShouldShowAlwaysTranslateButton()) {
   3721       AutomationJSONReply(this, reply_message)
   3722           .SendError("Always translate button not showing.");
   3723       return;
   3724     }
   3725     // Clicking 'Always Translate' triggers a translation. The observer will
   3726     // wait until the translation is complete before sending the reply.
   3727     new PageTranslatedObserver(this, reply_message, tab_contents);
   3728     translate_bar->AlwaysTranslatePageLanguage();
   3729     return;
   3730   }
   3731 
   3732   AutomationJSONReply reply(this, reply_message);
   3733   if (option == "never_translate_language") {
   3734     if (translate_bar->IsLanguageBlacklisted()) {
   3735       reply.SendError("The language was already blacklisted.");
   3736       return;
   3737     }
   3738     translate_bar->ToggleLanguageBlacklist();
   3739     reply.SendSuccess(NULL);
   3740   } else if (option == "never_translate_site") {
   3741     if (translate_bar->IsSiteBlacklisted()) {
   3742       reply.SendError("The site was already blacklisted.");
   3743       return;
   3744     }
   3745     translate_bar->ToggleSiteBlacklist();
   3746     reply.SendSuccess(NULL);
   3747   } else if (option == "toggle_always_translate") {
   3748     translate_bar->ToggleAlwaysTranslate();
   3749     reply.SendSuccess(NULL);
   3750   } else if (option == "revert_translation") {
   3751     translate_bar->RevertTranslation();
   3752     reply.SendSuccess(NULL);
   3753   } else if (option == "click_never_translate_lang_button") {
   3754     if (!translate_bar->ShouldShowNeverTranslateButton()) {
   3755       reply.SendError("Always translate button not showing.");
   3756       return;
   3757     }
   3758     translate_bar->NeverTranslatePageLanguage();
   3759     reply.SendSuccess(NULL);
   3760   } else if (option == "decline_translation") {
   3761     // This is the function called when an infobar is dismissed or when the
   3762     // user clicks the 'Nope' translate button.
   3763     translate_bar->TranslationDeclined();
   3764     tab_contents->RemoveInfoBar(translate_bar);
   3765     reply.SendSuccess(NULL);
   3766   } else {
   3767     reply.SendError("Invalid string found for option.");
   3768   }
   3769 }
   3770 
   3771 // Sample json input: { "command": "GetBlockedPopupsInfo",
   3772 //                      "tab_index": 1 }
   3773 // Refer GetBlockedPopupsInfo() in pyauto.py for sample output.
   3774 void TestingAutomationProvider::GetBlockedPopupsInfo(
   3775     Browser* browser,
   3776     DictionaryValue* args,
   3777     IPC::Message* reply_message) {
   3778   AutomationJSONReply reply(this, reply_message);
   3779   std::string error_message;
   3780   TabContents* tab_contents = GetTabContentsFromDict(
   3781       browser, args, &error_message);
   3782   if (!tab_contents) {
   3783     reply.SendError(error_message);
   3784     return;
   3785   }
   3786   scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
   3787   BlockedContentContainer* popup_container =
   3788       tab_contents->blocked_content_container();
   3789   ListValue* blocked_popups_list = new ListValue;
   3790   if (popup_container) {
   3791     std::vector<TabContents*> blocked_contents;
   3792     popup_container->GetBlockedContents(&blocked_contents);
   3793     for (std::vector<TabContents*>::const_iterator it =
   3794              blocked_contents.begin(); it != blocked_contents.end(); ++it) {
   3795       DictionaryValue* item = new DictionaryValue;
   3796       item->SetString("url", (*it)->GetURL().spec());
   3797       item->SetString("title", (*it)->GetTitle());
   3798       blocked_popups_list->Append(item);
   3799     }
   3800   }
   3801   return_value->Set("blocked_popups", blocked_popups_list);
   3802   reply.SendSuccess(return_value.get());
   3803 }
   3804 
   3805 // Refer UnblockAndLaunchBlockedPopup() in pyauto.py for sample input.
   3806 void TestingAutomationProvider::UnblockAndLaunchBlockedPopup(
   3807     Browser* browser,
   3808     DictionaryValue* args,
   3809     IPC::Message* reply_message) {
   3810   AutomationJSONReply reply(this, reply_message);
   3811   std::string error_message;
   3812   TabContents* tab_contents = GetTabContentsFromDict(
   3813       browser, args, &error_message);
   3814   if (!tab_contents) {
   3815     reply.SendError(error_message);
   3816     return;
   3817   }
   3818   int popup_index;
   3819   if (!args->GetInteger("popup_index", &popup_index)) {
   3820     reply.SendError("Need popup_index arg");
   3821     return;
   3822   }
   3823   scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
   3824   BlockedContentContainer* content_container =
   3825       tab_contents->blocked_content_container();
   3826   if (!content_container ||
   3827       popup_index >= (int)content_container->GetBlockedContentsCount()) {
   3828     reply.SendError(StringPrintf("No popup at index %d", popup_index));
   3829     return;
   3830   }
   3831   std::vector<TabContents*> blocked_contents;
   3832   content_container->GetBlockedContents(&blocked_contents);
   3833   content_container->LaunchForContents(blocked_contents[popup_index]);
   3834   reply.SendSuccess(NULL);
   3835 }
   3836 
   3837 // Sample json input: { "command": "GetThemeInfo" }
   3838 // Refer GetThemeInfo() in chrome/test/pyautolib/pyauto.py for sample output.
   3839 void TestingAutomationProvider::GetThemeInfo(
   3840     Browser* browser,
   3841     DictionaryValue* args,
   3842     IPC::Message* reply_message) {
   3843   scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
   3844   const Extension* theme = ThemeServiceFactory::GetThemeForProfile(profile());
   3845   if (theme) {
   3846     return_value->SetString("name", theme->name());
   3847     return_value->Set("images", theme->GetThemeImages()->DeepCopy());
   3848     return_value->Set("colors", theme->GetThemeColors()->DeepCopy());
   3849     return_value->Set("tints", theme->GetThemeTints()->DeepCopy());
   3850   }
   3851   AutomationJSONReply(this, reply_message).SendSuccess(return_value.get());
   3852 }
   3853 
   3854 namespace {
   3855 
   3856 ListValue* GetHostPermissions(const Extension* ext) {
   3857   ListValue* permissions = new ListValue;
   3858   const URLPatternList pattern_list =
   3859       ext->GetEffectiveHostPermissions().patterns();
   3860   for (URLPatternList::const_iterator perm = pattern_list.begin();
   3861        perm != pattern_list.end(); ++perm) {
   3862     permissions->Append(new StringValue(perm->GetAsString()));
   3863   }
   3864   return permissions;
   3865 }
   3866 
   3867 ListValue* GetAPIPermissions(const Extension* ext) {
   3868   ListValue* permissions = new ListValue;
   3869   std::set<std::string> perm_list = ext->api_permissions();
   3870   for (std::set<std::string>::const_iterator perm = perm_list.begin();
   3871        perm != perm_list.end(); ++perm) {
   3872     permissions->Append(new StringValue(perm->c_str()));
   3873   }
   3874   return permissions;
   3875 }
   3876 
   3877 }  // namespace
   3878 
   3879 // Sample json input: { "command": "GetExtensionsInfo" }
   3880 // See GetExtensionsInfo() in chrome/test/pyautolib/pyauto.py for sample json
   3881 // output.
   3882 void TestingAutomationProvider::GetExtensionsInfo(
   3883     Browser* browser,
   3884     DictionaryValue* args,
   3885     IPC::Message* reply_message) {
   3886   AutomationJSONReply reply(this, reply_message);
   3887   ExtensionService* service = profile()->GetExtensionService();
   3888   if (!service) {
   3889     reply.SendError("No extensions service.");
   3890   }
   3891   scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
   3892   ListValue* extensions_values = new ListValue;
   3893   const ExtensionList* extensions = service->extensions();
   3894   for (ExtensionList::const_iterator it = extensions->begin();
   3895        it != extensions->end(); ++it) {
   3896     const Extension* extension = *it;
   3897     DictionaryValue* extension_value = new DictionaryValue;
   3898     extension_value->SetString("id", extension->id());
   3899     extension_value->SetString("version", extension->VersionString());
   3900     extension_value->SetString("name", extension->name());
   3901     extension_value->SetString("public_key", extension->public_key());
   3902     extension_value->SetString("description", extension->description());
   3903     extension_value->SetString("background_url",
   3904                                extension->background_url().spec());
   3905     extension_value->SetString("options_url",
   3906                                extension->options_url().spec());
   3907     extension_value->Set("host_permissions", GetHostPermissions(extension));
   3908     extension_value->Set("api_permissions", GetAPIPermissions(extension));
   3909     extensions_values->Append(extension_value);
   3910   }
   3911   return_value->Set("extensions", extensions_values);
   3912   reply.SendSuccess(return_value.get());
   3913 }
   3914 
   3915 // See UninstallExtensionById() in chrome/test/pyautolib/pyauto.py for sample
   3916 // json input.
   3917 // Sample json output: {}
   3918 void TestingAutomationProvider::UninstallExtensionById(
   3919     Browser* browser,
   3920     DictionaryValue* args,
   3921     IPC::Message* reply_message) {
   3922   std::string id;
   3923   if (!args->GetString("id", &id)) {
   3924     AutomationJSONReply(this, reply_message).SendError(
   3925         "Must include string id.");
   3926     return;
   3927   }
   3928   ExtensionService* service = profile()->GetExtensionService();
   3929   if (!service) {
   3930     AutomationJSONReply(this, reply_message).SendError(
   3931         "No extensions service.");
   3932     return;
   3933   }
   3934 
   3935   if (!service->GetExtensionById(id, true) &&
   3936       !service->GetTerminatedExtension(id)) {
   3937     // The extension ID does not correspond to any extension, whether crashed
   3938     // or not.
   3939     AutomationJSONReply(this, reply_message).SendError(base::StringPrintf(
   3940         "Extension does not exist: %s.", id.c_str()));
   3941     return;
   3942   }
   3943 
   3944   // Wait for a notification indicating that the extension with the given ID
   3945   // has been uninstalled.  This observer will delete itself.
   3946   new ExtensionUninstallObserver(this, reply_message, id);
   3947   service->UninstallExtension(id, false, NULL);
   3948 }
   3949 
   3950 // Sample json input:
   3951 //    { "command": "GetAutofillProfile" }
   3952 // Refer to GetAutofillProfile() in chrome/test/pyautolib/pyauto.py for sample
   3953 // json output.
   3954 void TestingAutomationProvider::GetAutofillProfile(
   3955     Browser* browser,
   3956     DictionaryValue* args,
   3957     IPC::Message* reply_message) {
   3958   AutomationJSONReply reply(this, reply_message);
   3959   // Get the AutofillProfiles currently in the database.
   3960   int tab_index = 0;
   3961   if (!args->GetInteger("tab_index", &tab_index)) {
   3962     reply.SendError("Invalid or missing tab_index integer value.");
   3963     return;
   3964   }
   3965 
   3966   TabContents* tab_contents = browser->GetTabContentsAt(tab_index);
   3967   if (tab_contents) {
   3968     PersonalDataManager* pdm = tab_contents->profile()->GetOriginalProfile()
   3969         ->GetPersonalDataManager();
   3970     if (pdm) {
   3971       std::vector<AutofillProfile*> autofill_profiles = pdm->profiles();
   3972       std::vector<CreditCard*> credit_cards = pdm->credit_cards();
   3973 
   3974       ListValue* profiles = GetListFromAutofillProfiles(autofill_profiles);
   3975       ListValue* cards = GetListFromCreditCards(credit_cards);
   3976 
   3977       scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
   3978 
   3979       return_value->Set("profiles", profiles);
   3980       return_value->Set("credit_cards", cards);
   3981       reply.SendSuccess(return_value.get());
   3982     } else {
   3983       reply.SendError("No PersonalDataManager.");
   3984       return;
   3985     }
   3986   } else {
   3987     reply.SendError("No tab at that index.");
   3988     return;
   3989   }
   3990 }
   3991 
   3992 // Refer to FillAutofillProfile() in chrome/test/pyautolib/pyauto.py for sample
   3993 // json input.
   3994 // Sample json output: {}
   3995 void TestingAutomationProvider::FillAutofillProfile(
   3996     Browser* browser,
   3997     DictionaryValue* args,
   3998     IPC::Message* reply_message) {
   3999   AutomationJSONReply reply(this, reply_message);
   4000   ListValue* profiles = NULL;
   4001   ListValue* cards = NULL;
   4002 
   4003   // It's ok for profiles/credit_cards elements to be missing.
   4004   args->GetList("profiles", &profiles);
   4005   args->GetList("credit_cards", &cards);
   4006 
   4007   std::string error_mesg;
   4008 
   4009   std::vector<AutofillProfile> autofill_profiles;
   4010   std::vector<CreditCard> credit_cards;
   4011   // Create an AutofillProfile for each of the dictionary profiles.
   4012   if (profiles) {
   4013     autofill_profiles = GetAutofillProfilesFromList(*profiles, &error_mesg);
   4014   }
   4015   // Create a CreditCard for each of the dictionary values.
   4016   if (cards) {
   4017     credit_cards = GetCreditCardsFromList(*cards, &error_mesg);
   4018   }
   4019   if (!error_mesg.empty()) {
   4020     reply.SendError(error_mesg);
   4021     return;
   4022   }
   4023 
   4024   // Save the AutofillProfiles.
   4025   int tab_index = 0;
   4026   if (!args->GetInteger("tab_index", &tab_index)) {
   4027     reply.SendError("Invalid or missing tab_index integer");
   4028     return;
   4029   }
   4030 
   4031   TabContents* tab_contents = browser->GetTabContentsAt(tab_index);
   4032 
   4033   if (tab_contents) {
   4034     PersonalDataManager* pdm = tab_contents->profile()
   4035         ->GetPersonalDataManager();
   4036     if (pdm) {
   4037       if (profiles)
   4038         pdm->SetProfiles(&autofill_profiles);
   4039       if (cards)
   4040         pdm->SetCreditCards(&credit_cards);
   4041     } else {
   4042       reply.SendError("No PersonalDataManager.");
   4043       return;
   4044     }
   4045   } else {
   4046     reply.SendError("No tab at that index.");
   4047     return;
   4048   }
   4049   reply.SendSuccess(NULL);
   4050 }
   4051 
   4052 // Sample json output: { "success": true }
   4053 void TestingAutomationProvider::SignInToSync(Browser* browser,
   4054                                              DictionaryValue* args,
   4055                                              IPC::Message* reply_message) {
   4056   AutomationJSONReply reply(this, reply_message);
   4057   std::string username;
   4058   std::string password;
   4059   if (!args->GetString("username", &username) ||
   4060       !args->GetString("password", &password)) {
   4061       reply.SendError("Invalid or missing args");
   4062       return;
   4063   }
   4064   if (sync_waiter_.get() == NULL) {
   4065     sync_waiter_.reset(new ProfileSyncServiceHarness(
   4066         browser->profile(), username, password, 0));
   4067   } else {
   4068     sync_waiter_->SetCredentials(username, password);
   4069   }
   4070   if (sync_waiter_->SetupSync()) {
   4071     scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
   4072     return_value->SetBoolean("success", true);
   4073     reply.SendSuccess(return_value.get());
   4074   } else {
   4075     reply.SendError("Signing in to sync was unsuccessful");
   4076   }
   4077 }
   4078 
   4079 // Sample json output:
   4080 // {u'summary': u'SYNC DISABLED'}
   4081 //
   4082 // { u'authenticated': True,
   4083 //   u'last synced': u'Just now',
   4084 //   u'summary': u'READY',
   4085 //   u'sync url': u'clients4.google.com',
   4086 //   u'updates received': 42,
   4087 //   u'synced datatypes': [ u'Bookmarks',
   4088 //                          u'Preferences',
   4089 //                          u'Passwords',
   4090 //                          u'Autofill',
   4091 //                          u'Themes',
   4092 //                          u'Extensions',
   4093 //                          u'Apps']}
   4094 void TestingAutomationProvider::GetSyncInfo(Browser* browser,
   4095                                             DictionaryValue* args,
   4096                                             IPC::Message* reply_message) {
   4097   AutomationJSONReply reply(this, reply_message);
   4098   DictionaryValue* sync_info = new DictionaryValue;
   4099   scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
   4100   if (sync_waiter_.get() == NULL) {
   4101     sync_waiter_.reset(
   4102         ProfileSyncServiceHarness::CreateAndAttach(browser->profile()));
   4103   }
   4104   if (!sync_waiter_->IsSyncAlreadySetup()) {
   4105     sync_info->SetString("summary", "SYNC DISABLED");
   4106   } else {
   4107     ProfileSyncService* service = sync_waiter_->service();
   4108     ProfileSyncService::Status status = sync_waiter_->GetStatus();
   4109     sync_info->SetString("summary",
   4110         ProfileSyncService::BuildSyncStatusSummaryText(status.summary));
   4111     sync_info->SetString("sync url", service->sync_service_url().host());
   4112     sync_info->SetBoolean("authenticated", status.authenticated);
   4113     sync_info->SetString("last synced", service->GetLastSyncedTimeString());
   4114     sync_info->SetInteger("updates received", status.updates_received);
   4115     ListValue* synced_datatype_list = new ListValue;
   4116     syncable::ModelTypeSet synced_datatypes;
   4117     service->GetPreferredDataTypes(&synced_datatypes);
   4118     for (syncable::ModelTypeSet::iterator it = synced_datatypes.begin();
   4119          it != synced_datatypes.end(); ++it) {
   4120       synced_datatype_list->Append(
   4121           new StringValue(syncable::ModelTypeToString(*it)));
   4122     }
   4123     sync_info->Set("synced datatypes", synced_datatype_list);
   4124   }
   4125   return_value->Set("sync_info", sync_info);
   4126   reply.SendSuccess(return_value.get());
   4127 }
   4128 
   4129 // Sample json output: { "success": true }
   4130 void TestingAutomationProvider::AwaitSyncCycleCompletion(
   4131     Browser* browser,
   4132     DictionaryValue* args,
   4133     IPC::Message* reply_message) {
   4134   AutomationJSONReply reply(this, reply_message);
   4135   if (sync_waiter_.get() == NULL) {
   4136     sync_waiter_.reset(
   4137         ProfileSyncServiceHarness::CreateAndAttach(browser->profile()));
   4138   }
   4139   if (!sync_waiter_->IsSyncAlreadySetup()) {
   4140     reply.SendError("Not signed in to sync");
   4141     return;
   4142   }
   4143   // Ensure that the profile sync service is initialized before waiting for sync
   4144   // to complete. In cases where the browser is restarted with sync enabled,
   4145   // the sync service may take a while to get reinitialized.
   4146   if (!browser->profile()->GetProfileSyncService()) {
   4147     reply.SendError("ProfileSyncService not initialized.");
   4148     return;
   4149   }
   4150   sync_waiter_->AwaitSyncCycleCompletion("Waiting for sync cycle");
   4151   ProfileSyncService::Status status = sync_waiter_->GetStatus();
   4152   if (status.summary == ProfileSyncService::Status::READY) {
   4153     scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
   4154     return_value->SetBoolean("success", true);
   4155     reply.SendSuccess(return_value.get());
   4156   } else {
   4157     std::string error_msg = "Wait for sync cycle was unsuccessful. "
   4158                             "Sync status: ";
   4159     error_msg.append(
   4160         ProfileSyncService::BuildSyncStatusSummaryText(status.summary));
   4161     reply.SendError(error_msg);
   4162   }
   4163 }
   4164 
   4165 // Refer to EnableSyncForDatatypes() in chrome/test/pyautolib/pyauto.py for
   4166 // sample json input. Sample json output: { "success": true }
   4167 void TestingAutomationProvider::EnableSyncForDatatypes(
   4168     Browser* browser,
   4169     DictionaryValue* args,
   4170     IPC::Message* reply_message) {
   4171   AutomationJSONReply reply(this, reply_message);
   4172   if (sync_waiter_.get() == NULL) {
   4173     sync_waiter_.reset(
   4174         ProfileSyncServiceHarness::CreateAndAttach(browser->profile()));
   4175   }
   4176   if (!sync_waiter_->IsSyncAlreadySetup()) {
   4177     reply.SendError("Not signed in to sync");
   4178     return;
   4179   }
   4180   ListValue* datatypes = NULL;
   4181   if (!args->GetList("datatypes", &datatypes)) {
   4182     reply.SendError("Invalid or missing args");
   4183     return;
   4184   }
   4185   std::string first_datatype;
   4186   datatypes->GetString(0, &first_datatype);
   4187   if (first_datatype == "All") {
   4188     sync_waiter_->EnableSyncForAllDatatypes();
   4189   } else {
   4190     int num_datatypes = datatypes->GetSize();
   4191     for (int i = 0; i < num_datatypes; ++i) {
   4192       std::string datatype_string;
   4193       datatypes->GetString(i, &datatype_string);
   4194       syncable::ModelType datatype =
   4195           syncable::ModelTypeFromString(datatype_string);
   4196       if (datatype == syncable::UNSPECIFIED) {
   4197         AutomationJSONReply(this, reply_message).SendError(StringPrintf(
   4198             "Invalid datatype string: %s.", datatype_string.c_str()));
   4199         return;
   4200       }
   4201       sync_waiter_->EnableSyncForDatatype(datatype);
   4202       sync_waiter_->AwaitSyncCycleCompletion(StringPrintf(
   4203           "Enabling datatype: %s", datatype_string.c_str()));
   4204     }
   4205   }
   4206   ProfileSyncService::Status status = sync_waiter_->GetStatus();
   4207   if (status.summary == ProfileSyncService::Status::READY ||
   4208       status.summary == ProfileSyncService::Status::SYNCING) {
   4209     scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
   4210     return_value->SetBoolean("success", true);
   4211     reply.SendSuccess(return_value.get());
   4212   } else {
   4213     reply.SendError("Enabling sync for given datatypes was unsuccessful");
   4214   }
   4215 }
   4216 
   4217 // Refer to DisableSyncForDatatypes() in chrome/test/pyautolib/pyauto.py for
   4218 // sample json input. Sample json output: { "success": true }
   4219 void TestingAutomationProvider::DisableSyncForDatatypes(
   4220     Browser* browser,
   4221     DictionaryValue* args,
   4222     IPC::Message* reply_message) {
   4223   AutomationJSONReply reply(this, reply_message);
   4224   if (sync_waiter_.get() == NULL) {
   4225     sync_waiter_.reset(
   4226         ProfileSyncServiceHarness::CreateAndAttach(browser->profile()));
   4227   }
   4228   if (!sync_waiter_->IsSyncAlreadySetup()) {
   4229     reply.SendError("Not signed in to sync");
   4230     return;
   4231   }
   4232   ListValue* datatypes = NULL;
   4233   if (!args->GetList("datatypes", &datatypes)) {
   4234     reply.SendError("Invalid or missing args");
   4235     return;
   4236   }
   4237   std::string first_datatype;
   4238   if (!datatypes->GetString(0, &first_datatype)) {
   4239     reply.SendError("Invalid or missing string");
   4240     return;
   4241   }
   4242   if (first_datatype == "All") {
   4243     sync_waiter_->DisableSyncForAllDatatypes();
   4244     ProfileSyncService::Status status = sync_waiter_->GetStatus();
   4245     if (status.summary != ProfileSyncService::Status::READY &&
   4246         status.summary != ProfileSyncService::Status::SYNCING) {
   4247       scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
   4248       return_value->SetBoolean("success", true);
   4249       reply.SendSuccess(return_value.get());
   4250     } else {
   4251       reply.SendError("Disabling all sync datatypes was unsuccessful");
   4252     }
   4253   } else {
   4254     int num_datatypes = datatypes->GetSize();
   4255     for (int i = 0; i < num_datatypes; i++) {
   4256       std::string datatype_string;
   4257       datatypes->GetString(i, &datatype_string);
   4258       syncable::ModelType datatype =
   4259           syncable::ModelTypeFromString(datatype_string);
   4260       if (datatype == syncable::UNSPECIFIED) {
   4261         AutomationJSONReply(this, reply_message).SendError(StringPrintf(
   4262             "Invalid datatype string: %s.", datatype_string.c_str()));
   4263         return;
   4264       }
   4265       sync_waiter_->DisableSyncForDatatype(datatype);
   4266       sync_waiter_->AwaitSyncCycleCompletion(StringPrintf(
   4267           "Disabling datatype: %s", datatype_string.c_str()));
   4268     }
   4269     ProfileSyncService::Status status = sync_waiter_->GetStatus();
   4270     if (status.summary == ProfileSyncService::Status::READY ||
   4271         status.summary == ProfileSyncService::Status::SYNCING) {
   4272       scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
   4273       return_value->SetBoolean("success", true);
   4274       reply.SendSuccess(return_value.get());
   4275     } else {
   4276       reply.SendError("Disabling sync for given datatypes was unsuccessful");
   4277     }
   4278   }
   4279 }
   4280 
   4281 /* static */
   4282 ListValue* TestingAutomationProvider::GetListFromAutofillProfiles(
   4283     const std::vector<AutofillProfile*>& autofill_profiles) {
   4284   ListValue* profiles = new ListValue;
   4285 
   4286   std::map<AutofillFieldType, std::string> autofill_type_to_string
   4287       = GetAutofillFieldToStringMap();
   4288 
   4289   // For each AutofillProfile, transform it to a dictionary object to return.
   4290   for (std::vector<AutofillProfile*>::const_iterator it =
   4291            autofill_profiles.begin();
   4292        it != autofill_profiles.end(); ++it) {
   4293     AutofillProfile* profile = *it;
   4294     DictionaryValue* profile_info = new DictionaryValue;
   4295     // For each of the types, if it has a value, add it to the dictionary.
   4296     for (std::map<AutofillFieldType, std::string>::iterator
   4297          type_it = autofill_type_to_string.begin();
   4298          type_it != autofill_type_to_string.end(); ++type_it) {
   4299       string16 value = profile->GetInfo(type_it->first);
   4300       if (value.length()) {  // If there was something stored for that value.
   4301         profile_info->SetString(type_it->second, value);
   4302       }
   4303     }
   4304     profiles->Append(profile_info);
   4305   }
   4306   return profiles;
   4307 }
   4308 
   4309 /* static */
   4310 ListValue* TestingAutomationProvider::GetListFromCreditCards(
   4311     const std::vector<CreditCard*>& credit_cards) {
   4312   ListValue* cards = new ListValue;
   4313 
   4314   std::map<AutofillFieldType, std::string> credit_card_type_to_string =
   4315       GetCreditCardFieldToStringMap();
   4316 
   4317   // For each AutofillProfile, transform it to a dictionary object to return.
   4318   for (std::vector<CreditCard*>::const_iterator it =
   4319            credit_cards.begin();
   4320        it != credit_cards.end(); ++it) {
   4321     CreditCard* card = *it;
   4322     DictionaryValue* card_info = new DictionaryValue;
   4323     // For each of the types, if it has a value, add it to the dictionary.
   4324     for (std::map<AutofillFieldType, std::string>::iterator type_it =
   4325         credit_card_type_to_string.begin();
   4326         type_it != credit_card_type_to_string.end(); ++type_it) {
   4327       string16 value = card->GetInfo(type_it->first);
   4328       // If there was something stored for that value.
   4329       if (value.length()) {
   4330         card_info->SetString(type_it->second, value);
   4331       }
   4332     }
   4333     cards->Append(card_info);
   4334   }
   4335   return cards;
   4336 }
   4337 
   4338 /* static */
   4339 std::vector<AutofillProfile>
   4340 TestingAutomationProvider::GetAutofillProfilesFromList(
   4341     const ListValue& profiles, std::string* error_message) {
   4342   std::vector<AutofillProfile> autofill_profiles;
   4343   DictionaryValue* profile_info = NULL;
   4344   string16 current_value;
   4345 
   4346   std::map<AutofillFieldType, std::string> autofill_type_to_string =
   4347       GetAutofillFieldToStringMap();
   4348 
   4349   int num_profiles = profiles.GetSize();
   4350   for (int i = 0; i < num_profiles; i++) {
   4351     profiles.GetDictionary(i, &profile_info);
   4352     AutofillProfile profile;
   4353     // Loop through the possible profile types and add those provided.
   4354     for (std::map<AutofillFieldType, std::string>::iterator type_it =
   4355          autofill_type_to_string.begin();
   4356          type_it != autofill_type_to_string.end(); ++type_it) {
   4357       if (profile_info->HasKey(type_it->second)) {
   4358         if (profile_info->GetString(type_it->second,
   4359                                     &current_value)) {
   4360           profile.SetInfo(type_it->first, current_value);
   4361         } else {
   4362           *error_message= "All values must be strings";
   4363           break;
   4364         }
   4365       }
   4366     }
   4367     autofill_profiles.push_back(profile);
   4368   }
   4369   return autofill_profiles;
   4370 }
   4371 
   4372 /* static */
   4373 std::vector<CreditCard> TestingAutomationProvider::GetCreditCardsFromList(
   4374     const ListValue& cards, std::string* error_message) {
   4375   std::vector<CreditCard> credit_cards;
   4376   DictionaryValue* card_info = NULL;
   4377   string16 current_value;
   4378 
   4379   std::map<AutofillFieldType, std::string> credit_card_type_to_string =
   4380       GetCreditCardFieldToStringMap();
   4381 
   4382   int num_credit_cards = cards.GetSize();
   4383   for (int i = 0; i < num_credit_cards; i++) {
   4384     cards.GetDictionary(i, &card_info);
   4385     CreditCard card;
   4386     // Loop through the possible credit card fields and add those provided.
   4387     for (std::map<AutofillFieldType, std::string>::iterator type_it =
   4388         credit_card_type_to_string.begin();
   4389         type_it != credit_card_type_to_string.end(); ++type_it) {
   4390       if (card_info->HasKey(type_it->second)) {
   4391         if (card_info->GetString(type_it->second, &current_value)) {
   4392           card.SetInfo(type_it->first, current_value);
   4393         } else {
   4394           *error_message= "All values must be strings";
   4395           break;
   4396         }
   4397       }
   4398     }
   4399     credit_cards.push_back(card);
   4400   }
   4401   return credit_cards;
   4402 }
   4403 
   4404 /* static */
   4405 std::map<AutofillFieldType, std::string>
   4406     TestingAutomationProvider::GetAutofillFieldToStringMap() {
   4407   std::map<AutofillFieldType, std::string> autofill_type_to_string;
   4408   // Strings ordered by order of fields when adding a profile in Autofill prefs.
   4409   autofill_type_to_string[NAME_FIRST] = "NAME_FIRST";
   4410   autofill_type_to_string[NAME_MIDDLE] = "NAME_MIDDLE";
   4411   autofill_type_to_string[NAME_LAST] = "NAME_LAST";
   4412   autofill_type_to_string[COMPANY_NAME] = "COMPANY_NAME";
   4413   autofill_type_to_string[EMAIL_ADDRESS] = "EMAIL_ADDRESS";
   4414   autofill_type_to_string[ADDRESS_HOME_LINE1] = "ADDRESS_HOME_LINE1";
   4415   autofill_type_to_string[ADDRESS_HOME_LINE2] = "ADDRESS_HOME_LINE2";
   4416   autofill_type_to_string[ADDRESS_HOME_CITY] = "ADDRESS_HOME_CITY";
   4417   autofill_type_to_string[ADDRESS_HOME_STATE] = "ADDRESS_HOME_STATE";
   4418   autofill_type_to_string[ADDRESS_HOME_ZIP] = "ADDRESS_HOME_ZIP";
   4419   autofill_type_to_string[ADDRESS_HOME_COUNTRY] = "ADDRESS_HOME_COUNTRY";
   4420   autofill_type_to_string[PHONE_HOME_COUNTRY_CODE] =
   4421       "PHONE_HOME_COUNTRY_CODE";
   4422   autofill_type_to_string[PHONE_HOME_CITY_CODE] = "PHONE_HOME_CITY_CODE";
   4423   autofill_type_to_string[PHONE_HOME_WHOLE_NUMBER] =
   4424       "PHONE_HOME_WHOLE_NUMBER";
   4425   autofill_type_to_string[PHONE_FAX_COUNTRY_CODE] = "PHONE_FAX_COUNTRY_CODE";
   4426   autofill_type_to_string[PHONE_FAX_CITY_CODE] = "PHONE_FAX_CITY_CODE";
   4427   autofill_type_to_string[PHONE_FAX_WHOLE_NUMBER] = "PHONE_FAX_WHOLE_NUMBER";
   4428   return autofill_type_to_string;
   4429 }
   4430 
   4431 /* static */
   4432 std::map<AutofillFieldType, std::string>
   4433     TestingAutomationProvider::GetCreditCardFieldToStringMap() {
   4434   std::map<AutofillFieldType, std::string> credit_card_type_to_string;
   4435   credit_card_type_to_string[CREDIT_CARD_NAME] = "CREDIT_CARD_NAME";
   4436   credit_card_type_to_string[CREDIT_CARD_NUMBER] = "CREDIT_CARD_NUMBER";
   4437   credit_card_type_to_string[CREDIT_CARD_EXP_MONTH] = "CREDIT_CARD_EXP_MONTH";
   4438   credit_card_type_to_string[CREDIT_CARD_EXP_4_DIGIT_YEAR] =
   4439       "CREDIT_CARD_EXP_4_DIGIT_YEAR";
   4440   return credit_card_type_to_string;
   4441 }
   4442 
   4443 // Refer to GetActiveNotifications() in chrome/test/pyautolib/pyauto.py for
   4444 // sample json input/output.
   4445 void TestingAutomationProvider::GetActiveNotifications(
   4446     Browser* browser,
   4447     DictionaryValue* args,
   4448     IPC::Message* reply_message) {
   4449   new GetActiveNotificationsObserver(this, reply_message);
   4450 }
   4451 
   4452 // Refer to CloseNotification() in chrome/test/pyautolib/pyauto.py for
   4453 // sample json input.
   4454 // Returns empty json message.
   4455 void TestingAutomationProvider::CloseNotification(
   4456     Browser* browser,
   4457     DictionaryValue* args,
   4458     IPC::Message* reply_message) {
   4459   int index;
   4460   if (!args->GetInteger("index", &index)) {
   4461     AutomationJSONReply(this, reply_message)
   4462         .SendError("'index' missing or invalid.");
   4463     return;
   4464   }
   4465   NotificationUIManager* manager = g_browser_process->notification_ui_manager();
   4466   BalloonCollection* collection = manager->balloon_collection();
   4467   const BalloonCollection::Balloons& balloons = collection->GetActiveBalloons();
   4468   int balloon_count = static_cast<int>(balloons.size());
   4469   if (index < 0 || index >= balloon_count) {
   4470     AutomationJSONReply(this, reply_message)
   4471         .SendError(StringPrintf("No notification at index %d", index));
   4472     return;
   4473   }
   4474   // This will delete itself when finished.
   4475   new OnNotificationBalloonCountObserver(
   4476       this, reply_message, collection, balloon_count - 1);
   4477   manager->CancelById(balloons[index]->notification().notification_id());
   4478 }
   4479 
   4480 // Refer to WaitForNotificationCount() in chrome/test/pyautolib/pyauto.py for
   4481 // sample json input.
   4482 // Returns empty json message.
   4483 void TestingAutomationProvider::WaitForNotificationCount(
   4484     Browser* browser,
   4485     DictionaryValue* args,
   4486     IPC::Message* reply_message) {
   4487   int count;
   4488   if (!args->GetInteger("count", &count)) {
   4489     AutomationJSONReply(this, reply_message)
   4490         .SendError("'count' missing or invalid.");
   4491     return;
   4492   }
   4493   NotificationUIManager* manager = g_browser_process->notification_ui_manager();
   4494   BalloonCollection* collection = manager->balloon_collection();
   4495   const BalloonCollection::Balloons& balloons = collection->GetActiveBalloons();
   4496   if (static_cast<int>(balloons.size()) == count) {
   4497     AutomationJSONReply(this, reply_message).SendSuccess(NULL);
   4498     return;
   4499   }
   4500   // This will delete itself when finished.
   4501   new OnNotificationBalloonCountObserver(
   4502       this, reply_message, collection, count);
   4503 }
   4504 
   4505 // Sample JSON input: { "command": "GetNTPInfo" }
   4506 // For output, refer to chrome/test/pyautolib/ntp_model.py.
   4507 void TestingAutomationProvider::GetNTPInfo(
   4508     Browser* browser,
   4509     DictionaryValue* args,
   4510     IPC::Message* reply_message) {
   4511   // This observer will delete itself.
   4512   new NTPInfoObserver(this, reply_message, &consumer_);
   4513 }
   4514 
   4515 void TestingAutomationProvider::MoveNTPMostVisitedThumbnail(
   4516     Browser* browser,
   4517     DictionaryValue* args,
   4518     IPC::Message* reply_message) {
   4519   AutomationJSONReply reply(this, reply_message);
   4520   std::string url, error;
   4521   int index, old_index;
   4522   if (!args->GetString("url", &url)) {
   4523     reply.SendError("Missing or invalid 'url' key.");
   4524     return;
   4525   }
   4526   if (!args->GetInteger("index", &index)) {
   4527     reply.SendError("Missing or invalid 'index' key.");
   4528     return;
   4529   }
   4530   if (!args->GetInteger("old_index", &old_index)) {
   4531     reply.SendError("Missing or invalid 'old_index' key");
   4532     return;
   4533   }
   4534   history::TopSites* top_sites = browser->profile()->GetTopSites();
   4535   if (!top_sites) {
   4536     reply.SendError("TopSites service is not initialized.");
   4537     return;
   4538   }
   4539   GURL swapped;
   4540   // If thumbnail A is switching positions with a pinned thumbnail B, B
   4541   // should be pinned in the old index of A.
   4542   if (top_sites->GetPinnedURLAtIndex(index, &swapped)) {
   4543     top_sites->AddPinnedURL(swapped, old_index);
   4544   }
   4545   top_sites->AddPinnedURL(GURL(url), index);
   4546   reply.SendSuccess(NULL);
   4547 }
   4548 
   4549 void TestingAutomationProvider::RemoveNTPMostVisitedThumbnail(
   4550     Browser* browser,
   4551     DictionaryValue* args,
   4552     IPC::Message* reply_message) {
   4553   AutomationJSONReply reply(this, reply_message);
   4554   std::string url;
   4555   if (!args->GetString("url", &url)) {
   4556     reply.SendError("Missing or invalid 'url' key.");
   4557     return;
   4558   }
   4559   history::TopSites* top_sites = browser->profile()->GetTopSites();
   4560   if (!top_sites) {
   4561     reply.SendError("TopSites service is not initialized.");
   4562     return;
   4563   }
   4564   top_sites->AddBlacklistedURL(GURL(url));
   4565   reply.SendSuccess(NULL);
   4566 }
   4567 
   4568 void TestingAutomationProvider::UnpinNTPMostVisitedThumbnail(
   4569     Browser* browser,
   4570     DictionaryValue* args,
   4571     IPC::Message* reply_message) {
   4572   AutomationJSONReply reply(this, reply_message);
   4573   std::string url;
   4574   if (!args->GetString("url", &url)) {
   4575     reply.SendError("Missing or invalid 'url' key.");
   4576     return;
   4577   }
   4578   history::TopSites* top_sites = browser->profile()->GetTopSites();
   4579   if (!top_sites) {
   4580     reply.SendError("TopSites service is not initialized.");
   4581     return;
   4582   }
   4583   top_sites->RemovePinnedURL(GURL(url));
   4584   reply.SendSuccess(NULL);
   4585 }
   4586 
   4587 void TestingAutomationProvider::RestoreAllNTPMostVisitedThumbnails(
   4588     Browser* browser,
   4589     DictionaryValue* args,
   4590     IPC::Message* reply_message) {
   4591   AutomationJSONReply reply(this, reply_message);
   4592   history::TopSites* top_sites = browser->profile()->GetTopSites();
   4593   if (!top_sites) {
   4594     reply.SendError("TopSites service is not initialized.");
   4595     return;
   4596   }
   4597   top_sites->ClearBlacklistedURLs();
   4598   reply.SendSuccess(NULL);
   4599 }
   4600 
   4601 void TestingAutomationProvider::KillRendererProcess(
   4602     Browser* browser,
   4603     DictionaryValue* args,
   4604     IPC::Message* reply_message) {
   4605   int pid;
   4606   if (!args->GetInteger("pid", &pid)) {
   4607     AutomationJSONReply(this, reply_message)
   4608         .SendError("'pid' key missing or invalid.");
   4609     return;
   4610   }
   4611   base::ProcessHandle process;
   4612   if (!base::OpenProcessHandle(static_cast<base::ProcessId>(pid), &process)) {
   4613     AutomationJSONReply(this, reply_message).SendError(base::StringPrintf(
   4614         "Failed to open process handle for pid %d", pid));
   4615     return;
   4616   }
   4617   new RendererProcessClosedObserver(this, reply_message);
   4618   base::KillProcess(process, 0, false);
   4619   base::CloseProcessHandle(process);
   4620 }
   4621 
   4622 bool TestingAutomationProvider::BuildWebKeyEventFromArgs(
   4623     DictionaryValue* args,
   4624     std::string* error,
   4625     NativeWebKeyboardEvent* event) {
   4626   int type, modifiers;
   4627   bool is_system_key;
   4628   string16 unmodified_text, text;
   4629   std::string key_identifier;
   4630   if (!args->GetInteger("type", &type)) {
   4631     *error = "'type' missing or invalid.";
   4632     return false;
   4633   }
   4634   if (!args->GetBoolean("isSystemKey", &is_system_key)) {
   4635     *error = "'isSystemKey' missing or invalid.";
   4636     return false;
   4637   }
   4638   if (!args->GetString("unmodifiedText", &unmodified_text)) {
   4639     *error = "'unmodifiedText' missing or invalid.";
   4640     return false;
   4641   }
   4642   if (!args->GetString("text", &text)) {
   4643     *error = "'text' missing or invalid.";
   4644     return false;
   4645   }
   4646   if (!args->GetInteger("nativeKeyCode", &event->nativeKeyCode)) {
   4647     *error = "'nativeKeyCode' missing or invalid.";
   4648     return false;
   4649   }
   4650   if (!args->GetInteger("windowsKeyCode", &event->windowsKeyCode)) {
   4651     *error = "'windowsKeyCode' missing or invalid.";
   4652     return false;
   4653   }
   4654   if (!args->GetInteger("modifiers", &modifiers)) {
   4655     *error = "'modifiers' missing or invalid.";
   4656     return false;
   4657   }
   4658   if (args->GetString("keyIdentifier", &key_identifier)) {
   4659     base::strlcpy(event->keyIdentifier,
   4660                   key_identifier.c_str(),
   4661                   WebKit::WebKeyboardEvent::keyIdentifierLengthCap);
   4662   } else {
   4663     event->setKeyIdentifierFromWindowsKeyCode();
   4664   }
   4665 
   4666   if (type == automation::kRawKeyDownType) {
   4667     event->type = WebKit::WebInputEvent::RawKeyDown;
   4668   } else if (type == automation::kKeyDownType) {
   4669     event->type = WebKit::WebInputEvent::KeyDown;
   4670   } else if (type == automation::kKeyUpType) {
   4671     event->type = WebKit::WebInputEvent::KeyUp;
   4672   } else if (type == automation::kCharType) {
   4673     event->type = WebKit::WebInputEvent::Char;
   4674   } else {
   4675     *error = "'type' refers to an unrecognized keyboard event type";
   4676     return false;
   4677   }
   4678 
   4679   string16 unmodified_text_truncated = unmodified_text.substr(
   4680       0, WebKit::WebKeyboardEvent::textLengthCap - 1);
   4681   memcpy(event->unmodifiedText,
   4682          unmodified_text_truncated.c_str(),
   4683          unmodified_text_truncated.length() + 1);
   4684   string16 text_truncated = text.substr(
   4685       0, WebKit::WebKeyboardEvent::textLengthCap - 1);
   4686   memcpy(event->text, text_truncated.c_str(), text_truncated.length() + 1);
   4687 
   4688   event->modifiers = 0;
   4689   if (modifiers & automation::kShiftKeyMask)
   4690     event->modifiers |= WebKit::WebInputEvent::ShiftKey;
   4691   if (modifiers & automation::kControlKeyMask)
   4692     event->modifiers |= WebKit::WebInputEvent::ControlKey;
   4693   if (modifiers & automation::kAltKeyMask)
   4694     event->modifiers |= WebKit::WebInputEvent::AltKey;
   4695   if (modifiers & automation::kMetaKeyMask)
   4696     event->modifiers |= WebKit::WebInputEvent::MetaKey;
   4697 
   4698   event->isSystemKey = is_system_key;
   4699   event->timeStampSeconds = base::Time::Now().ToDoubleT();
   4700   event->skip_in_browser = true;
   4701   return true;
   4702 }
   4703 
   4704 void TestingAutomationProvider::SendWebkitKeyEvent(
   4705     DictionaryValue* args,
   4706     IPC::Message* reply_message) {
   4707   NativeWebKeyboardEvent event;
   4708   // BuildWebKeyEventFromArgs handles telling what when wrong and sending
   4709   // the reply message, if it failed we just have to stop here.
   4710   std::string error;
   4711   if (!BuildWebKeyEventFromArgs(args, &error, &event)) {
   4712     AutomationJSONReply(this, reply_message).SendError(error);
   4713     return;
   4714   }
   4715 
   4716   TabContents* tab_contents;
   4717   if (!GetTabFromJSONArgs(args, &tab_contents, &error)) {
   4718     AutomationJSONReply(this, reply_message).SendError(error);
   4719     return;
   4720   }
   4721   new InputEventAckNotificationObserver(this, reply_message, event.type);
   4722   tab_contents->render_view_host()->ForwardKeyboardEvent(event);
   4723 }
   4724 
   4725 void TestingAutomationProvider::SendOSLevelKeyEventToTab(
   4726     DictionaryValue* args,
   4727     IPC::Message* reply_message) {
   4728   int modifiers, keycode;
   4729   if (!args->GetInteger("keyCode", &keycode)) {
   4730     AutomationJSONReply(this, reply_message)
   4731         .SendError("'keyCode' missing or invalid.");
   4732     return;
   4733   }
   4734   if (!args->GetInteger("modifiers", &modifiers)) {
   4735     AutomationJSONReply(this, reply_message)
   4736         .SendError("'modifiers' missing or invalid.");
   4737     return;
   4738   }
   4739 
   4740   std::string error;
   4741   Browser* browser;
   4742   TabContents* tab_contents;
   4743   if (!GetBrowserAndTabFromJSONArgs(args, &browser, &tab_contents, &error)) {
   4744     AutomationJSONReply(this, reply_message).SendError(error);
   4745     return;
   4746   }
   4747   // The key events will be sent to the browser window, we need the current tab
   4748   // containing the element we send the text in to be shown.
   4749   browser->ActivateTabAt(
   4750       browser->GetIndexOfController(&tab_contents->controller()), true);
   4751 
   4752   BrowserWindow* browser_window = browser->window();
   4753   if (!browser_window) {
   4754     AutomationJSONReply(this, reply_message)
   4755         .SendError("Could not get the browser window");
   4756     return;
   4757   }
   4758   gfx::NativeWindow window = browser_window->GetNativeHandle();
   4759   if (!window) {
   4760     AutomationJSONReply(this, reply_message)
   4761         .SendError("Could not get the browser window handle");
   4762     return;
   4763   }
   4764 
   4765   bool control = !!(modifiers & automation::kControlKeyMask);
   4766   bool shift = !!(modifiers & automation::kShiftKeyMask);
   4767   bool alt = !!(modifiers & automation::kAltKeyMask);
   4768   bool meta = !!(modifiers & automation::kMetaKeyMask);
   4769   if (!ui_controls::SendKeyPressNotifyWhenDone(
   4770           window, static_cast<ui::KeyboardCode>(keycode),
   4771           control, shift, alt, meta,
   4772           NewRunnableMethod(this,
   4773               &TestingAutomationProvider::SendSuccessReply, reply_message))) {
   4774     AutomationJSONReply(this, reply_message)
   4775         .SendError("Could not send the native key event");
   4776   }
   4777 }
   4778 
   4779 void TestingAutomationProvider::SendSuccessReply(IPC::Message* reply_message) {
   4780   AutomationJSONReply(this, reply_message).SendSuccess(NULL);
   4781 }
   4782 
   4783 // Sample JSON input: { "command": "GetNTPThumbnailMode" }
   4784 // For output, refer to GetNTPThumbnailMode() in
   4785 // chrome/test/pyautolib/pyauto.py.
   4786 void TestingAutomationProvider::GetNTPThumbnailMode(
   4787     Browser* browser,
   4788     DictionaryValue* args,
   4789     IPC::Message* reply_message) {
   4790   const int shown_sections = ShownSectionsHandler::GetShownSections(
   4791       browser->profile()->GetPrefs());
   4792 
   4793   scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
   4794   return_value->SetBoolean("apps", shown_sections & APPS ? true : false);
   4795   return_value->SetBoolean("most_visited",
   4796                            shown_sections & THUMB ? true : false);
   4797 
   4798   AutomationJSONReply reply(this, reply_message);
   4799   reply.SendSuccess(return_value.get());
   4800 }
   4801 
   4802 // Sample JSON input: { "command": "SetNTPThumbnailMode", "section": "apps",
   4803 //                      "turn_on": true }
   4804 // Refer to SetNTPThumbnailMode() in chrome/test/pyautolib/pyauto.py for
   4805 // all possible input values.
   4806 // Sample JSON output: {}
   4807 void TestingAutomationProvider::SetNTPThumbnailMode(
   4808     Browser* browser,
   4809     DictionaryValue* args,
   4810     IPC::Message* reply_message) {
   4811   AutomationJSONReply reply(this, reply_message);
   4812   std::string section_name;
   4813   bool turn_on;
   4814   if (!args->GetString("section", &section_name) ||
   4815       !args->GetBoolean("turn_on", &turn_on)) {
   4816     reply.SendError("Invalid or missing args");
   4817     return;
   4818   }
   4819 
   4820   PrefService* prefs = browser->profile()->GetPrefs();
   4821   Section section;
   4822   if (section_name.compare("apps") == 0) {
   4823     section = APPS;
   4824   } else if (section_name.compare("most_visited") == 0) {
   4825     section = THUMB;
   4826   } else if (section_name.compare("recently_closed") == 0) {
   4827     reply.SendError("Thumbnail mode does not apply to the recently closed "
   4828                     "section.");
   4829     return;
   4830   } else {
   4831     reply.SendError(StringPrintf("Unexpected section name: '%s'",
   4832                                  section_name.c_str()));
   4833     return;
   4834   }
   4835 
   4836   if (turn_on) {
   4837     ShownSectionsHandler::SetShownSection(prefs, section);
   4838   } else {
   4839     int shown_sections = ShownSectionsHandler::GetShownSections(prefs);
   4840     // Change the bit for the relevant section in the bitmask to 0.
   4841     shown_sections &= ~(0xFFFFFFFF & section);
   4842     prefs->SetInteger(prefs::kNTPShownSections, shown_sections);
   4843   }
   4844 
   4845   reply.SendSuccess(NULL);
   4846 }
   4847 
   4848 // Sample JSON input: { "command": "GetNTPMenuMode" }
   4849 // For output, refer to GetNTPMenuMode() in
   4850 // chrome/test/pyautolib/pyauto.py.
   4851 void TestingAutomationProvider::GetNTPMenuMode(
   4852     Browser* browser,
   4853     DictionaryValue* args,
   4854     IPC::Message* reply_message) {
   4855   const int shown_sections = ShownSectionsHandler::GetShownSections(
   4856       browser->profile()->GetPrefs());
   4857 
   4858   scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
   4859   return_value->SetBoolean("apps", shown_sections & MENU_APPS ? true : false);
   4860   return_value->SetBoolean("most_visited",
   4861                            shown_sections & MENU_THUMB ? true : false);
   4862   return_value->SetBoolean("recently_closed",
   4863                            shown_sections & MENU_RECENT ? true : false);
   4864 
   4865   AutomationJSONReply reply(this, reply_message);
   4866   reply.SendSuccess(return_value.get());
   4867 }
   4868 
   4869 // Sample JSON input: { "command": "SetNTPMenuMode", "section": "apps",
   4870 //                      "turn_on": false }
   4871 // Refer to SetNTPMenuMode() in chrome/test/pyautolib/pyauto.py for all possible
   4872 // input values.
   4873 // Sample JSON output: {}
   4874 void TestingAutomationProvider::SetNTPMenuMode(
   4875     Browser* browser,
   4876     DictionaryValue* args,
   4877     IPC::Message* reply_message) {
   4878   AutomationJSONReply reply(this, reply_message);
   4879   std::string section_name;
   4880   bool turn_on;
   4881   if (!args->GetString("section", &section_name) ||
   4882       !args->GetBoolean("turn_on", &turn_on)) {
   4883     reply.SendError("Invalid or missing args");
   4884     return;
   4885   }
   4886 
   4887   PrefService* prefs = browser->profile()->GetPrefs();
   4888   Section section;
   4889   if (section_name.compare("apps") == 0) {
   4890     section = MENU_APPS;
   4891   } else if (section_name.compare("most_visited") == 0) {
   4892     section = MENU_THUMB;
   4893   } else if (section_name.compare("recently_closed") == 0) {
   4894     section = MENU_RECENT;
   4895   } else {
   4896     reply.SendError(StringPrintf("Unexpected section name: '%s'",
   4897                                  section_name.c_str()));
   4898     return;
   4899   }
   4900 
   4901   int shown_sections = ShownSectionsHandler::GetShownSections(prefs);
   4902   if (turn_on) {
   4903     // Change the bit for the relevant section in the bitmask to 1.
   4904     shown_sections |= section;
   4905   } else {
   4906     // Change the bit for the relevant section in the bitmask to 0.
   4907     shown_sections &= ~(0xFFFFFFFF & section);
   4908   }
   4909   prefs->SetInteger(prefs::kNTPShownSections, shown_sections);
   4910 
   4911   reply.SendSuccess(NULL);
   4912 }
   4913 
   4914 // Sample JSON input: { "command": "LaunchApp",
   4915 //                      "id": "ahfgeienlihckogmohjhadlkjgocpleb" }
   4916 // Sample JSON output: {}
   4917 void TestingAutomationProvider::LaunchApp(
   4918     Browser* browser,
   4919     DictionaryValue* args,
   4920     IPC::Message* reply_message) {
   4921   std::string id;
   4922   if (!args->GetString("id", &id)) {
   4923     AutomationJSONReply(this, reply_message).SendError(
   4924         "Must include string id.");
   4925     return;
   4926   }
   4927 
   4928   ExtensionService* service = browser->profile()->GetExtensionService();
   4929   if (!service) {
   4930     AutomationJSONReply(this, reply_message).SendError(
   4931         "No extensions service.");
   4932     return;
   4933   }
   4934 
   4935   const Extension* extension = service->GetExtensionById(
   4936       id, false  /* do not include disabled extensions */);
   4937   if (!extension) {
   4938     AutomationJSONReply(this, reply_message).SendError(
   4939         StringPrintf("Extension with ID '%s' doesn't exist or is disabled.",
   4940                      id.c_str()));
   4941     return;
   4942   }
   4943 
   4944   // Look at preferences to find the right launch container.  If no preference
   4945   // is set, launch as a regular tab.
   4946   extension_misc::LaunchContainer launch_container =
   4947       service->extension_prefs()->GetLaunchContainer(
   4948           extension, ExtensionPrefs::LAUNCH_REGULAR);
   4949 
   4950   TabContents* old_contents = browser->GetSelectedTabContents();
   4951   if (!old_contents) {
   4952     AutomationJSONReply(this, reply_message).SendError(
   4953         "Cannot identify selected tab contents.");
   4954     return;
   4955   }
   4956 
   4957   // This observer will delete itself.
   4958   new AppLaunchObserver(&old_contents->controller(), this, reply_message,
   4959                         launch_container);
   4960   Browser::OpenApplication(profile(), extension, launch_container,
   4961                            old_contents);
   4962 }
   4963 
   4964 // Sample JSON input: { "command": "SetAppLaunchType",
   4965 //                      "id": "ahfgeienlihckogmohjhadlkjgocpleb",
   4966 //                      "launch_type": "pinned" }
   4967 // Sample JSON output: {}
   4968 void TestingAutomationProvider::SetAppLaunchType(
   4969     Browser* browser,
   4970     DictionaryValue* args,
   4971     IPC::Message* reply_message) {
   4972   AutomationJSONReply reply(this, reply_message);
   4973 
   4974   std::string id;
   4975   if (!args->GetString("id", &id)) {
   4976     reply.SendError("Must include string id.");
   4977     return;
   4978   }
   4979 
   4980   std::string launch_type_str;
   4981   if (!args->GetString("launch_type", &launch_type_str)) {
   4982     reply.SendError("Must specify app launch type.");
   4983     return;
   4984   }
   4985 
   4986   ExtensionService* service = browser->profile()->GetExtensionService();
   4987   if (!service) {
   4988     reply.SendError("No extensions service.");
   4989     return;
   4990   }
   4991 
   4992   const Extension* extension = service->GetExtensionById(
   4993       id, true  /* include disabled extensions */);
   4994   if (!extension) {
   4995     reply.SendError(
   4996         StringPrintf("Extension with ID '%s' doesn't exist.", id.c_str()));
   4997     return;
   4998   }
   4999 
   5000   ExtensionPrefs::LaunchType launch_type;
   5001   if (launch_type_str == "pinned") {
   5002     launch_type = ExtensionPrefs::LAUNCH_PINNED;
   5003   } else if (launch_type_str == "regular") {
   5004     launch_type = ExtensionPrefs::LAUNCH_REGULAR;
   5005   } else if (launch_type_str == "fullscreen") {
   5006     launch_type = ExtensionPrefs::LAUNCH_FULLSCREEN;
   5007   } else if (launch_type_str == "window") {
   5008     launch_type = ExtensionPrefs::LAUNCH_WINDOW;
   5009   } else {
   5010     reply.SendError(
   5011         StringPrintf("Unexpected launch type '%s'.", launch_type_str.c_str()));
   5012     return;
   5013   }
   5014 
   5015   service->extension_prefs()->SetLaunchType(extension->id(), launch_type);
   5016   reply.SendSuccess(NULL);
   5017 }
   5018 
   5019 void TestingAutomationProvider::WaitForAllTabsToStopLoading(
   5020     DictionaryValue* args,
   5021     IPC::Message* reply_message) {
   5022   // This class will send the message immediately if no tab is loading.
   5023   new AllTabsStoppedLoadingObserver(this, reply_message);
   5024 }
   5025 
   5026 void TestingAutomationProvider::GetIndicesFromTab(
   5027     DictionaryValue* args,
   5028     IPC::Message* reply_message) {
   5029   AutomationJSONReply reply(this, reply_message);
   5030   int id_or_handle = 0;
   5031   bool has_id = args->HasKey("tab_id");
   5032   bool has_handle = args->HasKey("tab_handle");
   5033   if (has_id && has_handle) {
   5034     reply.SendError(
   5035         "Both 'tab_id' and 'tab_handle' were specified. Only one is allowed");
   5036     return;
   5037   } else if (!has_id && !has_handle) {
   5038     reply.SendError("Either 'tab_id' or 'tab_handle' must be specified");
   5039     return;
   5040   }
   5041   if (has_id && !args->GetInteger("tab_id", &id_or_handle)) {
   5042     reply.SendError("'tab_id' is invalid");
   5043     return;
   5044   }
   5045   if (has_handle && (!args->GetInteger("tab_handle", &id_or_handle) ||
   5046                      !tab_tracker_->ContainsHandle(id_or_handle))) {
   5047     reply.SendError("'tab_handle' is invalid");
   5048     return;
   5049   }
   5050   int id = id_or_handle;
   5051   if (has_handle)
   5052     id = tab_tracker_->GetResource(id_or_handle)->session_id().id();
   5053   BrowserList::const_iterator iter = BrowserList::begin();
   5054   int browser_index = 0;
   5055   for (; iter != BrowserList::end(); ++iter, ++browser_index) {
   5056     Browser* browser = *iter;
   5057     for (int tab_index = 0; tab_index < browser->tab_count(); ++tab_index) {
   5058       TabContents* tab = browser->GetTabContentsAt(tab_index);
   5059       if (tab->controller().session_id().id() == id) {
   5060         DictionaryValue dict;
   5061         dict.SetInteger("windex", browser_index);
   5062         dict.SetInteger("tab_index", tab_index);
   5063         reply.SendSuccess(&dict);
   5064         return;
   5065       }
   5066     }
   5067   }
   5068   reply.SendError("Could not find tab among current browser windows");
   5069 }
   5070 
   5071 void TestingAutomationProvider::NavigateToURL(
   5072     DictionaryValue* args,
   5073     IPC::Message* reply_message) {
   5074   int navigation_count;
   5075   std::string url, error;
   5076   Browser* browser;
   5077   TabContents* tab_contents;
   5078   if (!GetBrowserAndTabFromJSONArgs(args, &browser, &tab_contents, &error)) {
   5079     AutomationJSONReply(this, reply_message).SendError(error);
   5080     return;
   5081   }
   5082   if (!args->GetString("url", &url)) {
   5083     AutomationJSONReply(this, reply_message)
   5084         .SendError("'url' missing or invalid");
   5085     return;
   5086   }
   5087   if (!args->GetInteger("navigation_count", &navigation_count)) {
   5088     AutomationJSONReply(this, reply_message)
   5089         .SendError("'navigation_count' missing or invalid");
   5090     return;
   5091   }
   5092   new NavigationNotificationObserver(
   5093       &tab_contents->controller(), this, reply_message,
   5094       navigation_count, false, true);
   5095   browser->OpenURLFromTab(
   5096       tab_contents, GURL(url), GURL(), CURRENT_TAB, PageTransition::TYPED);
   5097 }
   5098 
   5099 void TestingAutomationProvider::ExecuteJavascriptJSON(
   5100     DictionaryValue* args,
   5101     IPC::Message* reply_message) {
   5102   string16 frame_xpath, javascript;
   5103   std::string error;
   5104   TabContents* tab_contents;
   5105   if (!GetTabFromJSONArgs(args, &tab_contents, &error)) {
   5106     AutomationJSONReply(this, reply_message).SendError(error);
   5107     return;
   5108   }
   5109   if (!args->GetString("frame_xpath", &frame_xpath)) {
   5110     AutomationJSONReply(this, reply_message)
   5111         .SendError("'frame_xpath' missing or invalid");
   5112     return;
   5113   }
   5114   if (!args->GetString("javascript", &javascript)) {
   5115     AutomationJSONReply(this, reply_message)
   5116         .SendError("'javascript' missing or invalid");
   5117     return;
   5118   }
   5119 
   5120   // Set the routing id of this message with the controller.
   5121   // This routing id needs to be remembered for the reverse
   5122   // communication while sending back the response of
   5123   // this javascript execution.
   5124   std::string set_automation_id;
   5125   base::SStringPrintf(&set_automation_id,
   5126                       "window.domAutomationController.setAutomationId(%d);",
   5127                       reply_message->routing_id());
   5128 
   5129   new DomOperationMessageSender(this, reply_message, true);
   5130   tab_contents->render_view_host()->ExecuteJavascriptInWebFrame(
   5131       frame_xpath, UTF8ToUTF16(set_automation_id));
   5132   tab_contents->render_view_host()->ExecuteJavascriptInWebFrame(
   5133       frame_xpath, javascript);
   5134 }
   5135 
   5136 void TestingAutomationProvider::GoForward(
   5137     DictionaryValue* args,
   5138     IPC::Message* reply_message) {
   5139   TabContents* tab_contents;
   5140   std::string error;
   5141   if (!GetTabFromJSONArgs(args, &tab_contents, &error)) {
   5142     AutomationJSONReply(this, reply_message).SendError(error);
   5143     return;
   5144   }
   5145   NavigationController& controller = tab_contents->controller();
   5146   if (!controller.CanGoForward()) {
   5147     DictionaryValue dict;
   5148     dict.SetBoolean("did_go_forward", false);
   5149     AutomationJSONReply(this, reply_message).SendSuccess(&dict);
   5150     return;
   5151   }
   5152   new NavigationNotificationObserver(&controller, this, reply_message,
   5153                                      1, false, true);
   5154   controller.GoForward();
   5155 }
   5156 
   5157 void TestingAutomationProvider::GoBack(
   5158     DictionaryValue* args,
   5159     IPC::Message* reply_message) {
   5160   TabContents* tab_contents;
   5161   std::string error;
   5162   if (!GetTabFromJSONArgs(args, &tab_contents, &error)) {
   5163     AutomationJSONReply(this, reply_message).SendError(error);
   5164     return;
   5165   }
   5166   NavigationController& controller = tab_contents->controller();
   5167   if (!controller.CanGoBack()) {
   5168     DictionaryValue dict;
   5169     dict.SetBoolean("did_go_back", false);
   5170     AutomationJSONReply(this, reply_message).SendSuccess(&dict);
   5171     return;
   5172   }
   5173   new NavigationNotificationObserver(&controller, this, reply_message,
   5174                                      1, false, true);
   5175   controller.GoBack();
   5176 }
   5177 
   5178 void TestingAutomationProvider::ReloadJSON(
   5179     DictionaryValue* args,
   5180     IPC::Message* reply_message) {
   5181   TabContents* tab_contents;
   5182   std::string error;
   5183   if (!GetTabFromJSONArgs(args, &tab_contents, &error)) {
   5184     AutomationJSONReply(this, reply_message).SendError(error);
   5185     return;
   5186   }
   5187   NavigationController& controller = tab_contents->controller();
   5188   new NavigationNotificationObserver(&controller, this, reply_message,
   5189                                      1, false, true);
   5190   controller.Reload(false);
   5191 }
   5192 
   5193 void TestingAutomationProvider::GetTabURLJSON(
   5194     DictionaryValue* args,
   5195     IPC::Message* reply_message) {
   5196   AutomationJSONReply reply(this, reply_message);
   5197   TabContents* tab_contents;
   5198   std::string error;
   5199   if (!GetTabFromJSONArgs(args, &tab_contents, &error)) {
   5200     reply.SendError(error);
   5201     return;
   5202   }
   5203   DictionaryValue dict;
   5204   dict.SetString("url", tab_contents->GetURL().possibly_invalid_spec());
   5205   reply.SendSuccess(&dict);
   5206 }
   5207 
   5208 void TestingAutomationProvider::GetTabTitleJSON(
   5209     DictionaryValue* args,
   5210     IPC::Message* reply_message) {
   5211   AutomationJSONReply reply(this, reply_message);
   5212   TabContents* tab_contents;
   5213   std::string error;
   5214   if (!GetTabFromJSONArgs(args, &tab_contents, &error)) {
   5215     reply.SendError(error);
   5216     return;
   5217   }
   5218   DictionaryValue dict;
   5219   dict.SetString("title", tab_contents->GetTitle());
   5220   reply.SendSuccess(&dict);
   5221 }
   5222 
   5223 void TestingAutomationProvider::CaptureEntirePageJSON(
   5224     DictionaryValue* args,
   5225     IPC::Message* reply_message) {
   5226   TabContents* tab_contents;
   5227   std::string error;
   5228 
   5229   if (!GetTabFromJSONArgs(args, &tab_contents, &error)) {
   5230     AutomationJSONReply(this, reply_message).SendError(error);
   5231     return;
   5232   }
   5233 
   5234   FilePath::StringType path_str;
   5235   if (!args->GetString("path", &path_str)) {
   5236     AutomationJSONReply(this, reply_message)
   5237         .SendError("'path' missing or invalid");
   5238     return;
   5239   }
   5240 
   5241   RenderViewHost* render_view = tab_contents->render_view_host();
   5242   if (render_view) {
   5243     FilePath path(path_str);
   5244     // This will delete itself when finished.
   5245     PageSnapshotTaker* snapshot_taker = new PageSnapshotTaker(
   5246         this, reply_message, render_view, path);
   5247     snapshot_taker->Start();
   5248   } else {
   5249     AutomationJSONReply(this, reply_message)
   5250         .SendError("Tab has no associated RenderViewHost");
   5251   }
   5252 }
   5253 
   5254 void TestingAutomationProvider::GetCookiesJSON(
   5255     DictionaryValue* args, IPC::Message* reply_message) {
   5256   automation_util::GetCookiesJSON(this, args, reply_message);
   5257 }
   5258 
   5259 void TestingAutomationProvider::DeleteCookieJSON(
   5260     DictionaryValue* args, IPC::Message* reply_message) {
   5261   automation_util::DeleteCookieJSON(this, args, reply_message);
   5262 }
   5263 
   5264 void TestingAutomationProvider::SetCookieJSON(
   5265     DictionaryValue* args, IPC::Message* reply_message) {
   5266   automation_util::SetCookieJSON(this, args, reply_message);
   5267 }
   5268 
   5269 void TestingAutomationProvider::GetTabIds(
   5270     DictionaryValue* args, IPC::Message* reply_message) {
   5271   ListValue* id_list = new ListValue();
   5272   BrowserList::const_iterator iter = BrowserList::begin();
   5273   for (; iter != BrowserList::end(); ++iter) {
   5274     Browser* browser = *iter;
   5275     for (int i = 0; i < browser->tab_count(); ++i) {
   5276       int id = browser->GetTabContentsAt(i)->controller().session_id().id();
   5277       id_list->Append(Value::CreateIntegerValue(id));
   5278     }
   5279   }
   5280   DictionaryValue dict;
   5281   dict.Set("ids", id_list);
   5282   AutomationJSONReply(this, reply_message).SendSuccess(&dict);
   5283 }
   5284 
   5285 void TestingAutomationProvider::IsTabIdValid(
   5286     DictionaryValue* args, IPC::Message* reply_message) {
   5287   AutomationJSONReply reply(this, reply_message);
   5288   int id;
   5289   if (!args->GetInteger("id", &id)) {
   5290     reply.SendError("'id' missing or invalid");
   5291     return;
   5292   }
   5293   bool is_valid = false;
   5294   BrowserList::const_iterator iter = BrowserList::begin();
   5295   for (; iter != BrowserList::end(); ++iter) {
   5296     Browser* browser = *iter;
   5297     for (int i = 0; i < browser->tab_count(); ++i) {
   5298       TabContents* tab = browser->GetTabContentsAt(i);
   5299       if (tab->controller().session_id().id() == id) {
   5300         is_valid = true;
   5301         break;
   5302       }
   5303     }
   5304   }
   5305   DictionaryValue dict;
   5306   dict.SetBoolean("is_valid", is_valid);
   5307   reply.SendSuccess(&dict);
   5308 }
   5309 
   5310 void TestingAutomationProvider::CloseTabJSON(
   5311     DictionaryValue* args, IPC::Message* reply_message) {
   5312   AutomationJSONReply reply(this, reply_message);
   5313   Browser* browser;
   5314   TabContents* tab_contents;
   5315   std::string error;
   5316   if (!GetBrowserAndTabFromJSONArgs(args, &browser, &tab_contents, &error)) {
   5317     reply.SendError(error);
   5318     return;
   5319   }
   5320   browser->CloseTabContents(tab_contents);
   5321   reply.SendSuccess(NULL);
   5322 }
   5323 
   5324 void TestingAutomationProvider::ActivateTabJSON(
   5325     DictionaryValue* args,
   5326     IPC::Message* reply_message) {
   5327   AutomationJSONReply reply(this, reply_message);
   5328   Browser* browser;
   5329   TabContents* tab_contents;
   5330   std::string error;
   5331   if (!GetBrowserAndTabFromJSONArgs(args, &browser, &tab_contents, &error)) {
   5332     reply.SendError(error);
   5333     return;
   5334   }
   5335   browser->ActivateTabAt(
   5336       browser->GetIndexOfController(&tab_contents->controller()), true);
   5337   reply.SendSuccess(NULL);
   5338 }
   5339 
   5340 // Sample json input: { "command": "UpdateExtensionsNow" }
   5341 // Sample json output: {}
   5342 void TestingAutomationProvider::UpdateExtensionsNow(
   5343     DictionaryValue* args,
   5344     IPC::Message* reply_message) {
   5345   ExtensionService* service = profile()->GetExtensionService();
   5346   if (!service) {
   5347     AutomationJSONReply(this, reply_message).SendError(
   5348         "No extensions service.");
   5349     return;
   5350   }
   5351 
   5352   ExtensionUpdater* updater = service->updater();
   5353   if (!updater) {
   5354     AutomationJSONReply(this, reply_message).SendError(
   5355         "No updater for extensions service.");
   5356     return;
   5357   }
   5358 
   5359   ExtensionProcessManager* manager = profile()->GetExtensionProcessManager();
   5360   if (!manager) {
   5361     AutomationJSONReply(this, reply_message).SendError(
   5362         "No extension process manager.");
   5363     return;
   5364   }
   5365 
   5366   // Create a new observer that waits until the extensions have been fully
   5367   // updated (we should not send the reply until after all extensions have
   5368   // been updated).  This observer will delete itself.
   5369   new ExtensionsUpdatedObserver(manager, this, reply_message);
   5370   updater->CheckNow();
   5371 }
   5372 
   5373 void TestingAutomationProvider::GetChromeDriverAutomationVersion(
   5374     DictionaryValue* args,
   5375     IPC::Message* reply_message) {
   5376   DictionaryValue reply_dict;
   5377   reply_dict.SetInteger("version", automation::kChromeDriverAutomationVersion);
   5378   AutomationJSONReply(this, reply_message).SendSuccess(&reply_dict);
   5379 }
   5380 
   5381 void TestingAutomationProvider::WaitForTabCountToBecome(
   5382     int browser_handle,
   5383     int target_tab_count,
   5384     IPC::Message* reply_message) {
   5385   if (!browser_tracker_->ContainsHandle(browser_handle)) {
   5386     AutomationMsg_WaitForTabCountToBecome::WriteReplyParams(reply_message,
   5387                                                             false);
   5388     Send(reply_message);
   5389     return;
   5390   }
   5391 
   5392   Browser* browser = browser_tracker_->GetResource(browser_handle);
   5393 
   5394   // The observer will delete itself.
   5395   new TabCountChangeObserver(this, browser, reply_message, target_tab_count);
   5396 }
   5397 
   5398 void TestingAutomationProvider::WaitForInfoBarCount(
   5399     int tab_handle,
   5400     size_t target_count,
   5401     IPC::Message* reply_message) {
   5402   if (!tab_tracker_->ContainsHandle(tab_handle)) {
   5403     AutomationMsg_WaitForInfoBarCount::WriteReplyParams(reply_message_, false);
   5404     Send(reply_message_);
   5405     return;
   5406   }
   5407 
   5408   NavigationController* controller = tab_tracker_->GetResource(tab_handle);
   5409   if (!controller) {
   5410     AutomationMsg_WaitForInfoBarCount::WriteReplyParams(reply_message_, false);
   5411     Send(reply_message_);
   5412     return;
   5413   }
   5414 
   5415   // The delegate will delete itself.
   5416   new InfoBarCountObserver(this, reply_message, controller->tab_contents(),
   5417                            target_count);
   5418 }
   5419 
   5420 // Gets the current used encoding name of the page in the specified tab.
   5421 void TestingAutomationProvider::GetPageCurrentEncoding(
   5422     int tab_handle, std::string* current_encoding) {
   5423   if (tab_tracker_->ContainsHandle(tab_handle)) {
   5424     NavigationController* nav = tab_tracker_->GetResource(tab_handle);
   5425     Browser* browser = FindAndActivateTab(nav);
   5426     DCHECK(browser);
   5427 
   5428     if (browser->command_updater()->IsCommandEnabled(IDC_ENCODING_MENU))
   5429       *current_encoding = nav->tab_contents()->encoding();
   5430   }
   5431 }
   5432 
   5433 void TestingAutomationProvider::ShutdownSessionService(int handle,
   5434                                                        bool* result) {
   5435   if (browser_tracker_->ContainsHandle(handle)) {
   5436     Browser* browser = browser_tracker_->GetResource(handle);
   5437     browser->profile()->ShutdownSessionService();
   5438     *result = true;
   5439   } else {
   5440     *result = false;
   5441   }
   5442 }
   5443 
   5444 void TestingAutomationProvider::SetContentSetting(
   5445     int handle,
   5446     const std::string& host,
   5447     ContentSettingsType content_type,
   5448     ContentSetting setting,
   5449     bool* success) {
   5450   *success = false;
   5451   if (browser_tracker_->ContainsHandle(handle)) {
   5452     Browser* browser = browser_tracker_->GetResource(handle);
   5453     HostContentSettingsMap* map =
   5454         browser->profile()->GetHostContentSettingsMap();
   5455     if (host.empty()) {
   5456       map->SetDefaultContentSetting(content_type, setting);
   5457     } else {
   5458       map->SetContentSetting(ContentSettingsPattern(host),
   5459                              content_type, "", setting);
   5460     }
   5461     *success = true;
   5462   }
   5463 }
   5464 
   5465 void TestingAutomationProvider::LoadBlockedPlugins(int tab_handle,
   5466                                                    bool* success) {
   5467   *success = false;
   5468   if (tab_tracker_->ContainsHandle(tab_handle)) {
   5469     NavigationController* nav = tab_tracker_->GetResource(tab_handle);
   5470     if (!nav)
   5471       return;
   5472     TabContents* contents = nav->tab_contents();
   5473     if (!contents)
   5474       return;
   5475     contents->render_view_host()->LoadBlockedPlugins();
   5476     *success = true;
   5477   }
   5478 }
   5479 
   5480 void TestingAutomationProvider::ResetToDefaultTheme() {
   5481   ThemeServiceFactory::GetForProfile(profile_)->UseDefaultTheme();
   5482 }
   5483 
   5484 void TestingAutomationProvider::WaitForProcessLauncherThreadToGoIdle(
   5485     IPC::Message* reply_message) {
   5486   new WaitForProcessLauncherThreadToGoIdleObserver(this, reply_message);
   5487 }
   5488 
   5489 void TestingAutomationProvider::GetParentBrowserOfTab(int tab_handle,
   5490                                                       int* browser_handle,
   5491                                                       bool* success) {
   5492   *success = false;
   5493   if (tab_tracker_->ContainsHandle(tab_handle)) {
   5494     NavigationController* controller = tab_tracker_->GetResource(tab_handle);
   5495     int index;
   5496     Browser* browser = Browser::GetBrowserForController(controller, &index);
   5497     if (browser) {
   5498       *browser_handle = browser_tracker_->Add(browser);
   5499       *success = true;
   5500     }
   5501   }
   5502 }
   5503 
   5504 // TODO(brettw) change this to accept GURLs when history supports it
   5505 void TestingAutomationProvider::OnRedirectQueryComplete(
   5506     HistoryService::Handle request_handle,
   5507     GURL from_url,
   5508     bool success,
   5509     history::RedirectList* redirects) {
   5510   DCHECK_EQ(redirect_query_, request_handle);
   5511   DCHECK(reply_message_ != NULL);
   5512 
   5513   std::vector<GURL> redirects_gurl;
   5514   reply_message_->WriteBool(success);
   5515   if (success) {
   5516     for (size_t i = 0; i < redirects->size(); i++)
   5517       redirects_gurl.push_back(redirects->at(i));
   5518   }
   5519 
   5520   IPC::ParamTraits<std::vector<GURL> >::Write(reply_message_, redirects_gurl);
   5521 
   5522   Send(reply_message_);
   5523   redirect_query_ = 0;
   5524   reply_message_ = NULL;
   5525 }
   5526 
   5527 void TestingAutomationProvider::OnRemoveProvider() {
   5528   AutomationProviderList::GetInstance()->RemoveProvider(this);
   5529 }
   5530