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
104namespace {
105
106void 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
124class 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
143TestingAutomationProvider::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
154TestingAutomationProvider::~TestingAutomationProvider() {
155  BrowserList::RemoveObserver(this);
156}
157
158void TestingAutomationProvider::OnBrowserAdded(const Browser* browser) {
159}
160
161void 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
174void 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
208void 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
218bool 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
419void TestingAutomationProvider::OnChannelError() {
420  if (!reinitialize_on_channel_error_ &&
421      browser_shutdown::GetShutdownType() == browser_shutdown::NOT_VALID)
422    BrowserList::CloseAllBrowsersAndExit();
423  AutomationProvider::OnChannelError();
424}
425
426void 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
436void 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
444void 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
457void 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
487void 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
496void 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
513void 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
521void 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
530void 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
538void 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
549void 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
574void TestingAutomationProvider::NavigationAsync(int handle,
575                                                const GURL& url,
576                                                bool* status) {
577  NavigationAsyncWithDisposition(handle, url, CURRENT_TAB, status);
578}
579
580void 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
603void 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
621void 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
646void 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
667void 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
681void 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
713void TestingAutomationProvider::GetBrowserWindowCount(int* window_count) {
714  *window_count = static_cast<int>(BrowserList::size());
715}
716
717void TestingAutomationProvider::GetNormalBrowserWindowCount(int* window_count) {
718  *window_count = static_cast<int>(
719      BrowserList::GetBrowserCountForType(profile_, Browser::TYPE_NORMAL));
720}
721
722void 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
729void 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
738void TestingAutomationProvider::GetLastActiveBrowserWindow(int* handle) {
739  *handle = 0;
740  Browser* browser = BrowserList::GetLastActive();
741  if (browser)
742    *handle = browser_tracker_->Add(browser);
743}
744
745void 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
754void 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
768void 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
805void TestingAutomationProvider::GetBrowserLocale(string16* locale) {
806  *locale = ASCIIToUTF16(g_browser_process->GetApplicationLocale());
807}
808
809void 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
822void 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
833void 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
841void 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
862void 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
907void 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
929void 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
977void 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
986void 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
995void 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
1008void 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
1021void 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
1037void 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
1047void 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
1059void 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
1074void 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
1084void 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
1095void 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
1107void 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
1119void 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
1135void  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
1158void 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
1175void 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
1189void 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
1217void 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
1228void 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
1243void 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
1252void 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
1264void 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
1279void 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
1301void 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
1325void 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
1335void 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
1349void 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
1369void 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
1389void 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
1396void 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
1428void 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
1438void 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
1449void 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
1474void 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
1505void 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
1513void 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
1524void 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.
1542void 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
1571void 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
1590void 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
1608void 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
1635void 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
1663void 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
1689void 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
1712void 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
1735void 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
1759void 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
1768void 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
1802void 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
1809void 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
1827void 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
1839void 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
1851void 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
1864void 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
1876void 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
1893void 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
1915void 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
1929void 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
1942void 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
1960void 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
1978void TestingAutomationProvider::SavePackageShouldPromptUser(
1979    bool should_prompt) {
1980  SavePackage::SetShouldPromptUser(should_prompt);
1981}
1982
1983void 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
2004void 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
2023void 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
2307void 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
2325ListValue* 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: {}
2380void 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
2432namespace {
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().
2437class 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.
2475void 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.
2596void 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.
2647void 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.
2675void 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.
2717void 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
2739void 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
2769namespace {
2770
2771DownloadItem* 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.
2792void 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" }
2856void 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.
2872void 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.
2904void 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 }
2945void 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.
2981void 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 }
2992void 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.
3021void 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" }
3060void 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.
3081void 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" }
3098void 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" }
3109void 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.
3136void 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.
3152void 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" }
3202void 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" }
3222void 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//    {}
3245void 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: "{}"
3285void 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
3328namespace {
3329
3330// Translates a dictionary password to a PasswordForm struct.
3331webkit_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 }
3390void 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: {}
3433void 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.
3466void 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: {}
3483void 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
3541namespace {
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
3574void 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.
3620void 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: {}
3654void 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.
3774void 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.
3806void 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.
3839void 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
3854namespace {
3855
3856ListValue* 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
3867ListValue* 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.
3882void 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: {}
3918void 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.
3954void 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: {}
3995void 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 }
4053void 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']}
4094void 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 }
4130void 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 }
4167void 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 }
4219void 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 */
4282ListValue* 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 */
4310ListValue* 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 */
4339std::vector<AutofillProfile>
4340TestingAutomationProvider::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 */
4373std::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 */
4405std::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 */
4432std::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.
4445void 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.
4455void 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.
4483void 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.
4507void 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
4515void 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
4549void 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
4568void 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
4587void 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
4601void 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
4622bool 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
4704void 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
4725void 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
4779void 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.
4786void 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: {}
4807void 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.
4851void 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: {}
4874void 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: {}
4917void 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: {}
4968void 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
5019void 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
5026void 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
5071void 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
5099void 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
5136void 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
5157void 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
5178void 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
5193void 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
5208void 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
5223void 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
5254void TestingAutomationProvider::GetCookiesJSON(
5255    DictionaryValue* args, IPC::Message* reply_message) {
5256  automation_util::GetCookiesJSON(this, args, reply_message);
5257}
5258
5259void TestingAutomationProvider::DeleteCookieJSON(
5260    DictionaryValue* args, IPC::Message* reply_message) {
5261  automation_util::DeleteCookieJSON(this, args, reply_message);
5262}
5263
5264void TestingAutomationProvider::SetCookieJSON(
5265    DictionaryValue* args, IPC::Message* reply_message) {
5266  automation_util::SetCookieJSON(this, args, reply_message);
5267}
5268
5269void 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
5285void 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
5310void 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
5324void 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: {}
5342void 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
5373void 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
5381void 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
5398void 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.
5421void 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
5433void 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
5444void 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
5465void 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
5480void TestingAutomationProvider::ResetToDefaultTheme() {
5481  ThemeServiceFactory::GetForProfile(profile_)->UseDefaultTheme();
5482}
5483
5484void TestingAutomationProvider::WaitForProcessLauncherThreadToGoIdle(
5485    IPC::Message* reply_message) {
5486  new WaitForProcessLauncherThreadToGoIdleObserver(this, reply_message);
5487}
5488
5489void 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
5505void 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
5527void TestingAutomationProvider::OnRemoveProvider() {
5528  AutomationProviderList::GetInstance()->RemoveProvider(this);
5529}
5530