automation_provider.cc revision c407dc5cd9bdc5668497f21b26b09d988ab439de
1// Copyright (c) 2010 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/automation_provider.h"
6
7#include <set>
8
9#include "app/l10n_util.h"
10#include "app/message_box_flags.h"
11#include "base/callback.h"
12#include "base/file_path.h"
13#include "base/file_version_info.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/keyboard_codes.h"
18#include "base/message_loop.h"
19#include "base/path_service.h"
20#include "base/process_util.h"
21#include "base/stl_util-inl.h"
22#include "base/string_util.h"
23#include "base/task.h"
24#include "base/thread.h"
25#include "base/utf_string_conversions.h"
26#include "base/values.h"
27#include "base/waitable_event.h"
28#include "chrome/app/chrome_dll_resource.h"
29#include "chrome/browser/app_modal_dialog.h"
30#include "chrome/browser/app_modal_dialog_queue.h"
31#include "chrome/browser/autofill/autofill_manager.h"
32#include "chrome/browser/automation/automation_autocomplete_edit_tracker.h"
33#include "chrome/browser/automation/automation_browser_tracker.h"
34#include "chrome/browser/automation/automation_extension_tracker.h"
35#include "chrome/browser/automation/automation_provider_json.h"
36#include "chrome/browser/automation/automation_provider_list.h"
37#include "chrome/browser/automation/automation_provider_observers.h"
38#include "chrome/browser/automation/automation_resource_message_filter.h"
39#include "chrome/browser/automation/automation_tab_tracker.h"
40#include "chrome/browser/automation/automation_window_tracker.h"
41#include "chrome/browser/automation/extension_port_container.h"
42#include "chrome/browser/autocomplete/autocomplete_edit.h"
43#include "chrome/browser/blocked_popup_container.h"
44#include "chrome/browser/bookmarks/bookmark_model.h"
45#include "chrome/browser/bookmarks/bookmark_storage.h"
46#include "chrome/browser/browser_list.h"
47#include "chrome/browser/browser_process.h"
48#include "chrome/browser/browser_window.h"
49#include "chrome/browser/browsing_data_remover.h"
50#include "chrome/browser/character_encoding.h"
51#include "chrome/browser/chrome_thread.h"
52#include "chrome/browser/dom_operation_notification_details.h"
53#include "chrome/browser/debugger/devtools_manager.h"
54#include "chrome/browser/download/download_item.h"
55#include "chrome/browser/download/download_shelf.h"
56#include "chrome/browser/download/save_package.h"
57#include "chrome/browser/extensions/crx_installer.h"
58#include "chrome/browser/extensions/extension_browser_event_router.h"
59#include "chrome/browser/extensions/extension_host.h"
60#include "chrome/browser/extensions/extension_install_ui.h"
61#include "chrome/browser/extensions/extension_message_service.h"
62#include "chrome/browser/extensions/extension_tabs_module.h"
63#include "chrome/browser/extensions/extension_toolbar_model.h"
64#include "chrome/browser/extensions/extensions_service.h"
65#include "chrome/browser/extensions/user_script_master.h"
66#include "chrome/browser/find_bar.h"
67#include "chrome/browser/find_bar_controller.h"
68#include "chrome/browser/find_notification_details.h"
69#include "chrome/browser/host_content_settings_map.h"
70#include "chrome/browser/importer/importer.h"
71#include "chrome/browser/importer/importer_data_types.h"
72#include "chrome/browser/io_thread.h"
73#include "chrome/browser/location_bar.h"
74#include "chrome/browser/login_prompt.h"
75#include "chrome/browser/net/url_request_mock_util.h"
76#include "chrome/browser/platform_util.h"
77#include "chrome/browser/pref_service.h"
78#include "chrome/browser/printing/print_job.h"
79#include "chrome/browser/profile_manager.h"
80#include "chrome/browser/renderer_host/render_process_host.h"
81#include "chrome/browser/renderer_host/render_view_host.h"
82#include "chrome/browser/ssl/ssl_manager.h"
83#include "chrome/browser/ssl/ssl_blocking_page.h"
84#include "chrome/browser/tab_contents/infobar_delegate.h"
85#include "chrome/browser/tab_contents/tab_contents.h"
86#include "chrome/browser/tab_contents/tab_contents_view.h"
87#include "chrome/browser/translate/translate_infobar_delegate.h"
88#include "chrome/common/automation_constants.h"
89#include "chrome/common/chrome_constants.h"
90#include "chrome/common/chrome_paths.h"
91#include "chrome/common/chrome_switches.h"
92#include "chrome/common/chrome_version_info.h"
93#include "chrome/common/extensions/extension.h"
94#include "chrome/common/json_value_serializer.h"
95#include "chrome/common/net/url_request_context_getter.h"
96#include "chrome/common/notification_service.h"
97#include "chrome/common/pref_names.h"
98#include "chrome/common/url_constants.h"
99#include "chrome/test/automation/automation_messages.h"
100#include "chrome/test/automation/tab_proxy.h"
101#include "net/proxy/proxy_service.h"
102#include "net/proxy/proxy_config_service_fixed.h"
103#include "net/url_request/url_request_context.h"
104#include "chrome/browser/automation/ui_controls.h"
105#include "views/event.h"
106#include "webkit/glue/password_form.h"
107#include "webkit/glue/plugins/plugin_list.h"
108
109#if defined(OS_WIN)
110#include "chrome/browser/external_tab_container_win.h"
111#endif  // defined(OS_WIN)
112
113using base::Time;
114
115class AutomationInterstitialPage : public InterstitialPage {
116 public:
117  AutomationInterstitialPage(TabContents* tab,
118                             const GURL& url,
119                             const std::string& contents)
120      : InterstitialPage(tab, true, url),
121        contents_(contents) {
122  }
123
124  virtual std::string GetHTMLContents() { return contents_; }
125
126 private:
127  std::string contents_;
128
129  DISALLOW_COPY_AND_ASSIGN(AutomationInterstitialPage);
130};
131
132class ClickTask : public Task {
133 public:
134  explicit ClickTask(int flags) : flags_(flags) {}
135  virtual ~ClickTask() {}
136
137  virtual void Run() {
138    ui_controls::MouseButton button = ui_controls::LEFT;
139    if ((flags_ & views::Event::EF_LEFT_BUTTON_DOWN) ==
140        views::Event::EF_LEFT_BUTTON_DOWN) {
141      button = ui_controls::LEFT;
142    } else if ((flags_ & views::Event::EF_RIGHT_BUTTON_DOWN) ==
143        views::Event::EF_RIGHT_BUTTON_DOWN) {
144      button = ui_controls::RIGHT;
145    } else if ((flags_ & views::Event::EF_MIDDLE_BUTTON_DOWN) ==
146        views::Event::EF_MIDDLE_BUTTON_DOWN) {
147      button = ui_controls::MIDDLE;
148    } else {
149      NOTREACHED();
150    }
151
152    ui_controls::SendMouseClick(button);
153  }
154
155 private:
156  int flags_;
157
158  DISALLOW_COPY_AND_ASSIGN(ClickTask);
159};
160
161AutomationProvider::AutomationProvider(Profile* profile)
162    : redirect_query_(0),
163      profile_(profile),
164      reply_message_(NULL),
165      popup_menu_waiter_(NULL) {
166  browser_tracker_.reset(new AutomationBrowserTracker(this));
167  extension_tracker_.reset(new AutomationExtensionTracker(this));
168  tab_tracker_.reset(new AutomationTabTracker(this));
169  window_tracker_.reset(new AutomationWindowTracker(this));
170  autocomplete_edit_tracker_.reset(
171      new AutomationAutocompleteEditTracker(this));
172  new_tab_ui_load_observer_.reset(new NewTabUILoadObserver(this));
173  dom_operation_observer_.reset(new DomOperationNotificationObserver(this));
174  metric_event_duration_observer_.reset(new MetricEventDurationObserver());
175  extension_test_result_observer_.reset(
176      new ExtensionTestResultNotificationObserver(this));
177  g_browser_process->AddRefModule();
178}
179
180AutomationProvider::~AutomationProvider() {
181  STLDeleteContainerPairSecondPointers(port_containers_.begin(),
182                                       port_containers_.end());
183  port_containers_.clear();
184
185  // Make sure that any outstanding NotificationObservers also get destroyed.
186  ObserverList<NotificationObserver>::Iterator it(notification_observer_list_);
187  NotificationObserver* observer;
188  while ((observer = it.GetNext()) != NULL)
189    delete observer;
190
191  if (channel_.get()) {
192    channel_->Close();
193  }
194  g_browser_process->ReleaseModule();
195}
196
197void AutomationProvider::ConnectToChannel(const std::string& channel_id) {
198  automation_resource_message_filter_ = new AutomationResourceMessageFilter;
199  channel_.reset(
200      new IPC::SyncChannel(channel_id, IPC::Channel::MODE_CLIENT, this,
201                           automation_resource_message_filter_,
202                           g_browser_process->io_thread()->message_loop(),
203                           true, g_browser_process->shutdown_event()));
204  scoped_ptr<FileVersionInfo> version_info(chrome::GetChromeVersionInfo());
205  std::string version_string;
206  if (version_info != NULL) {
207    version_string = WideToASCII(version_info->file_version());
208  }
209
210  // Send a hello message with our current automation protocol version.
211  channel_->Send(new AutomationMsg_Hello(0, version_string.c_str()));
212}
213
214void AutomationProvider::SetExpectedTabCount(size_t expected_tabs) {
215  if (expected_tabs == 0) {
216    Send(new AutomationMsg_InitialLoadsComplete(0));
217  } else {
218    initial_load_observer_.reset(new InitialLoadObserver(expected_tabs, this));
219  }
220}
221
222NotificationObserver* AutomationProvider::AddNavigationStatusListener(
223    NavigationController* tab, IPC::Message* reply_message,
224    int number_of_navigations, bool include_current_navigation) {
225  NotificationObserver* observer =
226      new NavigationNotificationObserver(tab, this, reply_message,
227                                         number_of_navigations,
228                                         include_current_navigation);
229
230  notification_observer_list_.AddObserver(observer);
231  return observer;
232}
233
234void AutomationProvider::RemoveNavigationStatusListener(
235    NotificationObserver* obs) {
236  notification_observer_list_.RemoveObserver(obs);
237}
238
239NotificationObserver* AutomationProvider::AddTabStripObserver(
240    Browser* parent,
241    IPC::Message* reply_message) {
242  NotificationObserver* observer =
243      new TabAppendedNotificationObserver(parent, this, reply_message);
244  notification_observer_list_.AddObserver(observer);
245
246  return observer;
247}
248
249void AutomationProvider::RemoveTabStripObserver(NotificationObserver* obs) {
250  notification_observer_list_.RemoveObserver(obs);
251}
252
253void AutomationProvider::AddLoginHandler(NavigationController* tab,
254                                         LoginHandler* handler) {
255  login_handler_map_[tab] = handler;
256}
257
258void AutomationProvider::RemoveLoginHandler(NavigationController* tab) {
259  DCHECK(login_handler_map_[tab]);
260  login_handler_map_.erase(tab);
261}
262
263void AutomationProvider::AddPortContainer(ExtensionPortContainer* port) {
264  int port_id = port->port_id();
265  DCHECK_NE(-1, port_id);
266  DCHECK(port_containers_.find(port_id) == port_containers_.end());
267
268  port_containers_[port_id] = port;
269}
270
271void AutomationProvider::RemovePortContainer(ExtensionPortContainer* port) {
272  int port_id = port->port_id();
273  DCHECK_NE(-1, port_id);
274
275  PortContainerMap::iterator it = port_containers_.find(port_id);
276  DCHECK(it != port_containers_.end());
277
278  if (it != port_containers_.end()) {
279    delete it->second;
280    port_containers_.erase(it);
281  }
282}
283
284ExtensionPortContainer* AutomationProvider::GetPortContainer(
285    int port_id) const {
286  PortContainerMap::const_iterator it = port_containers_.find(port_id);
287  if (it == port_containers_.end())
288    return NULL;
289
290  return it->second;
291}
292
293int AutomationProvider::GetIndexForNavigationController(
294    const NavigationController* controller, const Browser* parent) const {
295  DCHECK(parent);
296  return parent->GetIndexOfController(controller);
297}
298
299int AutomationProvider::AddExtension(Extension* extension) {
300  DCHECK(extension);
301  return extension_tracker_->Add(extension);
302}
303
304Extension* AutomationProvider::GetExtension(int extension_handle) {
305  return extension_tracker_->GetResource(extension_handle);
306}
307
308Extension* AutomationProvider::GetEnabledExtension(int extension_handle) {
309  Extension* extension = extension_tracker_->GetResource(extension_handle);
310  ExtensionsService* service = profile_->GetExtensionsService();
311  if (extension && service &&
312      service->GetExtensionById(extension->id(), false))
313    return extension;
314  return NULL;
315}
316
317Extension* AutomationProvider::GetDisabledExtension(int extension_handle) {
318  Extension* extension = extension_tracker_->GetResource(extension_handle);
319  ExtensionsService* service = profile_->GetExtensionsService();
320  if (extension && service &&
321      service->GetExtensionById(extension->id(), true) &&
322      !service->GetExtensionById(extension->id(), false))
323    return extension;
324  return NULL;
325}
326
327void AutomationProvider::OnMessageReceived(const IPC::Message& message) {
328  IPC_BEGIN_MESSAGE_MAP(AutomationProvider, message)
329    IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_CloseBrowser, CloseBrowser)
330    IPC_MESSAGE_HANDLER(AutomationMsg_CloseBrowserRequestAsync,
331                        CloseBrowserAsync)
332    IPC_MESSAGE_HANDLER(AutomationMsg_ActivateTab, ActivateTab)
333    IPC_MESSAGE_HANDLER(AutomationMsg_ActiveTabIndex, GetActiveTabIndex)
334    IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_AppendTab, AppendTab)
335    IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_CloseTab, CloseTab)
336    IPC_MESSAGE_HANDLER(AutomationMsg_GetCookies, GetCookies)
337    IPC_MESSAGE_HANDLER(AutomationMsg_SetCookie, SetCookie)
338    IPC_MESSAGE_HANDLER(AutomationMsg_DeleteCookie, DeleteCookie)
339    IPC_MESSAGE_HANDLER(AutomationMsg_ShowCollectedCookiesDialog,
340                        ShowCollectedCookiesDialog)
341    IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_NavigateToURL, NavigateToURL)
342    IPC_MESSAGE_HANDLER_DELAY_REPLY(
343        AutomationMsg_NavigateToURLBlockUntilNavigationsComplete,
344        NavigateToURLBlockUntilNavigationsComplete)
345    IPC_MESSAGE_HANDLER(AutomationMsg_NavigationAsync, NavigationAsync)
346    IPC_MESSAGE_HANDLER(AutomationMsg_NavigationAsyncWithDisposition,
347                        NavigationAsyncWithDisposition)
348    IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_GoBack, GoBack)
349    IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_GoForward, GoForward)
350    IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_Reload, Reload)
351    IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_SetAuth, SetAuth)
352    IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_CancelAuth, CancelAuth)
353    IPC_MESSAGE_HANDLER(AutomationMsg_NeedsAuth, NeedsAuth)
354    IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_RedirectsFrom,
355                                    GetRedirectsFrom)
356    IPC_MESSAGE_HANDLER(AutomationMsg_BrowserWindowCount, GetBrowserWindowCount)
357    IPC_MESSAGE_HANDLER(AutomationMsg_NormalBrowserWindowCount,
358                        GetNormalBrowserWindowCount)
359    IPC_MESSAGE_HANDLER(AutomationMsg_BrowserWindow, GetBrowserWindow)
360    IPC_MESSAGE_HANDLER(AutomationMsg_GetBrowserLocale, GetBrowserLocale)
361    IPC_MESSAGE_HANDLER(AutomationMsg_LastActiveBrowserWindow,
362                        GetLastActiveBrowserWindow)
363    IPC_MESSAGE_HANDLER(AutomationMsg_ActiveWindow, GetActiveWindow)
364    IPC_MESSAGE_HANDLER(AutomationMsg_FindNormalBrowserWindow,
365                        FindNormalBrowserWindow)
366    IPC_MESSAGE_HANDLER(AutomationMsg_IsWindowActive, IsWindowActive)
367    IPC_MESSAGE_HANDLER(AutomationMsg_ActivateWindow, ActivateWindow)
368    IPC_MESSAGE_HANDLER(AutomationMsg_IsWindowMaximized, IsWindowMaximized)
369    IPC_MESSAGE_HANDLER(AutomationMsg_WindowExecuteCommandAsync,
370                        ExecuteBrowserCommandAsync)
371    IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WindowExecuteCommand,
372                        ExecuteBrowserCommand)
373    IPC_MESSAGE_HANDLER(AutomationMsg_TerminateSession, TerminateSession)
374    IPC_MESSAGE_HANDLER(AutomationMsg_WindowViewBounds, WindowGetViewBounds)
375    IPC_MESSAGE_HANDLER(AutomationMsg_GetWindowBounds, GetWindowBounds)
376    IPC_MESSAGE_HANDLER(AutomationMsg_SetWindowBounds, SetWindowBounds)
377    IPC_MESSAGE_HANDLER(AutomationMsg_SetWindowVisible, SetWindowVisible)
378    IPC_MESSAGE_HANDLER(AutomationMsg_WindowClick, WindowSimulateClick)
379    IPC_MESSAGE_HANDLER(AutomationMsg_WindowMouseMove, WindowSimulateMouseMove)
380    IPC_MESSAGE_HANDLER(AutomationMsg_WindowKeyPress, WindowSimulateKeyPress)
381#if !defined(OS_MACOSX)
382    IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WindowDrag,
383                                    WindowSimulateDrag)
384#endif  // !defined(OS_MACOSX)
385    IPC_MESSAGE_HANDLER(AutomationMsg_TabCount, GetTabCount)
386    IPC_MESSAGE_HANDLER(AutomationMsg_Type, GetType)
387    IPC_MESSAGE_HANDLER(AutomationMsg_Tab, GetTab)
388#if defined(OS_WIN)
389    IPC_MESSAGE_HANDLER(AutomationMsg_TabHWND, GetTabHWND)
390#endif  // defined(OS_WIN)
391    IPC_MESSAGE_HANDLER(AutomationMsg_TabProcessID, GetTabProcessID)
392    IPC_MESSAGE_HANDLER(AutomationMsg_TabTitle, GetTabTitle)
393    IPC_MESSAGE_HANDLER(AutomationMsg_TabIndex, GetTabIndex)
394    IPC_MESSAGE_HANDLER(AutomationMsg_TabURL, GetTabURL)
395    IPC_MESSAGE_HANDLER(AutomationMsg_ShelfVisibility, GetShelfVisibility)
396    IPC_MESSAGE_HANDLER(AutomationMsg_IsFullscreen, IsFullscreen)
397    IPC_MESSAGE_HANDLER(AutomationMsg_IsFullscreenBubbleVisible,
398                        GetFullscreenBubbleVisibility)
399    IPC_MESSAGE_HANDLER(AutomationMsg_HandleUnused, HandleUnused)
400    IPC_MESSAGE_HANDLER(AutomationMsg_ApplyAccelerator, ApplyAccelerator)
401    IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_DomOperation,
402                                    ExecuteJavascript)
403    IPC_MESSAGE_HANDLER(AutomationMsg_ConstrainedWindowCount,
404                        GetConstrainedWindowCount)
405    IPC_MESSAGE_HANDLER(AutomationMsg_FindInPage, HandleFindInPageRequest)
406    IPC_MESSAGE_HANDLER(AutomationMsg_GetFocusedViewID, GetFocusedViewID)
407    IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_InspectElement,
408                                    HandleInspectElementRequest)
409    IPC_MESSAGE_HANDLER(AutomationMsg_DownloadDirectory, GetDownloadDirectory)
410    IPC_MESSAGE_HANDLER(AutomationMsg_SetProxyConfig, SetProxyConfig);
411    IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_OpenNewBrowserWindow,
412                                    OpenNewBrowserWindow)
413    IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_OpenNewBrowserWindowOfType,
414                                    OpenNewBrowserWindowOfType)
415    IPC_MESSAGE_HANDLER(AutomationMsg_WindowForBrowser, GetWindowForBrowser)
416    IPC_MESSAGE_HANDLER(AutomationMsg_AutocompleteEditForBrowser,
417                        GetAutocompleteEditForBrowser)
418    IPC_MESSAGE_HANDLER(AutomationMsg_BrowserForWindow, GetBrowserForWindow)
419    IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_ShowInterstitialPage,
420                                    ShowInterstitialPage)
421    IPC_MESSAGE_HANDLER(AutomationMsg_HideInterstitialPage,
422                        HideInterstitialPage)
423    IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WaitForTabToBeRestored,
424                                    WaitForTabToBeRestored)
425    IPC_MESSAGE_HANDLER(AutomationMsg_GetSecurityState, GetSecurityState)
426    IPC_MESSAGE_HANDLER(AutomationMsg_GetPageType, GetPageType)
427    IPC_MESSAGE_HANDLER(AutomationMsg_GetMetricEventDuration,
428                        GetMetricEventDuration)
429    IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_ActionOnSSLBlockingPage,
430                                    ActionOnSSLBlockingPage)
431    IPC_MESSAGE_HANDLER(AutomationMsg_BringBrowserToFront, BringBrowserToFront)
432    IPC_MESSAGE_HANDLER(AutomationMsg_IsMenuCommandEnabled,
433                        IsMenuCommandEnabled)
434    IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_PrintNow, PrintNow)
435    IPC_MESSAGE_HANDLER(AutomationMsg_PrintAsync, PrintAsync)
436    IPC_MESSAGE_HANDLER(AutomationMsg_SavePage, SavePage)
437    IPC_MESSAGE_HANDLER(AutomationMsg_AutocompleteEditGetText,
438                        GetAutocompleteEditText)
439    IPC_MESSAGE_HANDLER(AutomationMsg_AutocompleteEditSetText,
440                        SetAutocompleteEditText)
441    IPC_MESSAGE_HANDLER(AutomationMsg_AutocompleteEditIsQueryInProgress,
442                        AutocompleteEditIsQueryInProgress)
443    IPC_MESSAGE_HANDLER(AutomationMsg_AutocompleteEditGetMatches,
444                        AutocompleteEditGetMatches)
445    IPC_MESSAGE_HANDLER(AutomationMsg_OpenFindInPage,
446                        HandleOpenFindInPageRequest)
447    IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_Find, HandleFindRequest)
448    IPC_MESSAGE_HANDLER(AutomationMsg_FindWindowVisibility,
449                        GetFindWindowVisibility)
450    IPC_MESSAGE_HANDLER(AutomationMsg_FindWindowLocation,
451                        HandleFindWindowLocationRequest)
452    IPC_MESSAGE_HANDLER(AutomationMsg_BookmarkBarVisibility,
453                        GetBookmarkBarVisibility)
454    IPC_MESSAGE_HANDLER(AutomationMsg_GetBookmarksAsJSON,
455                        GetBookmarksAsJSON)
456    IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WaitForBookmarkModelToLoad,
457                                    WaitForBookmarkModelToLoad)
458    IPC_MESSAGE_HANDLER(AutomationMsg_AddBookmarkGroup,
459                        AddBookmarkGroup)
460    IPC_MESSAGE_HANDLER(AutomationMsg_AddBookmarkURL,
461                        AddBookmarkURL)
462    IPC_MESSAGE_HANDLER(AutomationMsg_ReparentBookmark,
463                        ReparentBookmark)
464    IPC_MESSAGE_HANDLER(AutomationMsg_SetBookmarkTitle,
465                        SetBookmarkTitle)
466    IPC_MESSAGE_HANDLER(AutomationMsg_SetBookmarkURL,
467                        SetBookmarkURL)
468    IPC_MESSAGE_HANDLER(AutomationMsg_RemoveBookmark,
469                        RemoveBookmark)
470    IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_SendJSONRequest,
471                                    SendJSONRequest)
472    IPC_MESSAGE_HANDLER(AutomationMsg_GetInfoBarCount, GetInfoBarCount)
473    IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_ClickInfoBarAccept,
474                                    ClickInfoBarAccept)
475    IPC_MESSAGE_HANDLER(AutomationMsg_GetLastNavigationTime,
476                        GetLastNavigationTime)
477    IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WaitForNavigation,
478                                    WaitForNavigation)
479    IPC_MESSAGE_HANDLER(AutomationMsg_SetIntPreference, SetIntPreference)
480    IPC_MESSAGE_HANDLER(AutomationMsg_ShowingAppModalDialog,
481                        GetShowingAppModalDialog)
482    IPC_MESSAGE_HANDLER(AutomationMsg_ClickAppModalDialogButton,
483                        ClickAppModalDialogButton)
484    IPC_MESSAGE_HANDLER(AutomationMsg_SetStringPreference, SetStringPreference)
485    IPC_MESSAGE_HANDLER(AutomationMsg_GetBooleanPreference,
486                        GetBooleanPreference)
487    IPC_MESSAGE_HANDLER(AutomationMsg_SetBooleanPreference,
488                        SetBooleanPreference)
489    IPC_MESSAGE_HANDLER(AutomationMsg_GetPageCurrentEncoding,
490                        GetPageCurrentEncoding)
491    IPC_MESSAGE_HANDLER(AutomationMsg_OverrideEncoding, OverrideEncoding)
492    IPC_MESSAGE_HANDLER(AutomationMsg_SavePackageShouldPromptUser,
493                        SavePackageShouldPromptUser)
494    IPC_MESSAGE_HANDLER(AutomationMsg_WindowTitle, GetWindowTitle)
495    IPC_MESSAGE_HANDLER(AutomationMsg_SetShelfVisibility, SetShelfVisibility)
496    IPC_MESSAGE_HANDLER(AutomationMsg_BlockedPopupCount, GetBlockedPopupCount)
497    IPC_MESSAGE_HANDLER(AutomationMsg_SelectAll, SelectAll)
498    IPC_MESSAGE_HANDLER(AutomationMsg_Cut, Cut)
499    IPC_MESSAGE_HANDLER(AutomationMsg_Copy, Copy)
500    IPC_MESSAGE_HANDLER(AutomationMsg_Paste, Paste)
501    IPC_MESSAGE_HANDLER(AutomationMsg_ReloadAsync, ReloadAsync)
502    IPC_MESSAGE_HANDLER(AutomationMsg_StopAsync, StopAsync)
503    IPC_MESSAGE_HANDLER_DELAY_REPLY(
504        AutomationMsg_WaitForBrowserWindowCountToBecome,
505        WaitForBrowserWindowCountToBecome)
506    IPC_MESSAGE_HANDLER_DELAY_REPLY(
507        AutomationMsg_WaitForAppModalDialogToBeShown,
508        WaitForAppModalDialogToBeShown)
509    IPC_MESSAGE_HANDLER_DELAY_REPLY(
510        AutomationMsg_GoBackBlockUntilNavigationsComplete,
511        GoBackBlockUntilNavigationsComplete)
512    IPC_MESSAGE_HANDLER_DELAY_REPLY(
513        AutomationMsg_GoForwardBlockUntilNavigationsComplete,
514        GoForwardBlockUntilNavigationsComplete)
515    IPC_MESSAGE_HANDLER(AutomationMsg_SetPageFontSize, OnSetPageFontSize)
516    IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_InstallExtension,
517                                    InstallExtension)
518    IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_LoadExpandedExtension,
519                                    LoadExpandedExtension)
520    IPC_MESSAGE_HANDLER(AutomationMsg_GetEnabledExtensions,
521                        GetEnabledExtensions)
522    IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WaitForExtensionTestResult,
523                                    WaitForExtensionTestResult)
524    IPC_MESSAGE_HANDLER_DELAY_REPLY(
525        AutomationMsg_InstallExtensionAndGetHandle,
526        InstallExtensionAndGetHandle)
527    IPC_MESSAGE_HANDLER(AutomationMsg_UninstallExtension,
528                        UninstallExtension)
529    IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_EnableExtension,
530                                    EnableExtension)
531    IPC_MESSAGE_HANDLER(AutomationMsg_DisableExtension,
532                        DisableExtension)
533    IPC_MESSAGE_HANDLER_DELAY_REPLY(
534        AutomationMsg_ExecuteExtensionActionInActiveTabAsync,
535        ExecuteExtensionActionInActiveTabAsync)
536    IPC_MESSAGE_HANDLER(AutomationMsg_MoveExtensionBrowserAction,
537                        MoveExtensionBrowserAction)
538    IPC_MESSAGE_HANDLER(AutomationMsg_GetExtensionProperty,
539                        GetExtensionProperty)
540    IPC_MESSAGE_HANDLER(AutomationMsg_ShutdownSessionService,
541                        ShutdownSessionService)
542    IPC_MESSAGE_HANDLER(AutomationMsg_SaveAsAsync, SaveAsAsync)
543    IPC_MESSAGE_HANDLER(AutomationMsg_SetContentSetting, SetContentSetting)
544    IPC_MESSAGE_HANDLER(AutomationMsg_RemoveBrowsingData, RemoveBrowsingData)
545    IPC_MESSAGE_HANDLER(AutomationMsg_ResetToDefaultTheme, ResetToDefaultTheme)
546#if defined(TOOLKIT_VIEWS)
547    IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WaitForFocusedViewIDToChange,
548                                    WaitForFocusedViewIDToChange)
549    IPC_MESSAGE_HANDLER(AutomationMsg_StartTrackingPopupMenus,
550                        StartTrackingPopupMenus)
551    IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WaitForPopupMenuToOpen,
552                                    WaitForPopupMenuToOpen)
553#endif  // defined(TOOLKIT_VIEWS)
554#if defined(OS_WIN)
555    // These are for use with external tabs.
556    IPC_MESSAGE_HANDLER(AutomationMsg_CreateExternalTab, CreateExternalTab)
557    IPC_MESSAGE_HANDLER(AutomationMsg_ProcessUnhandledAccelerator,
558                        ProcessUnhandledAccelerator)
559    IPC_MESSAGE_HANDLER(AutomationMsg_SetInitialFocus, SetInitialFocus)
560    IPC_MESSAGE_HANDLER(AutomationMsg_TabReposition, OnTabReposition)
561    IPC_MESSAGE_HANDLER(AutomationMsg_ForwardContextMenuCommandToChrome,
562                        OnForwardContextMenuCommandToChrome)
563    IPC_MESSAGE_HANDLER(AutomationMsg_NavigateInExternalTab,
564                        NavigateInExternalTab)
565    IPC_MESSAGE_HANDLER(AutomationMsg_NavigateExternalTabAtIndex,
566                        NavigateExternalTabAtIndex)
567    IPC_MESSAGE_HANDLER(AutomationMsg_ConnectExternalTab, ConnectExternalTab)
568    IPC_MESSAGE_HANDLER(AutomationMsg_SetEnableExtensionAutomation,
569                        SetEnableExtensionAutomation)
570    IPC_MESSAGE_HANDLER(AutomationMsg_HandleMessageFromExternalHost,
571                        OnMessageFromExternalHost)
572    IPC_MESSAGE_HANDLER(AutomationMsg_BrowserMove, OnBrowserMoved)
573    IPC_MESSAGE_HANDLER(AutomationMsg_RunUnloadHandlers, OnRunUnloadHandlers)
574#endif  // defined(OS_WIN)
575#if defined(OS_CHROMEOS)
576    IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_LoginWithUserAndPass,
577                                    LoginWithUserAndPass)
578#endif  // defined(OS_CHROMEOS)
579  IPC_END_MESSAGE_MAP()
580}
581
582void AutomationProvider::ActivateTab(int handle, int at_index, int* status) {
583  *status = -1;
584  if (browser_tracker_->ContainsHandle(handle) && at_index > -1) {
585    Browser* browser = browser_tracker_->GetResource(handle);
586    if (at_index >= 0 && at_index < browser->tab_count()) {
587      browser->SelectTabContentsAt(at_index, true);
588      *status = 0;
589    }
590  }
591}
592
593void AutomationProvider::AppendTab(int handle, const GURL& url,
594                                   IPC::Message* reply_message) {
595  int append_tab_response = -1;  // -1 is the error code
596  NotificationObserver* observer = NULL;
597
598  if (browser_tracker_->ContainsHandle(handle)) {
599    Browser* browser = browser_tracker_->GetResource(handle);
600    observer = AddTabStripObserver(browser, reply_message);
601    TabContents* tab_contents = browser->AddTabWithURL(
602        url, GURL(), PageTransition::TYPED, -1, TabStripModel::ADD_SELECTED,
603        NULL, std::string());
604    if (tab_contents) {
605      append_tab_response =
606          GetIndexForNavigationController(&tab_contents->controller(), browser);
607    }
608  }
609
610  if (append_tab_response < 0) {
611    // The append tab failed. Remove the TabStripObserver
612    if (observer) {
613      RemoveTabStripObserver(observer);
614      delete observer;
615    }
616
617    AutomationMsg_AppendTab::WriteReplyParams(reply_message,
618                                              append_tab_response);
619    Send(reply_message);
620  }
621}
622
623void AutomationProvider::NavigateToURL(int handle, const GURL& url,
624                                       IPC::Message* reply_message) {
625  NavigateToURLBlockUntilNavigationsComplete(handle, url, 1, reply_message);
626}
627
628void AutomationProvider::NavigateToURLBlockUntilNavigationsComplete(
629    int handle, const GURL& url, int number_of_navigations,
630    IPC::Message* reply_message) {
631  if (tab_tracker_->ContainsHandle(handle)) {
632    NavigationController* tab = tab_tracker_->GetResource(handle);
633
634    // Simulate what a user would do. Activate the tab and then navigate.
635    // We could allow navigating in a background tab in future.
636    Browser* browser = FindAndActivateTab(tab);
637
638    if (browser) {
639      AddNavigationStatusListener(tab, reply_message, number_of_navigations,
640                                  false);
641
642      // TODO(darin): avoid conversion to GURL
643      browser->OpenURL(url, GURL(), CURRENT_TAB, PageTransition::TYPED);
644      return;
645    }
646  }
647
648  AutomationMsg_NavigateToURL::WriteReplyParams(
649      reply_message, AUTOMATION_MSG_NAVIGATION_ERROR);
650  Send(reply_message);
651}
652
653void AutomationProvider::NavigationAsync(int handle,
654                                        const GURL& url,
655                                        bool* status) {
656  NavigationAsyncWithDisposition(handle, url, CURRENT_TAB, status);
657}
658
659void AutomationProvider::NavigationAsyncWithDisposition(
660    int handle,
661    const GURL& url,
662    WindowOpenDisposition disposition,
663    bool* status) {
664  *status = false;
665
666  if (tab_tracker_->ContainsHandle(handle)) {
667    NavigationController* tab = tab_tracker_->GetResource(handle);
668
669    // Simulate what a user would do. Activate the tab and then navigate.
670    // We could allow navigating in a background tab in future.
671    Browser* browser = FindAndActivateTab(tab);
672
673    if (browser) {
674      // Don't add any listener unless a callback mechanism is desired.
675      // TODO(vibhor): Do this if such a requirement arises in future.
676      browser->OpenURL(url, GURL(), disposition, PageTransition::TYPED);
677      *status = true;
678    }
679  }
680}
681
682void AutomationProvider::GoBack(int handle, IPC::Message* reply_message) {
683  if (tab_tracker_->ContainsHandle(handle)) {
684    NavigationController* tab = tab_tracker_->GetResource(handle);
685    Browser* browser = FindAndActivateTab(tab);
686    if (browser && browser->command_updater()->IsCommandEnabled(IDC_BACK)) {
687      AddNavigationStatusListener(tab, reply_message, 1, false);
688      browser->GoBack(CURRENT_TAB);
689      return;
690    }
691  }
692
693  AutomationMsg_GoBack::WriteReplyParams(
694      reply_message, AUTOMATION_MSG_NAVIGATION_ERROR);
695  Send(reply_message);
696}
697
698void AutomationProvider::GoForward(int handle, IPC::Message* reply_message) {
699  if (tab_tracker_->ContainsHandle(handle)) {
700    NavigationController* tab = tab_tracker_->GetResource(handle);
701    Browser* browser = FindAndActivateTab(tab);
702    if (browser && browser->command_updater()->IsCommandEnabled(IDC_FORWARD)) {
703      AddNavigationStatusListener(tab, reply_message, 1, false);
704      browser->GoForward(CURRENT_TAB);
705      return;
706    }
707  }
708
709  AutomationMsg_GoForward::WriteReplyParams(
710      reply_message, AUTOMATION_MSG_NAVIGATION_ERROR);
711  Send(reply_message);
712}
713
714void AutomationProvider::Reload(int handle, IPC::Message* reply_message) {
715  if (tab_tracker_->ContainsHandle(handle)) {
716    NavigationController* tab = tab_tracker_->GetResource(handle);
717    Browser* browser = FindAndActivateTab(tab);
718    if (browser && browser->command_updater()->IsCommandEnabled(IDC_RELOAD)) {
719      AddNavigationStatusListener(tab, reply_message, 1, false);
720      browser->Reload(CURRENT_TAB);
721      return;
722    }
723  }
724
725  AutomationMsg_Reload::WriteReplyParams(
726      reply_message, AUTOMATION_MSG_NAVIGATION_ERROR);
727  Send(reply_message);
728}
729
730void AutomationProvider::SetAuth(int tab_handle,
731                                 const std::wstring& username,
732                                 const std::wstring& password,
733                                 IPC::Message* reply_message) {
734  if (tab_tracker_->ContainsHandle(tab_handle)) {
735    NavigationController* tab = tab_tracker_->GetResource(tab_handle);
736    LoginHandlerMap::iterator iter = login_handler_map_.find(tab);
737
738    if (iter != login_handler_map_.end()) {
739      // If auth is needed again after this, assume login has failed.  This is
740      // not strictly correct, because a navigation can require both proxy and
741      // server auth, but it should be OK for now.
742      LoginHandler* handler = iter->second;
743      AddNavigationStatusListener(tab, reply_message, 1, false);
744      handler->SetAuth(username, password);
745      return;
746    }
747  }
748
749  AutomationMsg_SetAuth::WriteReplyParams(
750      reply_message, AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED);
751  Send(reply_message);
752}
753
754void AutomationProvider::CancelAuth(int tab_handle,
755                                    IPC::Message* reply_message) {
756  if (tab_tracker_->ContainsHandle(tab_handle)) {
757    NavigationController* tab = tab_tracker_->GetResource(tab_handle);
758    LoginHandlerMap::iterator iter = login_handler_map_.find(tab);
759
760    if (iter != login_handler_map_.end()) {
761      // If auth is needed again after this, something is screwy.
762      LoginHandler* handler = iter->second;
763      AddNavigationStatusListener(tab, reply_message, 1, false);
764      handler->CancelAuth();
765      return;
766    }
767  }
768
769  AutomationMsg_CancelAuth::WriteReplyParams(
770      reply_message, AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED);
771  Send(reply_message);
772}
773
774void AutomationProvider::NeedsAuth(int tab_handle, bool* needs_auth) {
775  *needs_auth = false;
776
777  if (tab_tracker_->ContainsHandle(tab_handle)) {
778    NavigationController* tab = tab_tracker_->GetResource(tab_handle);
779    LoginHandlerMap::iterator iter = login_handler_map_.find(tab);
780
781    if (iter != login_handler_map_.end()) {
782      // The LoginHandler will be in our map IFF the tab needs auth.
783      *needs_auth = true;
784    }
785  }
786}
787
788void AutomationProvider::GetRedirectsFrom(int tab_handle,
789                                          const GURL& source_url,
790                                          IPC::Message* reply_message) {
791  DCHECK(!redirect_query_) << "Can only handle one redirect query at once.";
792  if (tab_tracker_->ContainsHandle(tab_handle)) {
793    NavigationController* tab = tab_tracker_->GetResource(tab_handle);
794    HistoryService* history_service =
795        tab->profile()->GetHistoryService(Profile::EXPLICIT_ACCESS);
796
797    DCHECK(history_service) << "Tab " << tab_handle << "'s profile " <<
798                               "has no history service";
799    if (history_service) {
800      DCHECK(reply_message_ == NULL);
801      reply_message_ = reply_message;
802      // Schedule a history query for redirects. The response will be sent
803      // asynchronously from the callback the history system uses to notify us
804      // that it's done: OnRedirectQueryComplete.
805      redirect_query_ = history_service->QueryRedirectsFrom(
806          source_url, &consumer_,
807          NewCallback(this, &AutomationProvider::OnRedirectQueryComplete));
808      return;  // Response will be sent when query completes.
809    }
810  }
811
812  // Send failure response.
813  std::vector<GURL> empty;
814  AutomationMsg_RedirectsFrom::WriteReplyParams(reply_message, false, empty);
815  Send(reply_message);
816}
817
818void AutomationProvider::GetActiveTabIndex(int handle, int* active_tab_index) {
819  *active_tab_index = -1;  // -1 is the error code
820  if (browser_tracker_->ContainsHandle(handle)) {
821    Browser* browser = browser_tracker_->GetResource(handle);
822    *active_tab_index = browser->selected_index();
823  }
824}
825
826void AutomationProvider::GetBrowserLocale(string16* locale) {
827  DCHECK(g_browser_process);
828  *locale = ASCIIToUTF16(g_browser_process->GetApplicationLocale());
829}
830
831void AutomationProvider::GetBrowserWindowCount(int* window_count) {
832  *window_count = static_cast<int>(BrowserList::size());
833}
834
835void AutomationProvider::GetNormalBrowserWindowCount(int* window_count) {
836  *window_count = static_cast<int>(
837      BrowserList::GetBrowserCountForType(profile_, Browser::TYPE_NORMAL));
838}
839
840void AutomationProvider::GetShowingAppModalDialog(bool* showing_dialog,
841                                                  int* dialog_button) {
842  AppModalDialog* dialog_delegate =
843      Singleton<AppModalDialogQueue>()->active_dialog();
844  *showing_dialog = (dialog_delegate != NULL);
845  if (*showing_dialog)
846    *dialog_button = dialog_delegate->GetDialogButtons();
847  else
848    *dialog_button = MessageBoxFlags::DIALOGBUTTON_NONE;
849}
850
851void AutomationProvider::ClickAppModalDialogButton(int button, bool* success) {
852  *success = false;
853
854  AppModalDialog* dialog_delegate =
855      Singleton<AppModalDialogQueue>()->active_dialog();
856  if (dialog_delegate &&
857      (dialog_delegate->GetDialogButtons() & button) == button) {
858    if ((button & MessageBoxFlags::DIALOGBUTTON_OK) ==
859        MessageBoxFlags::DIALOGBUTTON_OK) {
860      dialog_delegate->AcceptWindow();
861      *success =  true;
862    }
863    if ((button & MessageBoxFlags::DIALOGBUTTON_CANCEL) ==
864        MessageBoxFlags::DIALOGBUTTON_CANCEL) {
865      DCHECK(!*success) << "invalid param, OK and CANCEL specified";
866      dialog_delegate->CancelWindow();
867      *success =  true;
868    }
869  }
870}
871
872void AutomationProvider::ShutdownSessionService(int handle, bool* result) {
873  if (browser_tracker_->ContainsHandle(handle)) {
874    Browser* browser = browser_tracker_->GetResource(handle);
875    browser->profile()->ShutdownSessionService();
876    *result = true;
877  } else {
878    *result = false;
879  }
880}
881
882void AutomationProvider::GetBrowserWindow(int index, int* handle) {
883  *handle = 0;
884  if (index >= 0) {
885    BrowserList::const_iterator iter = BrowserList::begin();
886    for (; (iter != BrowserList::end()) && (index > 0); ++iter, --index) {}
887    if (iter != BrowserList::end()) {
888      *handle = browser_tracker_->Add(*iter);
889    }
890  }
891}
892
893void AutomationProvider::FindNormalBrowserWindow(int* handle) {
894  *handle = 0;
895  Browser* browser = BrowserList::FindBrowserWithType(profile_,
896                                                      Browser::TYPE_NORMAL,
897                                                      false);
898  if (browser)
899    *handle = browser_tracker_->Add(browser);
900}
901
902void AutomationProvider::GetLastActiveBrowserWindow(int* handle) {
903  *handle = 0;
904  Browser* browser = BrowserList::GetLastActive();
905  if (browser)
906    *handle = browser_tracker_->Add(browser);
907}
908
909#if defined(OS_POSIX)
910// TODO(estade): use this implementation for all platforms?
911void AutomationProvider::GetActiveWindow(int* handle) {
912  gfx::NativeWindow window =
913      BrowserList::GetLastActive()->window()->GetNativeHandle();
914  *handle = window_tracker_->Add(window);
915}
916#endif
917
918void AutomationProvider::ExecuteBrowserCommandAsync(int handle, int command,
919                                                    bool* success) {
920  *success = false;
921  if (browser_tracker_->ContainsHandle(handle)) {
922    Browser* browser = browser_tracker_->GetResource(handle);
923    if (browser->command_updater()->SupportsCommand(command) &&
924        browser->command_updater()->IsCommandEnabled(command)) {
925      browser->ExecuteCommand(command);
926      *success = true;
927    }
928  }
929}
930
931void AutomationProvider::ExecuteBrowserCommand(
932    int handle, int command, IPC::Message* reply_message) {
933  // List of commands which just finish synchronously and don't require
934  // setting up an observer.
935  static const int kSynchronousCommands[] = {
936    IDC_HOME,
937    IDC_SELECT_NEXT_TAB,
938    IDC_SELECT_PREVIOUS_TAB,
939    IDC_SHOW_BOOKMARK_MANAGER,
940  };
941  if (browser_tracker_->ContainsHandle(handle)) {
942    Browser* browser = browser_tracker_->GetResource(handle);
943    if (browser->command_updater()->SupportsCommand(command) &&
944        browser->command_updater()->IsCommandEnabled(command)) {
945      // First check if we can handle the command without using an observer.
946      for (size_t i = 0; i < arraysize(kSynchronousCommands); i++) {
947        if (command == kSynchronousCommands[i]) {
948          browser->ExecuteCommand(command);
949          AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message,
950                                                               true);
951          Send(reply_message);
952          return;
953        }
954      }
955
956      // Use an observer if we have one, otherwise fail.
957      if (ExecuteBrowserCommandObserver::CreateAndRegisterObserver(
958          this, browser, command, reply_message)) {
959        browser->ExecuteCommand(command);
960        return;
961      }
962    }
963  }
964  AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message, false);
965  Send(reply_message);
966}
967
968// This task just adds another task to the event queue.  This is useful if
969// you want to ensure that any tasks added to the event queue after this one
970// have already been processed by the time |task| is run.
971class InvokeTaskLaterTask : public Task {
972 public:
973  explicit InvokeTaskLaterTask(Task* task) : task_(task) {}
974  virtual ~InvokeTaskLaterTask() {}
975
976  virtual void Run() {
977    MessageLoop::current()->PostTask(FROM_HERE, task_);
978  }
979
980 private:
981  Task* task_;
982
983  DISALLOW_COPY_AND_ASSIGN(InvokeTaskLaterTask);
984};
985
986void AutomationProvider::WindowSimulateClick(const IPC::Message& message,
987                                             int handle,
988                                             const gfx::Point& click,
989                                             int flags) {
990  if (window_tracker_->ContainsHandle(handle)) {
991    ui_controls::SendMouseMoveNotifyWhenDone(click.x(), click.y(),
992                                             new ClickTask(flags));
993  }
994}
995
996void AutomationProvider::WindowSimulateMouseMove(const IPC::Message& message,
997                                                 int handle,
998                                                 const gfx::Point& location) {
999  if (window_tracker_->ContainsHandle(handle))
1000    ui_controls::SendMouseMove(location.x(), location.y());
1001}
1002
1003void AutomationProvider::WindowSimulateKeyPress(const IPC::Message& message,
1004                                                int handle,
1005                                                int key,
1006                                                int flags) {
1007  if (!window_tracker_->ContainsHandle(handle))
1008    return;
1009
1010  gfx::NativeWindow window = window_tracker_->GetResource(handle);
1011  // The key event is sent to whatever window is active.
1012  ui_controls::SendKeyPress(window, static_cast<base::KeyboardCode>(key),
1013                           ((flags & views::Event::EF_CONTROL_DOWN) ==
1014                              views::Event::EF_CONTROL_DOWN),
1015                            ((flags & views::Event::EF_SHIFT_DOWN) ==
1016                              views::Event::EF_SHIFT_DOWN),
1017                            ((flags & views::Event::EF_ALT_DOWN) ==
1018                              views::Event::EF_ALT_DOWN),
1019                            ((flags & views::Event::EF_COMMAND_DOWN) ==
1020                              views::Event::EF_COMMAND_DOWN));
1021}
1022
1023void AutomationProvider::IsWindowActive(int handle, bool* success,
1024                                        bool* is_active) {
1025  if (window_tracker_->ContainsHandle(handle)) {
1026    *is_active =
1027        platform_util::IsWindowActive(window_tracker_->GetResource(handle));
1028    *success = true;
1029  } else {
1030    *success = false;
1031    *is_active = false;
1032  }
1033}
1034
1035void AutomationProvider::GetTabCount(int handle, int* tab_count) {
1036  *tab_count = -1;  // -1 is the error code
1037
1038  if (browser_tracker_->ContainsHandle(handle)) {
1039    Browser* browser = browser_tracker_->GetResource(handle);
1040    *tab_count = browser->tab_count();
1041  }
1042}
1043
1044void AutomationProvider::GetType(int handle, int* type_as_int) {
1045  *type_as_int = -1;  // -1 is the error code
1046
1047  if (browser_tracker_->ContainsHandle(handle)) {
1048    Browser* browser = browser_tracker_->GetResource(handle);
1049    *type_as_int = static_cast<int>(browser->type());
1050  }
1051}
1052
1053void AutomationProvider::GetTab(int win_handle, int tab_index,
1054                                int* tab_handle) {
1055  *tab_handle = 0;
1056  if (browser_tracker_->ContainsHandle(win_handle) && (tab_index >= 0)) {
1057    Browser* browser = browser_tracker_->GetResource(win_handle);
1058    if (tab_index < browser->tab_count()) {
1059      TabContents* tab_contents =
1060          browser->GetTabContentsAt(tab_index);
1061      *tab_handle = tab_tracker_->Add(&tab_contents->controller());
1062    }
1063  }
1064}
1065
1066void AutomationProvider::GetTabTitle(int handle, int* title_string_size,
1067                                     std::wstring* title) {
1068  *title_string_size = -1;  // -1 is the error code
1069  if (tab_tracker_->ContainsHandle(handle)) {
1070    NavigationController* tab = tab_tracker_->GetResource(handle);
1071    NavigationEntry* entry = tab->GetActiveEntry();
1072    if (entry != NULL) {
1073      *title = UTF16ToWideHack(entry->title());
1074    } else {
1075      *title = std::wstring();
1076    }
1077    *title_string_size = static_cast<int>(title->size());
1078  }
1079}
1080
1081void AutomationProvider::GetTabIndex(int handle, int* tabstrip_index) {
1082  *tabstrip_index = -1;  // -1 is the error code
1083
1084  if (tab_tracker_->ContainsHandle(handle)) {
1085    NavigationController* tab = tab_tracker_->GetResource(handle);
1086    Browser* browser = Browser::GetBrowserForController(tab, NULL);
1087    *tabstrip_index = browser->tabstrip_model()->GetIndexOfController(tab);
1088  }
1089}
1090
1091void AutomationProvider::HandleUnused(const IPC::Message& message, int handle) {
1092  if (window_tracker_->ContainsHandle(handle)) {
1093    window_tracker_->Remove(window_tracker_->GetResource(handle));
1094  }
1095}
1096
1097void AutomationProvider::OnChannelError() {
1098  LOG(INFO) << "AutomationProxy went away, shutting down app.";
1099  AutomationProviderList::GetInstance()->RemoveProvider(this);
1100}
1101
1102// TODO(brettw) change this to accept GURLs when history supports it
1103void AutomationProvider::OnRedirectQueryComplete(
1104    HistoryService::Handle request_handle,
1105    GURL from_url,
1106    bool success,
1107    history::RedirectList* redirects) {
1108  DCHECK(request_handle == redirect_query_);
1109  DCHECK(reply_message_ != NULL);
1110
1111  std::vector<GURL> redirects_gurl;
1112  reply_message_->WriteBool(success);
1113  if (success) {
1114    for (size_t i = 0; i < redirects->size(); i++)
1115      redirects_gurl.push_back(redirects->at(i));
1116  }
1117
1118  IPC::ParamTraits<std::vector<GURL> >::Write(reply_message_, redirects_gurl);
1119
1120  Send(reply_message_);
1121  redirect_query_ = 0;
1122  reply_message_ = NULL;
1123}
1124
1125bool AutomationProvider::Send(IPC::Message* msg) {
1126  DCHECK(channel_.get());
1127  return channel_->Send(msg);
1128}
1129
1130Browser* AutomationProvider::FindAndActivateTab(
1131    NavigationController* controller) {
1132  int tab_index;
1133  Browser* browser = Browser::GetBrowserForController(controller, &tab_index);
1134  if (browser)
1135    browser->SelectTabContentsAt(tab_index, true);
1136
1137  return browser;
1138}
1139
1140namespace {
1141
1142class GetCookiesTask : public Task {
1143 public:
1144  GetCookiesTask(const GURL& url,
1145                 URLRequestContextGetter* context_getter,
1146                 base::WaitableEvent* event,
1147                 std::string* cookies)
1148      : url_(url),
1149        context_getter_(context_getter),
1150        event_(event),
1151        cookies_(cookies) {}
1152
1153  virtual void Run() {
1154    *cookies_ = context_getter_->GetCookieStore()->GetCookies(url_);
1155    event_->Signal();
1156  }
1157
1158 private:
1159  const GURL& url_;
1160  URLRequestContextGetter* const context_getter_;
1161  base::WaitableEvent* const event_;
1162  std::string* const cookies_;
1163
1164  DISALLOW_COPY_AND_ASSIGN(GetCookiesTask);
1165};
1166
1167std::string GetCookiesForURL(
1168    const GURL& url,
1169    URLRequestContextGetter* context_getter) {
1170  std::string cookies;
1171  base::WaitableEvent event(true /* manual reset */,
1172                            false /* not initially signaled */);
1173  CHECK(ChromeThread::PostTask(
1174      ChromeThread::IO, FROM_HERE,
1175      new GetCookiesTask(url, context_getter, &event, &cookies)));
1176  event.Wait();
1177  return cookies;
1178}
1179
1180class SetCookieTask : public Task {
1181 public:
1182  SetCookieTask(const GURL& url,
1183                const std::string& value,
1184                URLRequestContextGetter* context_getter,
1185                base::WaitableEvent* event,
1186                bool* rv)
1187      : url_(url),
1188        value_(value),
1189        context_getter_(context_getter),
1190        event_(event),
1191        rv_(rv) {}
1192
1193  virtual void Run() {
1194    *rv_ = context_getter_->GetCookieStore()->SetCookie(url_, value_);
1195    event_->Signal();
1196  }
1197
1198 private:
1199  const GURL& url_;
1200  const std::string& value_;
1201  URLRequestContextGetter* const context_getter_;
1202  base::WaitableEvent* const event_;
1203  bool* const rv_;
1204
1205  DISALLOW_COPY_AND_ASSIGN(SetCookieTask);
1206};
1207
1208bool SetCookieForURL(
1209    const GURL& url,
1210    const std::string& value,
1211    URLRequestContextGetter* context_getter) {
1212  base::WaitableEvent event(true /* manual reset */,
1213                            false /* not initially signaled */);
1214  bool rv = false;
1215  CHECK(ChromeThread::PostTask(
1216      ChromeThread::IO, FROM_HERE,
1217      new SetCookieTask(url, value, context_getter, &event, &rv)));
1218  event.Wait();
1219  return rv;
1220}
1221
1222class DeleteCookieTask : public Task {
1223 public:
1224  DeleteCookieTask(const GURL& url,
1225                   const std::string& name,
1226                   const scoped_refptr<URLRequestContextGetter>& context_getter)
1227      : url_(url),
1228        name_(name),
1229        context_getter_(context_getter) {}
1230
1231  virtual void Run() {
1232    net::CookieStore* cookie_store = context_getter_->GetCookieStore();
1233    cookie_store->DeleteCookie(url_, name_);
1234  }
1235
1236 private:
1237  const GURL url_;
1238  const std::string name_;
1239  const scoped_refptr<URLRequestContextGetter> context_getter_;
1240
1241  DISALLOW_COPY_AND_ASSIGN(DeleteCookieTask);
1242};
1243
1244}  // namespace
1245
1246void AutomationProvider::GetCookies(const GURL& url, int handle,
1247                                    int* value_size,
1248                                    std::string* value) {
1249  *value_size = -1;
1250  if (url.is_valid() && tab_tracker_->ContainsHandle(handle)) {
1251    NavigationController* tab = tab_tracker_->GetResource(handle);
1252
1253    // Since we are running on the UI thread don't call GetURLRequestContext().
1254    scoped_refptr<URLRequestContextGetter> request_context =
1255        tab->tab_contents()->request_context();
1256    if (!request_context.get())
1257      request_context = tab->profile()->GetRequestContext();
1258
1259    *value = GetCookiesForURL(url, request_context.get());
1260    *value_size = static_cast<int>(value->size());
1261  }
1262}
1263
1264void AutomationProvider::SetCookie(const GURL& url,
1265                                   const std::string value,
1266                                   int handle,
1267                                   int* response_value) {
1268  *response_value = -1;
1269
1270  if (url.is_valid() && tab_tracker_->ContainsHandle(handle)) {
1271    NavigationController* tab = tab_tracker_->GetResource(handle);
1272
1273    scoped_refptr<URLRequestContextGetter> request_context =
1274        tab->tab_contents()->request_context();
1275    if (!request_context.get())
1276      request_context = tab->profile()->GetRequestContext();
1277
1278    if (SetCookieForURL(url, value, request_context.get()))
1279      *response_value = 1;
1280  }
1281}
1282
1283void AutomationProvider::DeleteCookie(const GURL& url,
1284                                      const std::string& cookie_name,
1285                                      int handle, bool* success) {
1286  *success = false;
1287  if (url.is_valid() && tab_tracker_->ContainsHandle(handle)) {
1288    NavigationController* tab = tab_tracker_->GetResource(handle);
1289    ChromeThread::PostTask(
1290        ChromeThread::IO, FROM_HERE,
1291        new DeleteCookieTask(url, cookie_name,
1292                             tab->profile()->GetRequestContext()));
1293    *success = true;
1294  }
1295}
1296
1297void AutomationProvider::ShowCollectedCookiesDialog(
1298    int handle, bool* success) {
1299  *success = false;
1300  if (tab_tracker_->ContainsHandle(handle)) {
1301    TabContents* tab_contents =
1302        tab_tracker_->GetResource(handle)->tab_contents();
1303    tab_contents->delegate()->ShowCollectedCookiesDialog(tab_contents);
1304    *success = true;
1305  }
1306}
1307
1308void AutomationProvider::GetTabURL(int handle, bool* success, GURL* url) {
1309  *success = false;
1310  if (tab_tracker_->ContainsHandle(handle)) {
1311    NavigationController* tab = tab_tracker_->GetResource(handle);
1312    // Return what the user would see in the location bar.
1313    *url = tab->GetActiveEntry()->virtual_url();
1314    *success = true;
1315  }
1316}
1317
1318void AutomationProvider::GetTabProcessID(int handle, int* process_id) {
1319  *process_id = -1;
1320
1321  if (tab_tracker_->ContainsHandle(handle)) {
1322    *process_id = 0;
1323    TabContents* tab_contents =
1324        tab_tracker_->GetResource(handle)->tab_contents();
1325    RenderProcessHost* rph = tab_contents->GetRenderProcessHost();
1326    if (rph)
1327      *process_id = base::GetProcId(rph->GetHandle());
1328  }
1329}
1330
1331void AutomationProvider::ApplyAccelerator(int handle, int id) {
1332  NOTREACHED() << "This function has been deprecated. "
1333               << "Please use ExecuteBrowserCommandAsync instead.";
1334}
1335
1336void AutomationProvider::ExecuteJavascript(int handle,
1337                                           const std::wstring& frame_xpath,
1338                                           const std::wstring& script,
1339                                           IPC::Message* reply_message) {
1340  bool succeeded = false;
1341  TabContents* tab_contents = GetTabContentsForHandle(handle, NULL);
1342  if (tab_contents) {
1343    // Set the routing id of this message with the controller.
1344    // This routing id needs to be remembered for the reverse
1345    // communication while sending back the response of
1346    // this javascript execution.
1347    std::wstring set_automation_id;
1348    SStringPrintf(&set_automation_id,
1349      L"window.domAutomationController.setAutomationId(%d);",
1350      reply_message->routing_id());
1351
1352    DCHECK(reply_message_ == NULL);
1353    reply_message_ = reply_message;
1354
1355    tab_contents->render_view_host()->ExecuteJavascriptInWebFrame(
1356        frame_xpath, set_automation_id);
1357    tab_contents->render_view_host()->ExecuteJavascriptInWebFrame(
1358        frame_xpath, script);
1359    succeeded = true;
1360  }
1361
1362  if (!succeeded) {
1363    AutomationMsg_DomOperation::WriteReplyParams(reply_message, std::string());
1364    Send(reply_message);
1365  }
1366}
1367
1368void AutomationProvider::GetShelfVisibility(int handle, bool* visible) {
1369  *visible = false;
1370
1371  if (browser_tracker_->ContainsHandle(handle)) {
1372#if defined(OS_CHROMEOS)
1373    // Chromium OS shows FileBrowse ui rather than download shelf. So we
1374    // enumerate all browsers and look for a chrome://filebrowse... pop up.
1375    for (BrowserList::const_iterator it = BrowserList::begin();
1376         it != BrowserList::end(); ++it) {
1377      if ((*it)->type() == Browser::TYPE_POPUP) {
1378        const GURL& url =
1379            (*it)->GetTabContentsAt((*it)->selected_index())->GetURL();
1380
1381        if (url.SchemeIs(chrome::kChromeUIScheme) &&
1382            url.host() == chrome::kChromeUIFileBrowseHost) {
1383          *visible = true;
1384          break;
1385        }
1386      }
1387    }
1388#else
1389    Browser* browser = browser_tracker_->GetResource(handle);
1390    if (browser) {
1391      *visible = browser->window()->IsDownloadShelfVisible();
1392    }
1393#endif
1394  }
1395}
1396
1397void AutomationProvider::SetShelfVisibility(int handle, bool visible) {
1398  if (browser_tracker_->ContainsHandle(handle)) {
1399    Browser* browser = browser_tracker_->GetResource(handle);
1400    if (browser) {
1401      if (visible)
1402        browser->window()->GetDownloadShelf()->Show();
1403      else
1404        browser->window()->GetDownloadShelf()->Close();
1405    }
1406  }
1407}
1408
1409void AutomationProvider::IsFullscreen(int handle, bool* visible) {
1410  *visible = false;
1411
1412  if (browser_tracker_->ContainsHandle(handle)) {
1413    Browser* browser = browser_tracker_->GetResource(handle);
1414    if (browser)
1415      *visible = browser->window()->IsFullscreen();
1416  }
1417}
1418
1419void AutomationProvider::GetFullscreenBubbleVisibility(int handle,
1420                                                       bool* visible) {
1421  *visible = false;
1422
1423  if (browser_tracker_->ContainsHandle(handle)) {
1424    Browser* browser = browser_tracker_->GetResource(handle);
1425    if (browser)
1426      *visible = browser->window()->IsFullscreenBubbleVisible();
1427  }
1428}
1429
1430void AutomationProvider::GetConstrainedWindowCount(int handle, int* count) {
1431  *count = -1;  // -1 is the error code
1432  if (tab_tracker_->ContainsHandle(handle)) {
1433      NavigationController* nav_controller = tab_tracker_->GetResource(handle);
1434      TabContents* tab_contents = nav_controller->tab_contents();
1435      if (tab_contents) {
1436        *count = static_cast<int>(tab_contents->child_windows_.size());
1437      }
1438  }
1439}
1440
1441void AutomationProvider::HandleFindInPageRequest(
1442    int handle, const std::wstring& find_request,
1443    int forward, int match_case, int* active_ordinal, int* matches_found) {
1444  NOTREACHED() << "This function has been deprecated."
1445    << "Please use HandleFindRequest instead.";
1446  *matches_found = -1;
1447  return;
1448}
1449
1450void AutomationProvider::HandleFindRequest(
1451    int handle,
1452    const AutomationMsg_Find_Params& params,
1453    IPC::Message* reply_message) {
1454  if (!tab_tracker_->ContainsHandle(handle)) {
1455    AutomationMsg_FindInPage::WriteReplyParams(reply_message, -1, -1);
1456    Send(reply_message);
1457    return;
1458  }
1459
1460  NavigationController* nav = tab_tracker_->GetResource(handle);
1461  TabContents* tab_contents = nav->tab_contents();
1462
1463  find_in_page_observer_.reset(new
1464      FindInPageNotificationObserver(this, tab_contents, reply_message));
1465
1466  tab_contents->set_current_find_request_id(
1467      FindInPageNotificationObserver::kFindInPageRequestId);
1468  tab_contents->render_view_host()->StartFinding(
1469      FindInPageNotificationObserver::kFindInPageRequestId,
1470      params.search_string, params.forward, params.match_case,
1471      params.find_next);
1472}
1473
1474void AutomationProvider::HandleOpenFindInPageRequest(
1475    const IPC::Message& message, int handle) {
1476  if (browser_tracker_->ContainsHandle(handle)) {
1477    Browser* browser = browser_tracker_->GetResource(handle);
1478    browser->FindInPage(false, false);
1479  }
1480}
1481
1482void AutomationProvider::GetFindWindowVisibility(int handle, bool* visible) {
1483  *visible = false;
1484  Browser* browser = browser_tracker_->GetResource(handle);
1485  if (browser) {
1486    FindBarTesting* find_bar =
1487        browser->GetFindBarController()->find_bar()->GetFindBarTesting();
1488    find_bar->GetFindBarWindowInfo(NULL, visible);
1489  }
1490}
1491
1492void AutomationProvider::HandleFindWindowLocationRequest(int handle, int* x,
1493                                                         int* y) {
1494  gfx::Point position(0, 0);
1495  bool visible = false;
1496  if (browser_tracker_->ContainsHandle(handle)) {
1497     Browser* browser = browser_tracker_->GetResource(handle);
1498     FindBarTesting* find_bar =
1499       browser->GetFindBarController()->find_bar()->GetFindBarTesting();
1500     find_bar->GetFindBarWindowInfo(&position, &visible);
1501  }
1502
1503  *x = position.x();
1504  *y = position.y();
1505}
1506
1507// Bookmark bar visibility is based on the pref (e.g. is it in the toolbar).
1508// Presence in the NTP is NOT considered visible by this call.
1509void AutomationProvider::GetBookmarkBarVisibility(int handle,
1510                                                  bool* visible,
1511                                                  bool* animating) {
1512  *visible = false;
1513  *animating = false;
1514
1515  if (browser_tracker_->ContainsHandle(handle)) {
1516    Browser* browser = browser_tracker_->GetResource(handle);
1517    if (browser) {
1518#if 0  // defined(TOOLKIT_VIEWS) && defined(OS_LINUX)
1519      // TODO(jrg): Was removed in rev43789 for perf. Need to investigate.
1520
1521      // IsBookmarkBarVisible() line looks correct but is not
1522      // consistent across platforms.  Specifically, on Mac/Linux, it
1523      // returns false if the bar is hidden in a pref (even if visible
1524      // on the NTP).  On ChromeOS, it returned true if on NTP
1525      // independent of the pref.  Making the code more consistent
1526      // caused a perf bot regression on Windows (which shares views).
1527      // See http://crbug.com/40225
1528      *visible = browser->profile()->GetPrefs()->GetBoolean(
1529          prefs::kShowBookmarkBar);
1530#else
1531      *visible = browser->window()->IsBookmarkBarVisible();
1532#endif
1533      *animating = browser->window()->IsBookmarkBarAnimating();
1534    }
1535  }
1536}
1537
1538void AutomationProvider::GetBookmarksAsJSON(int handle,
1539                                            std::string* bookmarks_as_json,
1540                                            bool *success) {
1541  *success = false;
1542  if (browser_tracker_->ContainsHandle(handle)) {
1543    Browser* browser = browser_tracker_->GetResource(handle);
1544    if (browser) {
1545      if (!browser->profile()->GetBookmarkModel()->IsLoaded()) {
1546        return;
1547      }
1548      scoped_refptr<BookmarkStorage> storage = new BookmarkStorage(
1549          browser->profile(),
1550          browser->profile()->GetBookmarkModel());
1551      *success = storage->SerializeData(bookmarks_as_json);
1552    }
1553  }
1554}
1555
1556void AutomationProvider::WaitForBookmarkModelToLoad(
1557    int handle,
1558    IPC::Message* reply_message) {
1559  if (browser_tracker_->ContainsHandle(handle)) {
1560    Browser* browser = browser_tracker_->GetResource(handle);
1561    BookmarkModel* model = browser->profile()->GetBookmarkModel();
1562    if (model->IsLoaded()) {
1563      AutomationMsg_WaitForBookmarkModelToLoad::WriteReplyParams(
1564          reply_message, true);
1565      Send(reply_message);
1566    } else {
1567      // The observer will delete itself when done.
1568      new AutomationProviderBookmarkModelObserver(this, reply_message,
1569                                                  model);
1570    }
1571  }
1572}
1573
1574void AutomationProvider::AddBookmarkGroup(int handle,
1575                                          int64 parent_id, int index,
1576                                          std::wstring title,
1577                                          bool* success) {
1578  if (browser_tracker_->ContainsHandle(handle)) {
1579    Browser* browser = browser_tracker_->GetResource(handle);
1580    if (browser) {
1581      BookmarkModel* model = browser->profile()->GetBookmarkModel();
1582      if (!model->IsLoaded()) {
1583        *success = false;
1584        return;
1585      }
1586      const BookmarkNode* parent = model->GetNodeByID(parent_id);
1587      DCHECK(parent);
1588      if (parent) {
1589        const BookmarkNode* child = model->AddGroup(parent, index,
1590                                                    WideToUTF16(title));
1591        DCHECK(child);
1592        if (child)
1593          *success = true;
1594      }
1595    }
1596  }
1597  *success = false;
1598}
1599
1600void AutomationProvider::AddBookmarkURL(int handle,
1601                                        int64 parent_id, int index,
1602                                        std::wstring title, const GURL& url,
1603                                        bool* success) {
1604  if (browser_tracker_->ContainsHandle(handle)) {
1605    Browser* browser = browser_tracker_->GetResource(handle);
1606    if (browser) {
1607      BookmarkModel* model = browser->profile()->GetBookmarkModel();
1608      if (!model->IsLoaded()) {
1609        *success = false;
1610        return;
1611      }
1612      const BookmarkNode* parent = model->GetNodeByID(parent_id);
1613      DCHECK(parent);
1614      if (parent) {
1615        const BookmarkNode* child = model->AddURL(parent, index,
1616                                                  WideToUTF16(title), url);
1617        DCHECK(child);
1618        if (child)
1619          *success = true;
1620      }
1621    }
1622  }
1623  *success = false;
1624}
1625
1626void AutomationProvider::ReparentBookmark(int handle,
1627                                          int64 id, int64 new_parent_id,
1628                                          int index,
1629                                          bool* success) {
1630  if (browser_tracker_->ContainsHandle(handle)) {
1631    Browser* browser = browser_tracker_->GetResource(handle);
1632    if (browser) {
1633      BookmarkModel* model = browser->profile()->GetBookmarkModel();
1634      if (!model->IsLoaded()) {
1635        *success = false;
1636        return;
1637      }
1638      const BookmarkNode* node = model->GetNodeByID(id);
1639      DCHECK(node);
1640      const BookmarkNode* new_parent = model->GetNodeByID(new_parent_id);
1641      DCHECK(new_parent);
1642      if (node && new_parent) {
1643        model->Move(node, new_parent, index);
1644        *success = true;
1645      }
1646    }
1647  }
1648  *success = false;
1649}
1650
1651void AutomationProvider::SetBookmarkTitle(int handle,
1652                                          int64 id, std::wstring title,
1653                                          bool* success) {
1654  if (browser_tracker_->ContainsHandle(handle)) {
1655    Browser* browser = browser_tracker_->GetResource(handle);
1656    if (browser) {
1657      BookmarkModel* model = browser->profile()->GetBookmarkModel();
1658      if (!model->IsLoaded()) {
1659        *success = false;
1660        return;
1661      }
1662      const BookmarkNode* node = model->GetNodeByID(id);
1663      DCHECK(node);
1664      if (node) {
1665        model->SetTitle(node, WideToUTF16(title));
1666        *success = true;
1667      }
1668    }
1669  }
1670  *success = false;
1671}
1672
1673void AutomationProvider::SetBookmarkURL(int handle,
1674                                        int64 id, const GURL& url,
1675                                        bool* success) {
1676  if (browser_tracker_->ContainsHandle(handle)) {
1677    Browser* browser = browser_tracker_->GetResource(handle);
1678    if (browser) {
1679      BookmarkModel* model = browser->profile()->GetBookmarkModel();
1680      if (!model->IsLoaded()) {
1681        *success = false;
1682        return;
1683      }
1684      const BookmarkNode* node = model->GetNodeByID(id);
1685      DCHECK(node);
1686      if (node) {
1687        model->SetURL(node, url);
1688        *success = true;
1689      }
1690    }
1691  }
1692  *success = false;
1693}
1694
1695void AutomationProvider::RemoveBookmark(int handle,
1696                                        int64 id,
1697                                        bool* success) {
1698  if (browser_tracker_->ContainsHandle(handle)) {
1699    Browser* browser = browser_tracker_->GetResource(handle);
1700    if (browser) {
1701      BookmarkModel* model = browser->profile()->GetBookmarkModel();
1702      if (!model->IsLoaded()) {
1703        *success = false;
1704        return;
1705      }
1706      const BookmarkNode* node = model->GetNodeByID(id);
1707      DCHECK(node);
1708      if (node) {
1709        const BookmarkNode* parent = node->GetParent();
1710        DCHECK(parent);
1711        model->Remove(parent, parent->IndexOfChild(node));
1712        *success = true;
1713      }
1714    }
1715  }
1716  *success = false;
1717}
1718
1719// Sample json input: { "command": "SetWindowDimensions",
1720//                      "x": 20,         # optional
1721//                      "y": 20,         # optional
1722//                      "width": 800,    # optional
1723//                      "height": 600 }  # optional
1724void AutomationProvider::SetWindowDimensions(Browser* browser,
1725                                             DictionaryValue* args,
1726                                             IPC::Message* reply_message) {
1727  gfx::Rect rect = browser->window()->GetRestoredBounds();
1728  int x, y, width, height;
1729  if (args->GetInteger(L"x", &x))
1730    rect.set_x(x);
1731  if (args->GetInteger(L"y", &y))
1732    rect.set_y(y);
1733  if (args->GetInteger(L"width", &width))
1734    rect.set_width(width);
1735  if (args->GetInteger(L"height", &height))
1736    rect.set_height(height);
1737  browser->window()->SetBounds(rect);
1738  AutomationJSONReply(this, reply_message).SendSuccess(NULL);
1739}
1740
1741ListValue* AutomationProvider::GetInfobarsInfo(TabContents* tc) {
1742  // Each infobar may have different properties depending on the type.
1743  ListValue* infobars = new ListValue;
1744  for (int infobar_index = 0;
1745       infobar_index < tc->infobar_delegate_count();
1746       ++infobar_index) {
1747    DictionaryValue* infobar_item = new DictionaryValue;
1748    InfoBarDelegate* infobar = tc->GetInfoBarDelegateAt(infobar_index);
1749    if (infobar->AsConfirmInfoBarDelegate()) {
1750      // Also covers ThemeInstalledInfoBarDelegate and
1751      // CrashedExtensionInfoBarDelegate.
1752      infobar_item->SetString(L"type", "confirm_infobar");
1753      ConfirmInfoBarDelegate* confirm_infobar =
1754        infobar->AsConfirmInfoBarDelegate();
1755      infobar_item->SetString(L"text", confirm_infobar->GetMessageText());
1756      infobar_item->SetString(L"link_text", confirm_infobar->GetLinkText());
1757      ListValue* buttons_list = new ListValue;
1758      int buttons = confirm_infobar->GetButtons();
1759      if (ConfirmInfoBarDelegate::BUTTON_OK & buttons) {
1760        StringValue* button_label = new StringValue(
1761            confirm_infobar->GetButtonLabel(
1762              ConfirmInfoBarDelegate::BUTTON_OK));
1763        buttons_list->Append(button_label);
1764      }
1765      if (ConfirmInfoBarDelegate::BUTTON_CANCEL & buttons) {
1766        StringValue* button_label = new StringValue(
1767            confirm_infobar->GetButtonLabel(
1768              ConfirmInfoBarDelegate::BUTTON_CANCEL));
1769        buttons_list->Append(button_label);
1770      }
1771      infobar_item->Set(L"buttons", buttons_list);
1772    } else if (infobar->AsAlertInfoBarDelegate()) {
1773      infobar_item->SetString(L"type", "alert_infobar");
1774      AlertInfoBarDelegate* alert_infobar =
1775        infobar->AsAlertInfoBarDelegate();
1776      infobar_item->SetString(L"text", alert_infobar->GetMessageText());
1777    } else if (infobar->AsLinkInfoBarDelegate()) {
1778      infobar_item->SetString(L"type", "link_infobar");
1779      LinkInfoBarDelegate* link_infobar = infobar->AsLinkInfoBarDelegate();
1780      infobar_item->SetString(L"link_text", link_infobar->GetLinkText());
1781    } else if (infobar->AsTranslateInfoBarDelegate()) {
1782      infobar_item->SetString(L"type", "translate_infobar");
1783      TranslateInfoBarDelegate* translate_infobar =
1784          infobar->AsTranslateInfoBarDelegate();
1785      infobar_item->SetString(L"original_lang_code",
1786                              translate_infobar->GetOriginalLanguageCode());
1787      infobar_item->SetString(L"target_lang_code",
1788                              translate_infobar->GetTargetLanguageCode());
1789    } else if (infobar->AsExtensionInfoBarDelegate()) {
1790      infobar_item->SetString(L"type", "extension_infobar");
1791    } else {
1792      infobar_item->SetString(L"type", "unknown_infobar");
1793    }
1794    infobars->Append(infobar_item);
1795  }
1796  return infobars;
1797}
1798
1799// Sample json input: { "command": "WaitForInfobarCount",
1800//                      "count": COUNT,
1801//                      "tab_index": INDEX }
1802// Sample output: {}
1803void AutomationProvider::WaitForInfobarCount(Browser* browser,
1804                                        DictionaryValue* args,
1805                                        IPC::Message* reply_message) {
1806  int tab_index;
1807  int count;
1808  if (!args->GetInteger(L"count", &count) || count < 0 ||
1809      !args->GetInteger(L"tab_index", &tab_index) || tab_index < 0) {
1810    AutomationJSONReply(this, reply_message).SendError(
1811        "Missing or invalid args: 'count', 'tab_index'.");
1812    return;
1813  }
1814
1815  TabContents* tab_contents = browser->GetTabContentsAt(tab_index);
1816  // Observer deletes itself.
1817  new WaitForInfobarCountObserver(this, reply_message, tab_contents, count);
1818}
1819
1820namespace {
1821
1822// Task to get info about BrowserChildProcessHost. Must run on IO thread to
1823// honor the semantics of BrowserChildProcessHost.
1824// Used by AutomationProvider::GetBrowserInfo().
1825class GetChildProcessHostInfoTask : public Task {
1826 public:
1827  GetChildProcessHostInfoTask(base::WaitableEvent* event,
1828                              ListValue* child_processes)
1829    : event_(event),
1830      child_processes_(child_processes) {}
1831
1832  virtual void Run() {
1833    DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO));
1834    for (BrowserChildProcessHost::Iterator iter; !iter.Done(); ++iter) {
1835      // Only add processes which are already started,
1836      // since we need their handle.
1837      if ((*iter)->handle() == base::kNullProcessHandle) {
1838        continue;
1839      }
1840      ChildProcessInfo* info = *iter;
1841      DictionaryValue* item = new DictionaryValue;
1842      item->SetString(L"name", info->name());
1843      item->SetString(L"type",
1844                      ChildProcessInfo::GetTypeNameInEnglish(info->type()));
1845      item->SetInteger(L"pid", base::GetProcId(info->handle()));
1846      child_processes_->Append(item);
1847    }
1848    event_->Signal();
1849  }
1850
1851 private:
1852  base::WaitableEvent* const event_;  // weak
1853  ListValue* child_processes_;
1854
1855  DISALLOW_COPY_AND_ASSIGN(GetChildProcessHostInfoTask);
1856};
1857
1858}  // namespace
1859
1860// Sample json input: { "command": "GetBrowserInfo" }
1861// Refer to GetBrowserInfo() in chrome/test/pyautolib/pyauto.py for
1862// sample json output.
1863void AutomationProvider::GetBrowserInfo(Browser* browser,
1864                                        DictionaryValue* args,
1865                                        IPC::Message* reply_message) {
1866  DictionaryValue* properties = new DictionaryValue;
1867  properties->SetString(L"ChromeVersion", chrome::kChromeVersion);
1868  properties->SetString(L"BrowserProcessExecutableName",
1869                        chrome::kBrowserProcessExecutableName);
1870  properties->SetString(L"HelperProcessExecutableName",
1871                        chrome::kHelperProcessExecutableName);
1872  properties->SetString(L"BrowserProcessExecutablePath",
1873                        chrome::kBrowserProcessExecutablePath);
1874  properties->SetString(L"HelperProcessExecutablePath",
1875                        chrome::kHelperProcessExecutablePath);
1876  properties->SetString(L"command_line_string",
1877      CommandLine::ForCurrentProcess()->command_line_string());
1878
1879  std::string branding;
1880#if defined(GOOGLE_CHROME_BUILD)
1881  branding = "Google Chrome";
1882#elif defined(CHROMIUM_BUILD)
1883  branding = "Chromium";
1884#else
1885  branding = "Unknown Branding";
1886#endif
1887  properties->SetString(L"branding", branding);
1888
1889  scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
1890  return_value->Set(L"properties", properties);
1891
1892  return_value->SetInteger(L"browser_pid", base::GetCurrentProcId());
1893  // Add info about all windows in a list of dictionaries, one dictionary
1894  // item per window.
1895  ListValue* windows = new ListValue;
1896  int windex = 0;
1897  for (BrowserList::const_iterator it = BrowserList::begin();
1898       it != BrowserList::end();
1899       ++it, ++windex) {
1900    DictionaryValue* browser_item = new DictionaryValue;
1901    browser = *it;
1902    browser_item->SetInteger(L"index", windex);
1903    // Window properties
1904    gfx::Rect rect = browser->window()->GetRestoredBounds();
1905    browser_item->SetInteger(L"x", rect.x());
1906    browser_item->SetInteger(L"y", rect.y());
1907    browser_item->SetInteger(L"width", rect.width());
1908    browser_item->SetInteger(L"height", rect.height());
1909    browser_item->SetBoolean(L"fullscreen",
1910                             browser->window()->IsFullscreen());
1911    browser_item->SetInteger(L"selected_tab", browser->selected_index());
1912    browser_item->SetBoolean(L"incognito",
1913                             browser->profile()->IsOffTheRecord());
1914    // For each window, add info about all tabs in a list of dictionaries,
1915    // one dictionary item per tab.
1916    ListValue* tabs = new ListValue;
1917    for (int i = 0; i < browser->tab_count(); ++i) {
1918      TabContents* tc = browser->GetTabContentsAt(i);
1919      DictionaryValue* tab = new DictionaryValue;
1920      tab->SetInteger(L"index", i);
1921      tab->SetString(L"url", tc->GetURL().spec());
1922      tab->SetInteger(L"renderer_pid",
1923                      base::GetProcId(tc->GetRenderProcessHost()->GetHandle()));
1924      tab->Set(L"infobars", GetInfobarsInfo(tc));
1925      tabs->Append(tab);
1926    }
1927    browser_item->Set(L"tabs", tabs);
1928
1929    windows->Append(browser_item);
1930  }
1931  return_value->Set(L"windows", windows);
1932
1933  return_value->SetString(L"child_process_path",
1934                          ChildProcessHost::GetChildPath(true).value());
1935  // Child processes are the processes for plugins and other workers.
1936  // Add all child processes in a list of dictionaries, one dictionary item
1937  // per child process.
1938  ListValue* child_processes = new ListValue;
1939  base::WaitableEvent event(true   /* manual reset */,
1940                            false  /* not initially signaled */);
1941  CHECK(ChromeThread::PostTask(
1942      ChromeThread::IO, FROM_HERE,
1943      new GetChildProcessHostInfoTask(&event, child_processes)));
1944  event.Wait();
1945  return_value->Set(L"child_processes", child_processes);
1946
1947  // Add all extension processes in a list of dictionaries, one dictionary
1948  // item per extension process.
1949  ListValue* extension_processes = new ListValue;
1950  ProfileManager* profile_manager = g_browser_process->profile_manager();
1951  for (ProfileManager::const_iterator it = profile_manager->begin();
1952       it != profile_manager->end(); ++it) {
1953    ExtensionProcessManager* process_manager =
1954        (*it)->GetExtensionProcessManager();
1955    ExtensionProcessManager::const_iterator jt;
1956    for (jt = process_manager->begin(); jt != process_manager->end(); ++jt) {
1957      ExtensionHost* ex_host = *jt;
1958      // Don't add dead extension processes.
1959      if (!ex_host->IsRenderViewLive())
1960        continue;
1961      DictionaryValue* item = new DictionaryValue;
1962      item->SetString(L"name", ex_host->extension()->name());
1963      item->SetInteger(
1964          L"pid",
1965          base::GetProcId(ex_host->render_process_host()->GetHandle()));
1966      extension_processes->Append(item);
1967    }
1968  }
1969  return_value->Set(L"extension_processes", extension_processes);
1970  AutomationJSONReply(this, reply_message).SendSuccess(return_value.get());
1971}
1972
1973// Sample json input: { "command": "GetHistoryInfo",
1974//                      "search_text": "some text" }
1975// Refer chrome/test/pyautolib/history_info.py for sample json output.
1976void AutomationProvider::GetHistoryInfo(Browser* browser,
1977                                        DictionaryValue* args,
1978                                        IPC::Message* reply_message) {
1979  consumer_.CancelAllRequests();
1980
1981  string16 search_text;
1982  args->GetString("search_text", &search_text);
1983
1984  // Fetch history.
1985  HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
1986  history::QueryOptions options;
1987  // The observer owns itself.  It deletes itself after it fetches history.
1988  AutomationProviderHistoryObserver* history_observer =
1989      new AutomationProviderHistoryObserver(this, reply_message);
1990  hs->QueryHistory(
1991      search_text,
1992      options,
1993      &consumer_,
1994      NewCallback(history_observer,
1995                  &AutomationProviderHistoryObserver::HistoryQueryComplete));
1996}
1997
1998// Sample json input: { "command": "AddHistoryItem",
1999//                      "item": { "URL": "http://www.google.com",
2000//                                "title": "Google",   # optional
2001//                                "time": 12345        # optional (time_t)
2002//                               } }
2003// Refer chrome/test/pyautolib/pyauto.py for details on input.
2004void AutomationProvider::AddHistoryItem(Browser* browser,
2005                                        DictionaryValue* args,
2006                                        IPC::Message* reply_message) {
2007  DictionaryValue* item = NULL;
2008  args->GetDictionary(L"item", &item);
2009  string16 url_text;
2010  string16 title;
2011  base::Time time = base::Time::Now();
2012  AutomationJSONReply reply(this, reply_message);
2013
2014  if (!item->GetString("url", &url_text)) {
2015    reply.SendError("bad args (no URL in dict?)");
2016    return;
2017  }
2018  GURL gurl(url_text);
2019  item->GetString("title", &title);  // Don't care if it fails.
2020  int it;
2021  double dt;
2022  if (item->GetInteger(L"time", &it))
2023    time = base::Time::FromTimeT(it);
2024  else if (item->GetReal(L"time", &dt))
2025    time = base::Time::FromDoubleT(dt);
2026
2027  // Ideas for "dummy" values (e.g. id_scope) came from
2028  // chrome/browser/autocomplete/history_contents_provider_unittest.cc
2029  HistoryService* hs = profile_->GetHistoryService(Profile::EXPLICIT_ACCESS);
2030  const void* id_scope = reinterpret_cast<void*>(1);
2031  hs->AddPage(gurl, time,
2032              id_scope,
2033              0,
2034              GURL(),
2035              PageTransition::LINK,
2036              history::RedirectList(),
2037              false);
2038  if (title.length())
2039    hs->SetPageTitle(gurl, title);
2040  reply.SendSuccess(NULL);
2041}
2042
2043// Sample json input: { "command": "GetDownloadsInfo" }
2044// Refer chrome/test/pyautolib/download_info.py for sample json output.
2045void AutomationProvider::GetDownloadsInfo(Browser* browser,
2046                                          DictionaryValue* args,
2047                                          IPC::Message* reply_message) {
2048  AutomationProviderDownloadManagerObserver observer;
2049  std::vector<DownloadItem*> downloads;
2050  scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
2051  AutomationJSONReply reply(this, reply_message);
2052
2053  if (!profile_->HasCreatedDownloadManager()) {
2054    reply.SendError("no download manager");
2055    return;
2056  }
2057  // Use DownloadManager's GetDownloads() method and not GetCurrentDownloads()
2058  // since that would be transient; a download might enter and empty out
2059  // the current download queue too soon to be noticed.
2060  profile_->GetDownloadManager()->GetDownloads(&observer, L"");
2061  downloads = observer.Downloads();
2062
2063  std::map<DownloadItem::DownloadState, std::string> state_to_string;
2064  state_to_string[DownloadItem::IN_PROGRESS] = std::string("IN_PROGRESS");
2065  state_to_string[DownloadItem::CANCELLED] = std::string("CANCELLED");
2066  state_to_string[DownloadItem::REMOVING] = std::string("REMOVING");
2067  state_to_string[DownloadItem::COMPLETE] = std::string("COMPLETE");
2068
2069  std::map<DownloadItem::SafetyState, std::string> safety_state_to_string;
2070  safety_state_to_string[DownloadItem::SAFE] = std::string("SAFE");
2071  safety_state_to_string[DownloadItem::DANGEROUS] = std::string("DANGEROUS");
2072  safety_state_to_string[DownloadItem::DANGEROUS_BUT_VALIDATED] =
2073      std::string("DANGEROUS_BUT_VALIDATED");
2074
2075  ListValue* list_of_downloads = new ListValue;
2076  for (std::vector<DownloadItem*>::iterator it = downloads.begin();
2077       it != downloads.end();
2078       it++) {  // Fill info about each download item.
2079    DictionaryValue* dl_item_value = new DictionaryValue;
2080    dl_item_value->SetInteger(L"id", static_cast<int>((*it)->id()));
2081    dl_item_value->SetString(L"url", (*it)->url().spec());
2082    dl_item_value->SetString(L"referrer_url", (*it)->referrer_url().spec());
2083    dl_item_value->SetString(L"file_name", (*it)->file_name().value());
2084    dl_item_value->SetString(L"full_path", (*it)->full_path().value());
2085    dl_item_value->SetBoolean(L"is_paused", (*it)->is_paused());
2086    dl_item_value->SetBoolean(L"open_when_complete",
2087                              (*it)->open_when_complete());
2088    dl_item_value->SetBoolean(L"is_extension_install",
2089                              (*it)->is_extension_install());
2090    dl_item_value->SetBoolean(L"is_temporary", (*it)->is_temporary());
2091    dl_item_value->SetBoolean(L"is_otr", (*it)->is_otr());  // off-the-record
2092    dl_item_value->SetString(L"state", state_to_string[(*it)->state()]);
2093    dl_item_value->SetString(L"safety_state",
2094                             safety_state_to_string[(*it)->safety_state()]);
2095    dl_item_value->SetInteger(L"PercentComplete", (*it)->PercentComplete());
2096    list_of_downloads->Append(dl_item_value);
2097  }
2098  return_value->Set(L"downloads", list_of_downloads);
2099
2100  reply.SendSuccess(return_value.get());
2101  // All value objects allocated above are owned by |return_value|
2102  // and get freed by it.
2103}
2104
2105void AutomationProvider::WaitForDownloadsToComplete(
2106    Browser* browser,
2107    DictionaryValue* args,
2108    IPC::Message* reply_message) {
2109  AutomationProviderDownloadManagerObserver observer;
2110  std::vector<DownloadItem*> downloads;
2111  AutomationJSONReply reply(this, reply_message);
2112
2113  // Look for a quick return.
2114  if (!profile_->HasCreatedDownloadManager()) {
2115    reply.SendSuccess(NULL);  // No download manager.
2116    return;
2117  }
2118  profile_->GetDownloadManager()->GetCurrentDownloads(&observer, FilePath());
2119  downloads = observer.Downloads();
2120  if (downloads.size() == 0) {
2121    reply.SendSuccess(NULL);
2122    return;
2123  }
2124
2125  // The observer owns itself.  When the last observed item pings, it
2126  // deletes itself.
2127  AutomationProviderDownloadItemObserver* item_observer =
2128      new AutomationProviderDownloadItemObserver(
2129          this, reply_message, downloads.size());
2130  for (std::vector<DownloadItem*>::iterator i = downloads.begin();
2131       i != downloads.end();
2132       i++) {
2133    (*i)->AddObserver(item_observer);
2134  }
2135}
2136
2137// Sample json input: { "command": "GetPrefsInfo" }
2138// Refer chrome/test/pyautolib/prefs_info.py for sample json output.
2139void AutomationProvider::GetPrefsInfo(Browser* browser,
2140                                      DictionaryValue* args,
2141                                      IPC::Message* reply_message) {
2142  const PrefService::PreferenceSet& prefs =
2143      profile_->GetPrefs()->preference_set();
2144  DictionaryValue* items = new DictionaryValue;
2145  for (PrefService::PreferenceSet::const_iterator it = prefs.begin();
2146       it != prefs.end(); ++it) {
2147    items->Set((*it)->name(), (*it)->GetValue()->DeepCopy());
2148  }
2149  scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
2150  return_value->Set(L"prefs", items);  // return_value owns items.
2151  AutomationJSONReply(this, reply_message).SendSuccess(return_value.get());
2152}
2153
2154// Sample json input: { "command": "SetPrefs", "path": path, "value": value }
2155void AutomationProvider::SetPrefs(Browser* browser,
2156                                  DictionaryValue* args,
2157                                  IPC::Message* reply_message) {
2158  std::wstring path;
2159  Value* val;
2160  AutomationJSONReply reply(this, reply_message);
2161  if (args->GetString(L"path", &path) && args->Get(L"value", &val)) {
2162    PrefService* pref_service = profile_->GetPrefs();
2163    const PrefService::Preference* pref =
2164        pref_service->FindPreference(path.c_str());
2165    if (!pref) {  // Not a registered pref.
2166      reply.SendError("pref not registered.");
2167      return;
2168    } else if (pref->IsManaged()) {  // Do not attempt to change a managed pref.
2169      reply.SendError("pref is managed. cannot be changed.");
2170      return;
2171    } else {  // Set the pref.
2172      pref_service->Set(path.c_str(), *val);
2173    }
2174  } else {
2175    reply.SendError("no pref path or value given.");
2176    return;
2177  }
2178
2179  reply.SendSuccess(NULL);
2180}
2181
2182// Sample json input: { "command": "GetOmniboxInfo" }
2183// Refer chrome/test/pyautolib/omnibox_info.py for sample json output.
2184void AutomationProvider::GetOmniboxInfo(Browser* browser,
2185                                        DictionaryValue* args,
2186                                        IPC::Message* reply_message) {
2187  scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
2188
2189  LocationBar* loc_bar = browser->window()->GetLocationBar();
2190  AutocompleteEditView* edit_view = loc_bar->location_entry();
2191  AutocompleteEditModel* model = edit_view->model();
2192
2193  // Fill up matches.
2194  ListValue* matches = new ListValue;
2195  const AutocompleteResult& result = model->result();
2196  for (AutocompleteResult::const_iterator i = result.begin();
2197       i != result.end(); ++i) {
2198    const AutocompleteMatch& match = *i;
2199    DictionaryValue* item = new DictionaryValue;  // owned by return_value
2200    item->SetString(L"type", AutocompleteMatch::TypeToString(match.type));
2201    item->SetBoolean(L"starred", match.starred);
2202    item->SetString(L"destination_url", match.destination_url.spec());
2203    item->SetString(L"contents", match.contents);
2204    item->SetString(L"description", match.description);
2205    matches->Append(item);
2206  }
2207  return_value->Set(L"matches", matches);
2208
2209  // Fill up other properties.
2210  DictionaryValue* properties = new DictionaryValue;  // owned by return_value
2211  properties->SetBoolean(L"has_focus", model->has_focus());
2212  properties->SetBoolean(L"query_in_progress", model->query_in_progress());
2213  properties->SetString(L"keyword", model->keyword());
2214  properties->SetString(L"text", edit_view->GetText());
2215  return_value->Set(L"properties", properties);
2216
2217  AutomationJSONReply(this, reply_message).SendSuccess(return_value.get());
2218}
2219
2220// Sample json input: { "command": "SetOmniboxText",
2221//                      "text": "goog" }
2222void AutomationProvider::SetOmniboxText(Browser* browser,
2223                                        DictionaryValue* args,
2224                                        IPC::Message* reply_message) {
2225  std::wstring text;
2226  AutomationJSONReply reply(this, reply_message);
2227  if (!args->GetString(L"text", &text)) {
2228    reply.SendError("text missing");
2229    return;
2230  }
2231  browser->FocusLocationBar();
2232  LocationBar* loc_bar = browser->window()->GetLocationBar();
2233  AutocompleteEditView* edit_view = loc_bar->location_entry();
2234  edit_view->model()->OnSetFocus(false);
2235  edit_view->SetUserText(text);
2236  reply.SendSuccess(NULL);
2237}
2238
2239// Sample json input: { "command": "OmniboxMovePopupSelection",
2240//                      "count": 1 }
2241// Negative count implies up, positive implies down. Count values will be
2242// capped by the size of the popup list.
2243void AutomationProvider::OmniboxMovePopupSelection(
2244    Browser* browser,
2245    DictionaryValue* args,
2246    IPC::Message* reply_message) {
2247  int count;
2248  AutomationJSONReply reply(this, reply_message);
2249  if (!args->GetInteger(L"count", &count)) {
2250    reply.SendError("count missing");
2251    return;
2252  }
2253  LocationBar* loc_bar = browser->window()->GetLocationBar();
2254  AutocompleteEditModel* model = loc_bar->location_entry()->model();
2255  model->OnUpOrDownKeyPressed(count);
2256  reply.SendSuccess(NULL);
2257}
2258
2259// Sample json input: { "command": "OmniboxAcceptInput" }
2260void AutomationProvider::OmniboxAcceptInput(Browser* browser,
2261                                            DictionaryValue* args,
2262                                            IPC::Message* reply_message) {
2263  NavigationController& controller =
2264      browser->GetSelectedTabContents()->controller();
2265  // Setup observer to wait until the selected item loads.
2266  NotificationObserver* observer =
2267      new OmniboxAcceptNotificationObserver(&controller, this, reply_message);
2268  notification_observer_list_.AddObserver(observer);
2269
2270  browser->window()->GetLocationBar()->AcceptInput();
2271}
2272
2273// Sample json input: { "command": "GetInitialLoadTimes" }
2274// Refer to InitialLoadObserver::GetTimingInformation() for sample output.
2275void AutomationProvider::GetInitialLoadTimes(
2276    Browser*,
2277    DictionaryValue*,
2278    IPC::Message* reply_message) {
2279  scoped_ptr<DictionaryValue> return_value(
2280      initial_load_observer_->GetTimingInformation());
2281
2282  std::string json_return;
2283  base::JSONWriter::Write(return_value.get(), false, &json_return);
2284  AutomationMsg_SendJSONRequest::WriteReplyParams(
2285      reply_message, json_return, true);
2286  Send(reply_message);
2287}
2288
2289// Sample json input: { "command": "GetPluginsInfo" }
2290// Refer chrome/test/pyautolib/plugins_info.py for sample json output.
2291void AutomationProvider::GetPluginsInfo(Browser* browser,
2292                                        DictionaryValue* args,
2293                                        IPC::Message* reply_message) {
2294  std::vector<WebPluginInfo> plugins;
2295  NPAPI::PluginList::Singleton()->GetPlugins(false, &plugins);
2296  ListValue* items = new ListValue;
2297  for (std::vector<WebPluginInfo>::const_iterator it = plugins.begin();
2298       it != plugins.end();
2299       ++it) {
2300    DictionaryValue* item = new DictionaryValue;
2301    item->SetStringFromUTF16(L"name", it->name);
2302    item->SetString(L"path", it->path.value());
2303    item->SetStringFromUTF16(L"version", it->version);
2304    item->SetStringFromUTF16(L"desc", it->desc);
2305    item->SetBoolean(L"enabled", it->enabled);
2306    // Add info about mime types.
2307    ListValue* mime_types = new ListValue();
2308    for (std::vector<WebPluginMimeType>::const_iterator type_it =
2309             it->mime_types.begin();
2310         type_it != it->mime_types.end();
2311         ++type_it) {
2312      DictionaryValue* mime_type = new DictionaryValue();
2313      mime_type->SetString(L"mimeType", type_it->mime_type);
2314      mime_type->SetStringFromUTF16(L"description", type_it->description);
2315
2316      ListValue* file_extensions = new ListValue();
2317      for (std::vector<std::string>::const_iterator ext_it =
2318               type_it->file_extensions.begin();
2319           ext_it != type_it->file_extensions.end();
2320           ++ext_it) {
2321        file_extensions->Append(new StringValue(*ext_it));
2322      }
2323      mime_type->Set(L"fileExtensions", file_extensions);
2324
2325      mime_types->Append(mime_type);
2326    }
2327    item->Set(L"mimeTypes", mime_types);
2328    items->Append(item);
2329  }
2330  scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
2331  return_value->Set(L"plugins", items);  // return_value owns items.
2332
2333  AutomationJSONReply(this, reply_message).SendSuccess(return_value.get());
2334}
2335
2336// Sample json input:
2337//    { "command": "EnablePlugin",
2338//      "path": "/Library/Internet Plug-Ins/Flash Player.plugin" }
2339void AutomationProvider::EnablePlugin(Browser* browser,
2340                                      DictionaryValue* args,
2341                                      IPC::Message* reply_message) {
2342  FilePath::StringType path;
2343  AutomationJSONReply reply(this, reply_message);
2344  if (!args->GetString(L"path", &path)) {
2345    reply.SendError("path not specified.");
2346    return;
2347  } else if (!NPAPI::PluginList::Singleton()->EnablePlugin(FilePath(path))) {
2348    reply.SendError(StringPrintf("Could not enable plugin for path %s.",
2349                                 path.c_str()));
2350    return;
2351  }
2352  reply.SendSuccess(NULL);
2353}
2354
2355// Sample json input:
2356//    { "command": "DisablePlugin",
2357//      "path": "/Library/Internet Plug-Ins/Flash Player.plugin" }
2358void AutomationProvider::DisablePlugin(Browser* browser,
2359                                       DictionaryValue* args,
2360                                       IPC::Message* reply_message) {
2361  FilePath::StringType path;
2362  AutomationJSONReply reply(this, reply_message);
2363  if (!args->GetString(L"path", &path)) {
2364    reply.SendError("path not specified.");
2365    return;
2366  } else if (!NPAPI::PluginList::Singleton()->DisablePlugin(FilePath(path))) {
2367    reply.SendError(StringPrintf("Could not disable plugin for path %s.",
2368                                 path.c_str()));
2369    return;
2370  }
2371  reply.SendSuccess(NULL);
2372}
2373
2374// Sample json input:
2375//    { "command": "SaveTabContents",
2376//      "tab_index": 0,
2377//      "filename": <a full pathname> }
2378// Sample json output:
2379//    {}
2380void AutomationProvider::SaveTabContents(Browser* browser,
2381                                         DictionaryValue* args,
2382                                         IPC::Message* reply_message) {
2383  int tab_index = 0;
2384  FilePath::StringType filename;
2385  FilePath::StringType parent_directory;
2386  TabContents* tab_contents = NULL;
2387
2388  if (!args->GetInteger(L"tab_index", &tab_index) ||
2389      !args->GetString(L"filename", &filename)) {
2390    AutomationJSONReply(this, reply_message).SendError(
2391        "tab_index or filename param missing");
2392    return;
2393  } else {
2394    tab_contents = browser->GetTabContentsAt(tab_index);
2395    if (!tab_contents) {
2396      AutomationJSONReply(this, reply_message).SendError(
2397          "no tab at tab_index");
2398      return;
2399    }
2400  }
2401  // We're doing a SAVE_AS_ONLY_HTML so the the directory path isn't
2402  // used.  Nevertheless, SavePackage requires it be valid.  Sigh.
2403  parent_directory = FilePath(filename).DirName().value();
2404  if (!tab_contents->SavePage(FilePath(filename), FilePath(parent_directory),
2405                              SavePackage::SAVE_AS_ONLY_HTML)) {
2406    AutomationJSONReply(this, reply_message).SendError(
2407        "Could not initiate SavePage");
2408    return;
2409  }
2410  // The observer will delete itself when done.
2411  new SavePackageNotificationObserver(tab_contents->save_package(),
2412                                      this, reply_message);
2413}
2414
2415// Refer to ImportSettings() in chrome/test/pyautolib/pyauto.py for sample
2416// json input.
2417// Sample json output: "{}"
2418void AutomationProvider::ImportSettings(Browser* browser,
2419                                        DictionaryValue* args,
2420                                        IPC::Message* reply_message) {
2421  // Map from the json string passed over to the import item masks.
2422  std::map<std::string, ImportItem> string_to_import_item;
2423  string_to_import_item["HISTORY"] = importer::HISTORY;
2424  string_to_import_item["FAVORITES"] = importer::FAVORITES;
2425  string_to_import_item["COOKIES"] = importer::COOKIES;
2426  string_to_import_item["PASSWORDS"] = importer::PASSWORDS;
2427  string_to_import_item["SEARCH_ENGINES"] = importer::SEARCH_ENGINES;
2428  string_to_import_item["HOME_PAGE"] = importer::HOME_PAGE;
2429  string_to_import_item["ALL"] = importer::ALL;
2430
2431  std::wstring browser_name;
2432  int import_items = 0;
2433  ListValue* import_items_list = NULL;
2434  bool first_run;
2435
2436  if (!args->GetString(L"import_from", &browser_name) ||
2437      !args->GetBoolean(L"first_run", &first_run) ||
2438      !args->GetList(L"import_items", &import_items_list)) {
2439    AutomationJSONReply(this, reply_message).SendError(
2440        "Incorrect type for one or more of the arguments.");
2441    return;
2442  }
2443
2444  int num_items = import_items_list->GetSize();
2445  for (int i = 0; i < num_items; i++) {
2446    std::string item;
2447    import_items_list->GetString(i, &item);
2448    // If the provided string is not part of the map, error out.
2449    if (!ContainsKey(string_to_import_item, item)) {
2450      AutomationJSONReply(this, reply_message).SendError(
2451          "Invalid item string found in import_items.");
2452      return;
2453    }
2454    import_items |= string_to_import_item[item];
2455  }
2456
2457  ImporterHost* importer_host = new ImporterHost();
2458  // Get the correct ProfileInfo based on the browser they user provided.
2459  importer::ProfileInfo profile_info;
2460  int num_browsers = importer_host->GetAvailableProfileCount();
2461  int i = 0;
2462  for ( ; i < num_browsers; i++) {
2463    std::wstring name = importer_host->GetSourceProfileNameAt(i);
2464    if (name == browser_name) {
2465      profile_info = importer_host->GetSourceProfileInfoAt(i);
2466      break;
2467    }
2468  }
2469  // If we made it to the end of the loop, then the input was bad.
2470  if (i == num_browsers) {
2471    AutomationJSONReply(this, reply_message).SendError(
2472        "Invalid browser name string found.");
2473    return;
2474  }
2475
2476  Profile* profile = browser->profile();
2477
2478  importer_host->SetObserver(
2479      new AutomationProviderImportSettingsObserver(this, reply_message));
2480  importer_host->StartImportSettings(profile_info, profile, import_items,
2481                                     new ProfileWriter(profile), first_run);
2482}
2483
2484// See AddSavedPassword() in chrome/test/functional/pyauto.py for sample json
2485// input.
2486// Sample json output: { "password_added": true }
2487void AutomationProvider::AddSavedPassword(Browser* browser,
2488                                          DictionaryValue* args,
2489                                          IPC::Message* reply_message) {
2490  string16 username;
2491  string16 password;
2492  base::Time time = base::Time::Now();
2493  AutomationJSONReply reply(this, reply_message);
2494
2495  if (!args->GetStringAsUTF16(L"password", &password) ||
2496      !args->GetStringAsUTF16(L"username", &username)) {
2497    reply.SendError("Username and password must be strings.");
2498    return;
2499  }
2500
2501  // If the time is specified, change time to the specified time.
2502  int it;
2503  double dt;
2504  if (args->GetInteger(L"time", &it))
2505    time = base::Time::FromTimeT(it);
2506  else if (args->GetReal(L"time", &dt))
2507    time = base::Time::FromDoubleT(dt);
2508
2509  webkit_glue::PasswordForm new_password;
2510  new_password.username_value = username;
2511  new_password.password_value = password;
2512  new_password.date_created = time;
2513
2514  Profile* profile = browser->profile();
2515  // Use IMPLICIT_ACCESS since new passwords aren't added off the record.
2516  PasswordStore* password_store =
2517      profile->GetPasswordStore(Profile::IMPLICIT_ACCESS);
2518
2519  // Set the return based on whether setting the password succeeded.
2520  scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
2521
2522  // It will be null if it's accessed in an incognito window.
2523  if (password_store != NULL) {
2524    password_store->AddLogin(new_password);
2525    return_value->SetBoolean(L"password_added", true);
2526  } else {
2527    return_value->SetBoolean(L"password_added", false);
2528  }
2529
2530  reply.SendSuccess(return_value.get());
2531}
2532
2533// Sample json input: { "command": "GetSavedPasswords" }
2534// Refer to GetSavedPasswords() in chrome/test/pyautolib/pyauto.py for sample
2535// json output.
2536void AutomationProvider::GetSavedPasswords(Browser* browser,
2537                                           DictionaryValue* args,
2538                                           IPC::Message* reply_message) {
2539  Profile* profile = browser->profile();
2540  // Use EXPLICIT_ACCESS since saved passwords can be retreived off the record.
2541  PasswordStore* password_store =
2542      profile->GetPasswordStore(Profile::EXPLICIT_ACCESS);
2543  password_store->GetAutofillableLogins(
2544      new AutomationProviderGetPasswordsObserver(this, reply_message));
2545  // Observer deletes itself after returning.
2546}
2547
2548// Refer to ClearBrowsingData() in chrome/test/pyautolib/pyauto.py for sample
2549// json input.
2550// Sample json output: {}
2551void AutomationProvider::ClearBrowsingData(Browser* browser,
2552                                           DictionaryValue* args,
2553                                           IPC::Message* reply_message) {
2554  std::map<std::string, BrowsingDataRemover::TimePeriod> string_to_time_period;
2555  string_to_time_period["LAST_HOUR"] = BrowsingDataRemover::LAST_HOUR;
2556  string_to_time_period["LAST_DAY"] = BrowsingDataRemover::LAST_DAY;
2557  string_to_time_period["LAST_WEEK"] = BrowsingDataRemover::LAST_WEEK;
2558  string_to_time_period["FOUR_WEEKS"] = BrowsingDataRemover::FOUR_WEEKS;
2559  string_to_time_period["EVERYTHING"] = BrowsingDataRemover::EVERYTHING;
2560
2561  std::map<std::string, int> string_to_mask_value;
2562  string_to_mask_value["HISTORY"] = BrowsingDataRemover::REMOVE_HISTORY;
2563  string_to_mask_value["DOWNLOADS"] = BrowsingDataRemover::REMOVE_DOWNLOADS;
2564  string_to_mask_value["COOKIES"] = BrowsingDataRemover::REMOVE_COOKIES;
2565  string_to_mask_value["PASSWORDS"] = BrowsingDataRemover::REMOVE_PASSWORDS;
2566  string_to_mask_value["FORM_DATA"] = BrowsingDataRemover::REMOVE_FORM_DATA;
2567  string_to_mask_value["CACHE"] = BrowsingDataRemover::REMOVE_CACHE;
2568
2569  std::string time_period;
2570  ListValue* to_remove;
2571  if (!args->GetString(L"time_period", &time_period) ||
2572      !args->GetList(L"to_remove", &to_remove)) {
2573    AutomationJSONReply(this, reply_message).SendError(
2574        "time_period must be a string and to_remove a list.");
2575    return;
2576  }
2577
2578  int remove_mask = 0;
2579  int num_removals = to_remove->GetSize();
2580  for (int i = 0; i < num_removals; i++) {
2581    std::string removal;
2582    to_remove->GetString(i, &removal);
2583    // If the provided string is not part of the map, then error out.
2584    if (!ContainsKey(string_to_mask_value, removal)) {
2585      AutomationJSONReply(this, reply_message).SendError(
2586          "Invalid browsing data string found in to_remove.");
2587      return;
2588    }
2589    remove_mask |= string_to_mask_value[removal];
2590  }
2591
2592  if (!ContainsKey(string_to_time_period, time_period)) {
2593    AutomationJSONReply(this, reply_message).SendError(
2594        "Invalid string for time_period.");
2595    return;
2596  }
2597
2598  BrowsingDataRemover* remover = new BrowsingDataRemover(
2599      profile(), string_to_time_period[time_period], base::Time());
2600
2601  remover->AddObserver(
2602      new AutomationProviderBrowsingDataObserver(this, reply_message));
2603  remover->Remove(remove_mask);
2604  // BrowsingDataRemover deletes itself using DeleteTask.
2605  // The observer also deletes itself after sending the reply.
2606}
2607
2608// Sample json input: { "command": "GetThemeInfo" }
2609// Refer GetThemeInfo() in chrome/test/pyautolib/pyauto.py for sample output.
2610void AutomationProvider::GetThemeInfo(Browser* browser,
2611                                      DictionaryValue* args,
2612                                      IPC::Message* reply_message) {
2613  scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
2614  Extension* theme = browser->profile()->GetTheme();
2615  if (theme) {
2616    return_value->SetString(L"name", theme->name());
2617    return_value->Set(L"images", theme->GetThemeImages()->DeepCopy());
2618    return_value->Set(L"colors", theme->GetThemeColors()->DeepCopy());
2619    return_value->Set(L"tints", theme->GetThemeTints()->DeepCopy());
2620  }
2621  AutomationJSONReply(this, reply_message).SendSuccess(return_value.get());
2622}
2623
2624// Sample json input:
2625//    { "command": "GetAutoFillProfile" }
2626// Refer to GetAutoFillProfile() in chrome/test/pyautolib/pyauto.py for sample
2627// json output.
2628void AutomationProvider::GetAutoFillProfile(Browser* browser,
2629                                            DictionaryValue* args,
2630                                            IPC::Message* reply_message) {
2631  // Get the AutoFillProfiles currently in the database.
2632  int tab_index = 0;
2633  args->GetInteger(L"tab_index", &tab_index);
2634  TabContents* tab_contents = browser->GetTabContentsAt(tab_index);
2635  AutomationJSONReply reply(this, reply_message);
2636
2637  if (tab_contents) {
2638    PersonalDataManager* pdm = tab_contents->profile()->GetOriginalProfile()
2639        ->GetPersonalDataManager();
2640    if (pdm) {
2641      std::vector<AutoFillProfile*> autofill_profiles = pdm->profiles();
2642      std::vector<CreditCard*> credit_cards = pdm->credit_cards();
2643
2644      ListValue* profiles = GetListFromAutoFillProfiles(autofill_profiles);
2645      ListValue* cards = GetListFromCreditCards(credit_cards);
2646
2647      scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
2648
2649      return_value->Set(L"profiles", profiles);
2650      return_value->Set(L"credit_cards", cards);
2651      reply.SendSuccess(return_value.get());
2652    } else {
2653      reply.SendError("No PersonalDataManager.");
2654      return;
2655    }
2656  } else {
2657    reply.SendError("No tab at that index.");
2658    return;
2659  }
2660}
2661
2662// Refer to FillAutoFillProfile() in chrome/test/pyautolib/pyauto.py for sample
2663// json input.
2664// Sample json output: {}
2665void AutomationProvider::FillAutoFillProfile(Browser* browser,
2666                                             DictionaryValue* args,
2667                                             IPC::Message* reply_message) {
2668  AutomationJSONReply reply(this, reply_message);
2669  ListValue* profiles = NULL;
2670  ListValue* cards = NULL;
2671  args->GetList(L"profiles", &profiles);
2672  args->GetList(L"credit_cards", &cards);
2673  std::string error_mesg;
2674
2675  std::vector<AutoFillProfile> autofill_profiles;
2676  std::vector<CreditCard> credit_cards;
2677  // Create an AutoFillProfile for each of the dictionary profiles.
2678  if (profiles) {
2679    autofill_profiles = GetAutoFillProfilesFromList(*profiles, &error_mesg);
2680  }
2681  // Create a CreditCard for each of the dictionary values.
2682  if (cards) {
2683    credit_cards = GetCreditCardsFromList(*cards, &error_mesg);
2684  }
2685  if (!error_mesg.empty()) {
2686    reply.SendError(error_mesg);
2687    return;
2688  }
2689
2690  // Save the AutoFillProfiles.
2691  int tab_index = 0;
2692  args->GetInteger(L"tab_index", &tab_index);
2693  TabContents* tab_contents = browser->GetTabContentsAt(tab_index);
2694
2695  if (tab_contents) {
2696    PersonalDataManager* pdm = tab_contents->profile()
2697        ->GetPersonalDataManager();
2698    if (pdm) {
2699      pdm->OnAutoFillDialogApply(profiles? &autofill_profiles : NULL,
2700                                 cards? &credit_cards : NULL);
2701    } else {
2702      reply.SendError("No PersonalDataManager.");
2703      return;
2704    }
2705  } else {
2706    reply.SendError("No tab at that index.");
2707    return;
2708  }
2709  reply.SendSuccess(NULL);
2710}
2711
2712/* static */
2713ListValue* AutomationProvider::GetListFromAutoFillProfiles(
2714    std::vector<AutoFillProfile*> autofill_profiles) {
2715  ListValue* profiles = new ListValue;
2716
2717  std::map<AutoFillFieldType, std::wstring> autofill_type_to_string
2718      = GetAutoFillFieldToStringMap();
2719
2720  // For each AutoFillProfile, transform it to a dictionary object to return.
2721  for (std::vector<AutoFillProfile*>::iterator it = autofill_profiles.begin();
2722       it != autofill_profiles.end(); ++it) {
2723    AutoFillProfile* profile = *it;
2724    DictionaryValue* profile_info = new DictionaryValue;
2725    profile_info->SetStringFromUTF16(L"label", profile->Label());
2726    // For each of the types, if it has a value, add it to the dictionary.
2727    for (std::map<AutoFillFieldType, std::wstring>::iterator
2728         type_it = autofill_type_to_string.begin();
2729         type_it != autofill_type_to_string.end(); ++type_it) {
2730      string16 value = profile->GetFieldText(AutoFillType(type_it->first));
2731      if (value.length()) {  // If there was something stored for that value.
2732        profile_info->SetStringFromUTF16(type_it->second, value);
2733      }
2734    }
2735    profiles->Append(profile_info);
2736  }
2737  return profiles;
2738}
2739
2740/* static */
2741ListValue* AutomationProvider::GetListFromCreditCards(
2742    std::vector<CreditCard*> credit_cards) {
2743  ListValue* cards = new ListValue;
2744
2745  std::map<AutoFillFieldType, std::wstring> credit_card_type_to_string =
2746      GetCreditCardFieldToStringMap();
2747
2748  // For each AutoFillProfile, transform it to a dictionary object to return.
2749  for (std::vector<CreditCard*>::iterator it = credit_cards.begin();
2750       it != credit_cards.end(); ++it) {
2751    CreditCard* card = *it;
2752    DictionaryValue* card_info = new DictionaryValue;
2753    card_info->SetStringFromUTF16(L"label", card->Label());
2754    // For each of the types, if it has a value, add it to the dictionary.
2755    for (std::map<AutoFillFieldType, std::wstring>::iterator type_it =
2756        credit_card_type_to_string.begin();
2757        type_it != credit_card_type_to_string.end(); ++type_it) {
2758      string16 value = card->GetFieldText(AutoFillType(type_it->first));
2759      // If there was something stored for that value.
2760      if (value.length()) {
2761        card_info->SetStringFromUTF16(type_it->second, value);
2762      }
2763    }
2764    cards->Append(card_info);
2765  }
2766  return cards;
2767}
2768
2769/* static */
2770std::vector<AutoFillProfile> AutomationProvider::GetAutoFillProfilesFromList(
2771    const ListValue& profiles, std::string* error_message) {
2772  std::vector<AutoFillProfile> autofill_profiles;
2773  DictionaryValue* profile_info = NULL;
2774  string16 profile_label;
2775  string16 current_value;
2776
2777  std::map<AutoFillFieldType, std::wstring> autofill_type_to_string =
2778      GetAutoFillFieldToStringMap();
2779
2780  int num_profiles = profiles.GetSize();
2781  for (int i = 0; i < num_profiles; i++) {
2782    profiles.GetDictionary(i, &profile_info);
2783    profile_info->GetString("label", &profile_label);
2784    // Choose an id of 0 so that a unique id will be created.
2785    AutoFillProfile profile(profile_label, 0);
2786    // Loop through the possible profile types and add those provided.
2787    for (std::map<AutoFillFieldType, std::wstring>::iterator type_it =
2788         autofill_type_to_string.begin();
2789         type_it != autofill_type_to_string.end(); ++type_it) {
2790      if (profile_info->HasKey(type_it->second)) {
2791        if (profile_info->GetStringAsUTF16(type_it->second, &current_value)) {
2792          profile.SetInfo(AutoFillType(type_it->first), current_value);
2793        } else {
2794          *error_message= "All values must be strings";
2795          break;
2796        }
2797      }
2798    }
2799    autofill_profiles.push_back(profile);
2800  }
2801  return autofill_profiles;
2802}
2803
2804/* static */
2805std::vector<CreditCard> AutomationProvider::GetCreditCardsFromList(
2806    const ListValue& cards, std::string* error_message) {
2807  std::vector<CreditCard> credit_cards;
2808  DictionaryValue* card_info = NULL;
2809  string16 card_label;
2810  string16 current_value;
2811
2812  std::map<AutoFillFieldType, std::wstring> credit_card_type_to_string =
2813      GetCreditCardFieldToStringMap();
2814
2815  int num_credit_cards = cards.GetSize();
2816  for (int i = 0; i < num_credit_cards; i++) {
2817    cards.GetDictionary(i, &card_info);
2818    card_info->GetString("label", &card_label);
2819    CreditCard card(card_label, 0);
2820    // Loop through the possible credit card fields and add those provided.
2821    for (std::map<AutoFillFieldType, std::wstring>::iterator type_it =
2822        credit_card_type_to_string.begin();
2823        type_it != credit_card_type_to_string.end(); ++type_it) {
2824      if (card_info->HasKey(type_it->second)) {
2825        if (card_info->GetStringAsUTF16(type_it->second, &current_value)) {
2826          card.SetInfo(AutoFillType(type_it->first), current_value);
2827        } else {
2828          *error_message= "All values must be strings";
2829          break;
2830        }
2831      }
2832    }
2833    credit_cards.push_back(card);
2834  }
2835  return credit_cards;
2836}
2837
2838/* static */
2839std::map<AutoFillFieldType, std::wstring>
2840    AutomationProvider::GetAutoFillFieldToStringMap() {
2841  std::map<AutoFillFieldType, std::wstring> autofill_type_to_string;
2842  autofill_type_to_string[NAME_FIRST] = L"NAME_FIRST";
2843  autofill_type_to_string[NAME_MIDDLE] = L"NAME_MIDDLE";
2844  autofill_type_to_string[NAME_LAST] = L"NAME_LAST";
2845  autofill_type_to_string[COMPANY_NAME] = L"COMPANY_NAME";
2846  autofill_type_to_string[EMAIL_ADDRESS] = L"EMAIL_ADDRESS";
2847  autofill_type_to_string[ADDRESS_HOME_LINE1] = L"ADDRESS_HOME_LINE1";
2848  autofill_type_to_string[ADDRESS_HOME_LINE2] = L"ADDRESS_HOME_LINE2";
2849  autofill_type_to_string[ADDRESS_HOME_CITY] = L"ADDRESS_HOME_CITY";
2850  autofill_type_to_string[ADDRESS_HOME_STATE] = L"ADDRESS_HOME_STATE";
2851  autofill_type_to_string[ADDRESS_HOME_ZIP] = L"ADDRESS_HOME_ZIP";
2852  autofill_type_to_string[ADDRESS_HOME_COUNTRY] = L"ADDRESS_HOME_COUNTRY";
2853  autofill_type_to_string[PHONE_HOME_NUMBER] = L"PHONE_HOME_NUMBER";
2854  autofill_type_to_string[PHONE_FAX_NUMBER] = L"PHONE_FAX_NUMBER";
2855  autofill_type_to_string[NAME_FIRST] = L"NAME_FIRST";
2856  return autofill_type_to_string;
2857}
2858
2859/* static */
2860std::map<AutoFillFieldType, std::wstring>
2861    AutomationProvider::GetCreditCardFieldToStringMap() {
2862  std::map<AutoFillFieldType, std::wstring> credit_card_type_to_string;
2863  credit_card_type_to_string[CREDIT_CARD_NAME] = L"CREDIT_CARD_NAME";
2864  credit_card_type_to_string[CREDIT_CARD_NUMBER] = L"CREDIT_CARD_NUMBER";
2865  credit_card_type_to_string[CREDIT_CARD_TYPE] = L"CREDIT_CARD_TYPE";
2866  credit_card_type_to_string[CREDIT_CARD_EXP_MONTH] = L"CREDIT_CARD_EXP_MONTH";
2867  credit_card_type_to_string[CREDIT_CARD_EXP_4_DIGIT_YEAR] =
2868      L"CREDIT_CARD_EXP_4_DIGIT_YEAR";
2869  return credit_card_type_to_string;
2870}
2871
2872void AutomationProvider::SendJSONRequest(int handle,
2873                                         std::string json_request,
2874                                         IPC::Message* reply_message) {
2875  Browser* browser = NULL;
2876  scoped_ptr<Value> values;
2877
2878  // Basic error checking.
2879  if (browser_tracker_->ContainsHandle(handle)) {
2880    browser = browser_tracker_->GetResource(handle);
2881  }
2882  if (!browser) {
2883    AutomationJSONReply(this, reply_message).SendError("no browser object");
2884    return;
2885  }
2886  base::JSONReader reader;
2887  std::string error;
2888  values.reset(reader.ReadAndReturnError(json_request, true, NULL, &error));
2889  if (!error.empty()) {
2890    AutomationJSONReply(this, reply_message).SendError(error);
2891    return;
2892  }
2893
2894  // Make sure input is a dict with a string command.
2895  std::string command;
2896  DictionaryValue* dict_value = NULL;
2897  if (values->GetType() != Value::TYPE_DICTIONARY) {
2898    AutomationJSONReply(this, reply_message).SendError("not a dict");
2899    return;
2900  }
2901  // Ownership remains with "values" variable.
2902  dict_value = static_cast<DictionaryValue*>(values.get());
2903  if (!dict_value->GetStringASCII(std::string("command"), &command)) {
2904    AutomationJSONReply(this, reply_message).SendError(
2905        "no command key in dict or not a string command");
2906    return;
2907  }
2908
2909  // Map json commands to their handlers.
2910  std::map<std::string, JsonHandler> handler_map;
2911  handler_map["DisablePlugin"] = &AutomationProvider::DisablePlugin;
2912  handler_map["EnablePlugin"] = &AutomationProvider::EnablePlugin;
2913  handler_map["GetPluginsInfo"] = &AutomationProvider::GetPluginsInfo;
2914
2915  handler_map["GetBrowserInfo"] = &AutomationProvider::GetBrowserInfo;
2916
2917  handler_map["WaitForInfobarCount"] = &AutomationProvider::WaitForInfobarCount;
2918
2919  handler_map["GetHistoryInfo"] = &AutomationProvider::GetHistoryInfo;
2920  handler_map["AddHistoryItem"] = &AutomationProvider::AddHistoryItem;
2921
2922  handler_map["GetOmniboxInfo"] = &AutomationProvider::GetOmniboxInfo;
2923  handler_map["SetOmniboxText"] = &AutomationProvider::SetOmniboxText;
2924  handler_map["OmniboxAcceptInput"] = &AutomationProvider::OmniboxAcceptInput;
2925  handler_map["OmniboxMovePopupSelection"] =
2926      &AutomationProvider::OmniboxMovePopupSelection;
2927
2928  handler_map["GetPrefsInfo"] = &AutomationProvider::GetPrefsInfo;
2929  handler_map["SetPrefs"] = &AutomationProvider::SetPrefs;
2930
2931  handler_map["SetWindowDimensions"] = &AutomationProvider::SetWindowDimensions;
2932
2933  handler_map["GetDownloadsInfo"] = &AutomationProvider::GetDownloadsInfo;
2934  handler_map["WaitForAllDownloadsToComplete"] =
2935      &AutomationProvider::WaitForDownloadsToComplete;
2936
2937  handler_map["GetInitialLoadTimes"] = &AutomationProvider::GetInitialLoadTimes;
2938
2939  handler_map["SaveTabContents"] = &AutomationProvider::SaveTabContents;
2940
2941  handler_map["ImportSettings"] = &AutomationProvider::ImportSettings;
2942
2943  handler_map["AddSavedPassword"] = &AutomationProvider::AddSavedPassword;
2944  handler_map["GetSavedPasswords"] = &AutomationProvider::GetSavedPasswords;
2945
2946  handler_map["ClearBrowsingData"] = &AutomationProvider::ClearBrowsingData;
2947
2948  // SetTheme() implemented using InstallExtension().
2949  handler_map["GetThemeInfo"] = &AutomationProvider::GetThemeInfo;
2950
2951  handler_map["GetAutoFillProfile"] = &AutomationProvider::GetAutoFillProfile;
2952  handler_map["FillAutoFillProfile"] = &AutomationProvider::FillAutoFillProfile;
2953
2954  if (handler_map.find(std::string(command)) != handler_map.end()) {
2955    (this->*handler_map[command])(browser, dict_value, reply_message);
2956  } else {
2957    std::string error_string = "Unknown command. Options: ";
2958    for (std::map<std::string, JsonHandler>::const_iterator it =
2959         handler_map.begin(); it != handler_map.end(); ++it) {
2960      error_string += it->first + ", ";
2961    }
2962    AutomationJSONReply(this, reply_message).SendError(error_string);
2963  }
2964}
2965
2966void AutomationProvider::HandleInspectElementRequest(
2967    int handle, int x, int y, IPC::Message* reply_message) {
2968  TabContents* tab_contents = GetTabContentsForHandle(handle, NULL);
2969  if (tab_contents) {
2970    DCHECK(reply_message_ == NULL);
2971    reply_message_ = reply_message;
2972
2973    DevToolsManager::GetInstance()->InspectElement(
2974        tab_contents->render_view_host(), x, y);
2975  } else {
2976    AutomationMsg_InspectElement::WriteReplyParams(reply_message, -1);
2977    Send(reply_message);
2978  }
2979}
2980
2981void AutomationProvider::ReceivedInspectElementResponse(int num_resources) {
2982  if (reply_message_) {
2983    AutomationMsg_InspectElement::WriteReplyParams(reply_message_,
2984                                                   num_resources);
2985    Send(reply_message_);
2986    reply_message_ = NULL;
2987  }
2988}
2989
2990class SetProxyConfigTask : public Task {
2991 public:
2992  SetProxyConfigTask(URLRequestContextGetter* request_context_getter,
2993                     const std::string& new_proxy_config)
2994      : request_context_getter_(request_context_getter),
2995        proxy_config_(new_proxy_config) {}
2996  virtual void Run() {
2997    // First, deserialize the JSON string. If this fails, log and bail.
2998    JSONStringValueSerializer deserializer(proxy_config_);
2999    std::string error_msg;
3000    scoped_ptr<Value> root(deserializer.Deserialize(NULL, &error_msg));
3001    if (!root.get() || root->GetType() != Value::TYPE_DICTIONARY) {
3002      DLOG(WARNING) << "Received bad JSON string for ProxyConfig: "
3003                    << error_msg;
3004      return;
3005    }
3006
3007    scoped_ptr<DictionaryValue> dict(
3008        static_cast<DictionaryValue*>(root.release()));
3009    // Now put together a proxy configuration from the deserialized string.
3010    net::ProxyConfig pc;
3011    PopulateProxyConfig(*dict.get(), &pc);
3012
3013    net::ProxyService* proxy_service =
3014        request_context_getter_->GetURLRequestContext()->proxy_service();
3015    DCHECK(proxy_service);
3016    scoped_ptr<net::ProxyConfigService> proxy_config_service(
3017        new net::ProxyConfigServiceFixed(pc));
3018    proxy_service->ResetConfigService(proxy_config_service.release());
3019  }
3020
3021  void PopulateProxyConfig(const DictionaryValue& dict, net::ProxyConfig* pc) {
3022    DCHECK(pc);
3023    bool no_proxy = false;
3024    if (dict.GetBoolean(automation::kJSONProxyNoProxy, &no_proxy)) {
3025      // Make no changes to the ProxyConfig.
3026      return;
3027    }
3028    bool auto_config;
3029    if (dict.GetBoolean(automation::kJSONProxyAutoconfig, &auto_config)) {
3030      pc->set_auto_detect(true);
3031    }
3032    std::string pac_url;
3033    if (dict.GetString(automation::kJSONProxyPacUrl, &pac_url)) {
3034      pc->set_pac_url(GURL(pac_url));
3035    }
3036    std::string proxy_bypass_list;
3037    if (dict.GetString(automation::kJSONProxyBypassList, &proxy_bypass_list)) {
3038      pc->proxy_rules().bypass_rules.ParseFromString(proxy_bypass_list);
3039    }
3040    std::string proxy_server;
3041    if (dict.GetString(automation::kJSONProxyServer, &proxy_server)) {
3042      pc->proxy_rules().ParseFromString(proxy_server);
3043    }
3044  }
3045
3046 private:
3047  scoped_refptr<URLRequestContextGetter> request_context_getter_;
3048  std::string proxy_config_;
3049};
3050
3051
3052void AutomationProvider::SetProxyConfig(const std::string& new_proxy_config) {
3053  URLRequestContextGetter* context_getter = Profile::GetDefaultRequestContext();
3054  if (!context_getter) {
3055    FilePath user_data_dir;
3056    PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
3057    ProfileManager* profile_manager = g_browser_process->profile_manager();
3058    DCHECK(profile_manager);
3059    Profile* profile = profile_manager->GetDefaultProfile(user_data_dir);
3060    DCHECK(profile);
3061    context_getter = profile->GetRequestContext();
3062  }
3063  DCHECK(context_getter);
3064
3065  ChromeThread::PostTask(
3066      ChromeThread::IO, FROM_HERE,
3067      new SetProxyConfigTask(context_getter, new_proxy_config));
3068}
3069
3070void AutomationProvider::GetDownloadDirectory(
3071    int handle, FilePath* download_directory) {
3072  DLOG(INFO) << "Handling download directory request";
3073  if (tab_tracker_->ContainsHandle(handle)) {
3074    NavigationController* tab = tab_tracker_->GetResource(handle);
3075    DownloadManager* dlm = tab->profile()->GetDownloadManager();
3076    DCHECK(dlm);
3077    *download_directory = dlm->download_path();
3078  }
3079}
3080
3081void AutomationProvider::OpenNewBrowserWindow(bool show,
3082                                              IPC::Message* reply_message) {
3083  OpenNewBrowserWindowOfType(static_cast<int>(Browser::TYPE_NORMAL), show,
3084                             reply_message);
3085}
3086
3087void AutomationProvider::OpenNewBrowserWindowOfType(
3088    int type, bool show, IPC::Message* reply_message) {
3089  new BrowserOpenedNotificationObserver(this, reply_message);
3090  // We may have no current browser windows open so don't rely on
3091  // asking an existing browser to execute the IDC_NEWWINDOW command
3092  Browser* browser = new Browser(static_cast<Browser::Type>(type), profile_);
3093  browser->CreateBrowserWindow();
3094  browser->AddBlankTab(true);
3095  if (show)
3096    browser->window()->Show();
3097}
3098
3099void AutomationProvider::GetWindowForBrowser(int browser_handle,
3100                                             bool* success,
3101                                             int* handle) {
3102  *success = false;
3103  *handle = 0;
3104
3105  if (browser_tracker_->ContainsHandle(browser_handle)) {
3106    Browser* browser = browser_tracker_->GetResource(browser_handle);
3107    gfx::NativeWindow win = browser->window()->GetNativeHandle();
3108    // Add() returns the existing handle for the resource if any.
3109    *handle = window_tracker_->Add(win);
3110    *success = true;
3111  }
3112}
3113
3114void AutomationProvider::GetAutocompleteEditForBrowser(
3115    int browser_handle,
3116    bool* success,
3117    int* autocomplete_edit_handle) {
3118  *success = false;
3119  *autocomplete_edit_handle = 0;
3120
3121  if (browser_tracker_->ContainsHandle(browser_handle)) {
3122    Browser* browser = browser_tracker_->GetResource(browser_handle);
3123    LocationBar* loc_bar = browser->window()->GetLocationBar();
3124    AutocompleteEditView* edit_view = loc_bar->location_entry();
3125    // Add() returns the existing handle for the resource if any.
3126    *autocomplete_edit_handle = autocomplete_edit_tracker_->Add(edit_view);
3127    *success = true;
3128  }
3129}
3130
3131void AutomationProvider::ShowInterstitialPage(int tab_handle,
3132                                              const std::string& html_text,
3133                                              IPC::Message* reply_message) {
3134  if (tab_tracker_->ContainsHandle(tab_handle)) {
3135    NavigationController* controller = tab_tracker_->GetResource(tab_handle);
3136    TabContents* tab_contents = controller->tab_contents();
3137
3138    AddNavigationStatusListener(controller, reply_message, 1, false);
3139    AutomationInterstitialPage* interstitial =
3140        new AutomationInterstitialPage(tab_contents,
3141                                       GURL("about:interstitial"),
3142                                       html_text);
3143    interstitial->Show();
3144    return;
3145  }
3146
3147  AutomationMsg_ShowInterstitialPage::WriteReplyParams(
3148      reply_message, AUTOMATION_MSG_NAVIGATION_ERROR);
3149  Send(reply_message);
3150}
3151
3152void AutomationProvider::HideInterstitialPage(int tab_handle,
3153                                              bool* success) {
3154  *success = false;
3155  TabContents* tab_contents = GetTabContentsForHandle(tab_handle, NULL);
3156  if (tab_contents && tab_contents->interstitial_page()) {
3157    tab_contents->interstitial_page()->DontProceed();
3158    *success = true;
3159  }
3160}
3161
3162void AutomationProvider::CloseTab(int tab_handle,
3163                                  bool wait_until_closed,
3164                                  IPC::Message* reply_message) {
3165  if (tab_tracker_->ContainsHandle(tab_handle)) {
3166    NavigationController* controller = tab_tracker_->GetResource(tab_handle);
3167    int index;
3168    Browser* browser = Browser::GetBrowserForController(controller, &index);
3169    DCHECK(browser);
3170    new TabClosedNotificationObserver(this, wait_until_closed, reply_message);
3171    browser->CloseContents(controller->tab_contents());
3172    return;
3173  }
3174
3175  AutomationMsg_CloseTab::WriteReplyParams(reply_message, false);
3176  Send(reply_message);
3177}
3178
3179void AutomationProvider::CloseBrowser(int browser_handle,
3180                                      IPC::Message* reply_message) {
3181  if (browser_tracker_->ContainsHandle(browser_handle)) {
3182    Browser* browser = browser_tracker_->GetResource(browser_handle);
3183    new BrowserClosedNotificationObserver(browser, this,
3184                                          reply_message);
3185    browser->window()->Close();
3186  } else {
3187    NOTREACHED();
3188  }
3189}
3190
3191void AutomationProvider::CloseBrowserAsync(int browser_handle) {
3192  if (browser_tracker_->ContainsHandle(browser_handle)) {
3193    Browser* browser = browser_tracker_->GetResource(browser_handle);
3194    browser->window()->Close();
3195  } else {
3196    NOTREACHED();
3197  }
3198}
3199
3200void AutomationProvider::WaitForTabToBeRestored(int tab_handle,
3201                                                IPC::Message* reply_message) {
3202  if (tab_tracker_->ContainsHandle(tab_handle)) {
3203    NavigationController* tab = tab_tracker_->GetResource(tab_handle);
3204    restore_tracker_.reset(
3205        new NavigationControllerRestoredObserver(this, tab, reply_message));
3206  }
3207}
3208
3209void AutomationProvider::GetSecurityState(int handle, bool* success,
3210                                          SecurityStyle* security_style,
3211                                          int* ssl_cert_status,
3212                                          int* insecure_content_status) {
3213  if (tab_tracker_->ContainsHandle(handle)) {
3214    NavigationController* tab = tab_tracker_->GetResource(handle);
3215    NavigationEntry* entry = tab->GetActiveEntry();
3216    *success = true;
3217    *security_style = entry->ssl().security_style();
3218    *ssl_cert_status = entry->ssl().cert_status();
3219    *insecure_content_status = entry->ssl().content_status();
3220  } else {
3221    *success = false;
3222    *security_style = SECURITY_STYLE_UNKNOWN;
3223    *ssl_cert_status = 0;
3224    *insecure_content_status = 0;
3225  }
3226}
3227
3228void AutomationProvider::GetPageType(int handle, bool* success,
3229                                     NavigationEntry::PageType* page_type) {
3230  if (tab_tracker_->ContainsHandle(handle)) {
3231    NavigationController* tab = tab_tracker_->GetResource(handle);
3232    NavigationEntry* entry = tab->GetActiveEntry();
3233    *page_type = entry->page_type();
3234    *success = true;
3235    // In order to return the proper result when an interstitial is shown and
3236    // no navigation entry were created for it we need to ask the TabContents.
3237    if (*page_type == NavigationEntry::NORMAL_PAGE &&
3238        tab->tab_contents()->showing_interstitial_page())
3239      *page_type = NavigationEntry::INTERSTITIAL_PAGE;
3240  } else {
3241    *success = false;
3242    *page_type = NavigationEntry::NORMAL_PAGE;
3243  }
3244}
3245
3246void AutomationProvider::GetMetricEventDuration(const std::string& event_name,
3247                                                int* duration_ms) {
3248  *duration_ms = metric_event_duration_observer_->GetEventDurationMs(
3249      event_name);
3250}
3251
3252void AutomationProvider::ActionOnSSLBlockingPage(int handle, bool proceed,
3253                                                 IPC::Message* reply_message) {
3254  if (tab_tracker_->ContainsHandle(handle)) {
3255    NavigationController* tab = tab_tracker_->GetResource(handle);
3256    NavigationEntry* entry = tab->GetActiveEntry();
3257    if (entry->page_type() == NavigationEntry::INTERSTITIAL_PAGE) {
3258      TabContents* tab_contents = tab->tab_contents();
3259      InterstitialPage* ssl_blocking_page =
3260          InterstitialPage::GetInterstitialPage(tab_contents);
3261      if (ssl_blocking_page) {
3262        if (proceed) {
3263          AddNavigationStatusListener(tab, reply_message, 1, false);
3264          ssl_blocking_page->Proceed();
3265          return;
3266        }
3267        ssl_blocking_page->DontProceed();
3268        AutomationMsg_ActionOnSSLBlockingPage::WriteReplyParams(
3269            reply_message, AUTOMATION_MSG_NAVIGATION_SUCCESS);
3270        Send(reply_message);
3271        return;
3272      }
3273    }
3274  }
3275  // We failed.
3276  AutomationMsg_ActionOnSSLBlockingPage::WriteReplyParams(
3277      reply_message, AUTOMATION_MSG_NAVIGATION_ERROR);
3278  Send(reply_message);
3279}
3280
3281void AutomationProvider::BringBrowserToFront(int browser_handle,
3282                                             bool* success) {
3283  if (browser_tracker_->ContainsHandle(browser_handle)) {
3284    Browser* browser = browser_tracker_->GetResource(browser_handle);
3285    browser->window()->Activate();
3286    *success = true;
3287  } else {
3288    *success = false;
3289  }
3290}
3291
3292void AutomationProvider::IsMenuCommandEnabled(int browser_handle,
3293                                              int message_num,
3294                                              bool* menu_item_enabled) {
3295  if (browser_tracker_->ContainsHandle(browser_handle)) {
3296    Browser* browser = browser_tracker_->GetResource(browser_handle);
3297    *menu_item_enabled =
3298        browser->command_updater()->IsCommandEnabled(message_num);
3299  } else {
3300    *menu_item_enabled = false;
3301  }
3302}
3303
3304void AutomationProvider::PrintNow(int tab_handle,
3305                                  IPC::Message* reply_message) {
3306  NavigationController* tab = NULL;
3307  TabContents* tab_contents = GetTabContentsForHandle(tab_handle, &tab);
3308  if (tab_contents) {
3309    FindAndActivateTab(tab);
3310    notification_observer_list_.AddObserver(
3311        new DocumentPrintedNotificationObserver(this, reply_message));
3312    if (tab_contents->PrintNow())
3313      return;
3314  }
3315  AutomationMsg_PrintNow::WriteReplyParams(reply_message, false);
3316  Send(reply_message);
3317}
3318
3319void AutomationProvider::SavePage(int tab_handle,
3320                                  const FilePath& file_name,
3321                                  const FilePath& dir_path,
3322                                  int type,
3323                                  bool* success) {
3324  if (!tab_tracker_->ContainsHandle(tab_handle)) {
3325    *success = false;
3326    return;
3327  }
3328
3329  NavigationController* nav = tab_tracker_->GetResource(tab_handle);
3330  Browser* browser = FindAndActivateTab(nav);
3331  DCHECK(browser);
3332  if (!browser->command_updater()->IsCommandEnabled(IDC_SAVE_PAGE)) {
3333    *success = false;
3334    return;
3335  }
3336
3337  SavePackage::SavePackageType save_type =
3338      static_cast<SavePackage::SavePackageType>(type);
3339  DCHECK(save_type >= SavePackage::SAVE_AS_ONLY_HTML &&
3340         save_type <= SavePackage::SAVE_AS_COMPLETE_HTML);
3341  nav->tab_contents()->SavePage(file_name, dir_path, save_type);
3342
3343  *success = true;
3344}
3345
3346void AutomationProvider::GetAutocompleteEditText(int autocomplete_edit_handle,
3347                                                 bool* success,
3348                                                 std::wstring* text) {
3349  *success = false;
3350  if (autocomplete_edit_tracker_->ContainsHandle(autocomplete_edit_handle)) {
3351    *text = autocomplete_edit_tracker_->GetResource(autocomplete_edit_handle)->
3352        GetText();
3353    *success = true;
3354  }
3355}
3356
3357void AutomationProvider::SetAutocompleteEditText(int autocomplete_edit_handle,
3358                                                 const std::wstring& text,
3359                                                 bool* success) {
3360  *success = false;
3361  if (autocomplete_edit_tracker_->ContainsHandle(autocomplete_edit_handle)) {
3362    autocomplete_edit_tracker_->GetResource(autocomplete_edit_handle)->
3363        SetUserText(text);
3364    *success = true;
3365  }
3366}
3367
3368void AutomationProvider::AutocompleteEditGetMatches(
3369    int autocomplete_edit_handle,
3370    bool* success,
3371    std::vector<AutocompleteMatchData>* matches) {
3372  *success = false;
3373  if (autocomplete_edit_tracker_->ContainsHandle(autocomplete_edit_handle)) {
3374    const AutocompleteResult& result = autocomplete_edit_tracker_->
3375        GetResource(autocomplete_edit_handle)->model()->result();
3376    for (AutocompleteResult::const_iterator i = result.begin();
3377        i != result.end(); ++i)
3378      matches->push_back(AutocompleteMatchData(*i));
3379    *success = true;
3380  }
3381}
3382
3383void AutomationProvider::AutocompleteEditIsQueryInProgress(
3384    int autocomplete_edit_handle,
3385    bool* success,
3386    bool* query_in_progress) {
3387  *success = false;
3388  *query_in_progress = false;
3389  if (autocomplete_edit_tracker_->ContainsHandle(autocomplete_edit_handle)) {
3390    *query_in_progress = autocomplete_edit_tracker_->
3391        GetResource(autocomplete_edit_handle)->model()->query_in_progress();
3392    *success = true;
3393  }
3394}
3395
3396#if !defined(OS_MACOSX)
3397
3398#endif  // !defined(OS_MACOSX)
3399
3400TabContents* AutomationProvider::GetTabContentsForHandle(
3401    int handle, NavigationController** tab) {
3402  if (tab_tracker_->ContainsHandle(handle)) {
3403    NavigationController* nav_controller = tab_tracker_->GetResource(handle);
3404    if (tab)
3405      *tab = nav_controller;
3406    return nav_controller->tab_contents();
3407  }
3408  return NULL;
3409}
3410
3411TestingAutomationProvider::TestingAutomationProvider(Profile* profile)
3412    : AutomationProvider(profile) {
3413  BrowserList::AddObserver(this);
3414  registrar_.Add(this, NotificationType::SESSION_END,
3415                 NotificationService::AllSources());
3416}
3417
3418TestingAutomationProvider::~TestingAutomationProvider() {
3419  BrowserList::RemoveObserver(this);
3420}
3421
3422void TestingAutomationProvider::OnChannelError() {
3423  BrowserList::CloseAllBrowsersAndExit();
3424  AutomationProvider::OnChannelError();
3425}
3426
3427void TestingAutomationProvider::OnBrowserAdded(const Browser* browser) {
3428}
3429
3430void TestingAutomationProvider::OnBrowserRemoving(const Browser* browser) {
3431  // For backwards compatibility with the testing automation interface, we
3432  // want the automation provider (and hence the process) to go away when the
3433  // last browser goes away.
3434  if (BrowserList::size() == 1 && !CommandLine::ForCurrentProcess()->HasSwitch(
3435          switches::kKeepAliveForTest)) {
3436    // If you change this, update Observer for NotificationType::SESSION_END
3437    // below.
3438    MessageLoop::current()->PostTask(FROM_HERE,
3439        NewRunnableMethod(this, &TestingAutomationProvider::OnRemoveProvider));
3440  }
3441}
3442
3443void TestingAutomationProvider::Observe(NotificationType type,
3444                                        const NotificationSource& source,
3445                                        const NotificationDetails& details) {
3446  DCHECK(type == NotificationType::SESSION_END);
3447  // OnBrowserRemoving does a ReleaseLater. When session end is received we exit
3448  // before the task runs resulting in this object not being deleted. This
3449  // Release balance out the Release scheduled by OnBrowserRemoving.
3450  Release();
3451}
3452
3453void TestingAutomationProvider::OnRemoveProvider() {
3454  AutomationProviderList::GetInstance()->RemoveProvider(this);
3455}
3456
3457void AutomationProvider::GetInfoBarCount(int handle, int* count) {
3458  *count = -1;  // -1 means error.
3459  if (tab_tracker_->ContainsHandle(handle)) {
3460    NavigationController* nav_controller = tab_tracker_->GetResource(handle);
3461    if (nav_controller)
3462      *count = nav_controller->tab_contents()->infobar_delegate_count();
3463  }
3464}
3465
3466void AutomationProvider::ClickInfoBarAccept(int handle,
3467                                            int info_bar_index,
3468                                            bool wait_for_navigation,
3469                                            IPC::Message* reply_message) {
3470  bool success = false;
3471  if (tab_tracker_->ContainsHandle(handle)) {
3472    NavigationController* nav_controller = tab_tracker_->GetResource(handle);
3473    if (nav_controller) {
3474      int count = nav_controller->tab_contents()->infobar_delegate_count();
3475      if (info_bar_index >= 0 && info_bar_index < count) {
3476        if (wait_for_navigation) {
3477          AddNavigationStatusListener(nav_controller, reply_message, 1, false);
3478        }
3479        InfoBarDelegate* delegate =
3480            nav_controller->tab_contents()->GetInfoBarDelegateAt(
3481                info_bar_index);
3482        if (delegate->AsConfirmInfoBarDelegate())
3483          delegate->AsConfirmInfoBarDelegate()->Accept();
3484        success = true;
3485      }
3486    }
3487  }
3488
3489  // This "!wait_for_navigation || !success condition" logic looks suspicious.
3490  // It will send a failure message when success is true but
3491  // |wait_for_navigation| is false.
3492  // TODO(phajdan.jr): investgate whether the reply param (currently
3493  // AUTOMATION_MSG_NAVIGATION_ERROR) should depend on success.
3494  if (!wait_for_navigation || !success)
3495    AutomationMsg_ClickInfoBarAccept::WriteReplyParams(
3496        reply_message, AUTOMATION_MSG_NAVIGATION_ERROR);
3497}
3498
3499void AutomationProvider::GetLastNavigationTime(int handle,
3500                                               int64* last_navigation_time) {
3501  Time time = tab_tracker_->GetLastNavigationTime(handle);
3502  *last_navigation_time = time.ToInternalValue();
3503}
3504
3505void AutomationProvider::WaitForNavigation(int handle,
3506                                           int64 last_navigation_time,
3507                                           IPC::Message* reply_message) {
3508  NavigationController* controller = tab_tracker_->GetResource(handle);
3509  Time time = tab_tracker_->GetLastNavigationTime(handle);
3510
3511  if (time.ToInternalValue() > last_navigation_time || !controller) {
3512    AutomationMsg_WaitForNavigation::WriteReplyParams(reply_message,
3513        controller == NULL ? AUTOMATION_MSG_NAVIGATION_ERROR :
3514                             AUTOMATION_MSG_NAVIGATION_SUCCESS);
3515    Send(reply_message);
3516    return;
3517  }
3518
3519  AddNavigationStatusListener(controller, reply_message, 1, true);
3520}
3521
3522void AutomationProvider::SetIntPreference(int handle,
3523                                          const std::wstring& name,
3524                                          int value,
3525                                          bool* success) {
3526  *success = false;
3527  if (browser_tracker_->ContainsHandle(handle)) {
3528    Browser* browser = browser_tracker_->GetResource(handle);
3529    browser->profile()->GetPrefs()->SetInteger(name.c_str(), value);
3530    *success = true;
3531  }
3532}
3533
3534void AutomationProvider::SetStringPreference(int handle,
3535                                             const std::wstring& name,
3536                                             const std::string& value,
3537                                             bool* success) {
3538  *success = false;
3539  if (browser_tracker_->ContainsHandle(handle)) {
3540    Browser* browser = browser_tracker_->GetResource(handle);
3541    browser->profile()->GetPrefs()->SetString(name.c_str(), value);
3542    *success = true;
3543  }
3544}
3545
3546void AutomationProvider::GetBooleanPreference(int handle,
3547                                              const std::wstring& name,
3548                                              bool* success,
3549                                              bool* value) {
3550  *success = false;
3551  *value = false;
3552  if (browser_tracker_->ContainsHandle(handle)) {
3553    Browser* browser = browser_tracker_->GetResource(handle);
3554    *value = browser->profile()->GetPrefs()->GetBoolean(name.c_str());
3555    *success = true;
3556  }
3557}
3558
3559void AutomationProvider::SetBooleanPreference(int handle,
3560                                              const std::wstring& name,
3561                                              bool value,
3562                                              bool* success) {
3563  *success = false;
3564  if (browser_tracker_->ContainsHandle(handle)) {
3565    Browser* browser = browser_tracker_->GetResource(handle);
3566    browser->profile()->GetPrefs()->SetBoolean(name.c_str(), value);
3567    *success = true;
3568  }
3569}
3570
3571// Gets the current used encoding name of the page in the specified tab.
3572void AutomationProvider::GetPageCurrentEncoding(
3573    int tab_handle, std::string* current_encoding) {
3574  if (tab_tracker_->ContainsHandle(tab_handle)) {
3575    NavigationController* nav = tab_tracker_->GetResource(tab_handle);
3576    Browser* browser = FindAndActivateTab(nav);
3577    DCHECK(browser);
3578
3579    if (browser->command_updater()->IsCommandEnabled(IDC_ENCODING_MENU))
3580      *current_encoding = nav->tab_contents()->encoding();
3581  }
3582}
3583
3584// Gets the current used encoding name of the page in the specified tab.
3585void AutomationProvider::OverrideEncoding(int tab_handle,
3586                                          const std::string& encoding_name,
3587                                          bool* success) {
3588  *success = false;
3589  if (tab_tracker_->ContainsHandle(tab_handle)) {
3590    NavigationController* nav = tab_tracker_->GetResource(tab_handle);
3591    if (!nav)
3592      return;
3593    Browser* browser = FindAndActivateTab(nav);
3594
3595    // If the browser has UI, simulate what a user would do.
3596    // Activate the tab and then click the encoding menu.
3597    if (browser &&
3598        browser->command_updater()->IsCommandEnabled(IDC_ENCODING_MENU)) {
3599      int selected_encoding_id =
3600          CharacterEncoding::GetCommandIdByCanonicalEncodingName(encoding_name);
3601      if (selected_encoding_id) {
3602        browser->OverrideEncoding(selected_encoding_id);
3603        *success = true;
3604      }
3605    } else {
3606      // There is no UI, Chrome probably runs as Chrome-Frame mode.
3607      // Try to get TabContents and call its override_encoding method.
3608      TabContents* contents = nav->tab_contents();
3609      if (!contents)
3610        return;
3611      const std::string selected_encoding =
3612          CharacterEncoding::GetCanonicalEncodingNameByAliasName(encoding_name);
3613      if (selected_encoding.empty())
3614        return;
3615      contents->SetOverrideEncoding(selected_encoding);
3616    }
3617  }
3618}
3619
3620void AutomationProvider::SavePackageShouldPromptUser(bool should_prompt) {
3621  SavePackage::SetShouldPromptUser(should_prompt);
3622}
3623
3624void AutomationProvider::GetBlockedPopupCount(int handle, int* count) {
3625  *count = -1;  // -1 is the error code
3626  if (tab_tracker_->ContainsHandle(handle)) {
3627      NavigationController* nav_controller = tab_tracker_->GetResource(handle);
3628      TabContents* tab_contents = nav_controller->tab_contents();
3629      if (tab_contents) {
3630        BlockedPopupContainer* container =
3631            tab_contents->blocked_popup_container();
3632        if (container) {
3633          *count = static_cast<int>(container->GetBlockedPopupCount());
3634        } else {
3635          // If we don't have a container, we don't have any blocked popups to
3636          // contain!
3637          *count = 0;
3638        }
3639      }
3640  }
3641}
3642
3643void AutomationProvider::SelectAll(int tab_handle) {
3644  RenderViewHost* view = GetViewForTab(tab_handle);
3645  if (!view) {
3646    NOTREACHED();
3647    return;
3648  }
3649
3650  view->SelectAll();
3651}
3652
3653void AutomationProvider::Cut(int tab_handle) {
3654  RenderViewHost* view = GetViewForTab(tab_handle);
3655  if (!view) {
3656    NOTREACHED();
3657    return;
3658  }
3659
3660  view->Cut();
3661}
3662
3663void AutomationProvider::Copy(int tab_handle) {
3664  RenderViewHost* view = GetViewForTab(tab_handle);
3665  if (!view) {
3666    NOTREACHED();
3667    return;
3668  }
3669
3670  view->Copy();
3671}
3672
3673void AutomationProvider::Paste(int tab_handle) {
3674  RenderViewHost* view = GetViewForTab(tab_handle);
3675  if (!view) {
3676    NOTREACHED();
3677    return;
3678  }
3679
3680  view->Paste();
3681}
3682
3683void AutomationProvider::ReloadAsync(int tab_handle) {
3684  if (tab_tracker_->ContainsHandle(tab_handle)) {
3685    NavigationController* tab = tab_tracker_->GetResource(tab_handle);
3686    if (!tab) {
3687      NOTREACHED();
3688      return;
3689    }
3690
3691    const bool check_for_repost = true;
3692    tab->Reload(check_for_repost);
3693  }
3694}
3695
3696void AutomationProvider::StopAsync(int tab_handle) {
3697  RenderViewHost* view = GetViewForTab(tab_handle);
3698  if (!view) {
3699    // We tolerate StopAsync being called even before a view has been created.
3700    // So just log a warning instead of a NOTREACHED().
3701    DLOG(WARNING) << "StopAsync: no view for handle " << tab_handle;
3702    return;
3703  }
3704
3705  view->Stop();
3706}
3707
3708void AutomationProvider::OnSetPageFontSize(int tab_handle,
3709                                           int font_size) {
3710  AutomationPageFontSize automation_font_size =
3711      static_cast<AutomationPageFontSize>(font_size);
3712
3713  if (automation_font_size < SMALLEST_FONT ||
3714      automation_font_size > LARGEST_FONT) {
3715      DLOG(ERROR) << "Invalid font size specified : "
3716                  << font_size;
3717      return;
3718  }
3719
3720  if (tab_tracker_->ContainsHandle(tab_handle)) {
3721    NavigationController* tab = tab_tracker_->GetResource(tab_handle);
3722    DCHECK(tab != NULL);
3723    if (tab && tab->tab_contents()) {
3724      DCHECK(tab->tab_contents()->profile() != NULL);
3725      tab->tab_contents()->profile()->GetPrefs()->SetInteger(
3726          prefs::kWebKitDefaultFontSize, font_size);
3727    }
3728  }
3729}
3730
3731void AutomationProvider::RemoveBrowsingData(int remove_mask) {
3732  BrowsingDataRemover* remover;
3733  remover = new BrowsingDataRemover(profile(),
3734      BrowsingDataRemover::EVERYTHING,  // All time periods.
3735      base::Time());
3736  remover->Remove(remove_mask);
3737  // BrowsingDataRemover deletes itself.
3738}
3739
3740void AutomationProvider::WaitForBrowserWindowCountToBecome(
3741    int target_count, IPC::Message* reply_message) {
3742  if (static_cast<int>(BrowserList::size()) == target_count) {
3743    AutomationMsg_WaitForBrowserWindowCountToBecome::WriteReplyParams(
3744        reply_message, true);
3745    Send(reply_message);
3746    return;
3747  }
3748
3749  // Set up an observer (it will delete itself).
3750  new BrowserCountChangeNotificationObserver(target_count, this, reply_message);
3751}
3752
3753void AutomationProvider::WaitForAppModalDialogToBeShown(
3754    IPC::Message* reply_message) {
3755  if (Singleton<AppModalDialogQueue>()->HasActiveDialog()) {
3756    AutomationMsg_WaitForAppModalDialogToBeShown::WriteReplyParams(
3757        reply_message, true);
3758    Send(reply_message);
3759    return;
3760  }
3761
3762  // Set up an observer (it will delete itself).
3763  new AppModalDialogShownObserver(this, reply_message);
3764}
3765
3766void AutomationProvider::GoBackBlockUntilNavigationsComplete(
3767    int handle, int number_of_navigations, IPC::Message* reply_message) {
3768  if (tab_tracker_->ContainsHandle(handle)) {
3769    NavigationController* tab = tab_tracker_->GetResource(handle);
3770    Browser* browser = FindAndActivateTab(tab);
3771    if (browser && browser->command_updater()->IsCommandEnabled(IDC_BACK)) {
3772      AddNavigationStatusListener(tab, reply_message, number_of_navigations,
3773                                  false);
3774      browser->GoBack(CURRENT_TAB);
3775      return;
3776    }
3777  }
3778
3779  AutomationMsg_GoBackBlockUntilNavigationsComplete::WriteReplyParams(
3780      reply_message, AUTOMATION_MSG_NAVIGATION_ERROR);
3781  Send(reply_message);
3782}
3783
3784void AutomationProvider::GoForwardBlockUntilNavigationsComplete(
3785    int handle, int number_of_navigations, IPC::Message* reply_message) {
3786  if (tab_tracker_->ContainsHandle(handle)) {
3787    NavigationController* tab = tab_tracker_->GetResource(handle);
3788    Browser* browser = FindAndActivateTab(tab);
3789    if (browser && browser->command_updater()->IsCommandEnabled(IDC_FORWARD)) {
3790      AddNavigationStatusListener(tab, reply_message, number_of_navigations,
3791                                  false);
3792      browser->GoForward(CURRENT_TAB);
3793      return;
3794    }
3795  }
3796
3797  AutomationMsg_GoForwardBlockUntilNavigationsComplete::WriteReplyParams(
3798      reply_message, AUTOMATION_MSG_NAVIGATION_ERROR);
3799  Send(reply_message);
3800}
3801
3802RenderViewHost* AutomationProvider::GetViewForTab(int tab_handle) {
3803  if (tab_tracker_->ContainsHandle(tab_handle)) {
3804    NavigationController* tab = tab_tracker_->GetResource(tab_handle);
3805    if (!tab) {
3806      NOTREACHED();
3807      return NULL;
3808    }
3809
3810    TabContents* tab_contents = tab->tab_contents();
3811    if (!tab_contents) {
3812      NOTREACHED();
3813      return NULL;
3814    }
3815
3816    RenderViewHost* view_host = tab_contents->render_view_host();
3817    return view_host;
3818  }
3819
3820  return NULL;
3821}
3822
3823void AutomationProvider::GetBrowserForWindow(int window_handle,
3824                                             bool* success,
3825                                             int* browser_handle) {
3826  *success = false;
3827  *browser_handle = 0;
3828
3829  gfx::NativeWindow window = window_tracker_->GetResource(window_handle);
3830  if (!window)
3831    return;
3832
3833  BrowserList::const_iterator iter = BrowserList::begin();
3834  for (;iter != BrowserList::end(); ++iter) {
3835    gfx::NativeWindow this_window = (*iter)->window()->GetNativeHandle();
3836    if (window == this_window) {
3837      // Add() returns the existing handle for the resource if any.
3838      *browser_handle = browser_tracker_->Add(*iter);
3839      *success = true;
3840      return;
3841    }
3842  }
3843}
3844
3845void AutomationProvider::InstallExtension(const FilePath& crx_path,
3846                                          IPC::Message* reply_message) {
3847  ExtensionsService* service = profile_->GetExtensionsService();
3848  if (service) {
3849    // The observer will delete itself when done.
3850    new ExtensionInstallNotificationObserver(this,
3851                                             AutomationMsg_InstallExtension::ID,
3852                                             reply_message);
3853
3854    const FilePath& install_dir = service->install_directory();
3855    scoped_refptr<CrxInstaller> installer(
3856        new CrxInstaller(install_dir,
3857                         service,
3858                         NULL));  // silent install, no UI
3859    installer->set_allow_privilege_increase(true);
3860    installer->InstallCrx(crx_path);
3861  } else {
3862    AutomationMsg_InstallExtension::WriteReplyParams(
3863        reply_message, AUTOMATION_MSG_EXTENSION_INSTALL_FAILED);
3864    Send(reply_message);
3865  }
3866}
3867
3868void AutomationProvider::LoadExpandedExtension(
3869    const FilePath& extension_dir,
3870    IPC::Message* reply_message) {
3871  if (profile_->GetExtensionsService()) {
3872    // The observer will delete itself when done.
3873    new ExtensionInstallNotificationObserver(
3874        this,
3875        AutomationMsg_LoadExpandedExtension::ID,
3876        reply_message);
3877
3878    profile_->GetExtensionsService()->LoadExtension(extension_dir);
3879  } else {
3880    AutomationMsg_LoadExpandedExtension::WriteReplyParams(
3881        reply_message, AUTOMATION_MSG_EXTENSION_INSTALL_FAILED);
3882    Send(reply_message);
3883  }
3884}
3885
3886void AutomationProvider::GetEnabledExtensions(
3887    std::vector<FilePath>* result) {
3888  ExtensionsService* service = profile_->GetExtensionsService();
3889  DCHECK(service);
3890  if (service->extensions_enabled()) {
3891    const ExtensionList* extensions = service->extensions();
3892    DCHECK(extensions);
3893    for (size_t i = 0; i < extensions->size(); ++i) {
3894      Extension* extension = (*extensions)[i];
3895      DCHECK(extension);
3896      if (extension->location() == Extension::INTERNAL ||
3897          extension->location() == Extension::LOAD) {
3898        result->push_back(extension->path());
3899      }
3900    }
3901  }
3902}
3903
3904void AutomationProvider::WaitForExtensionTestResult(
3905    IPC::Message* reply_message) {
3906  DCHECK(reply_message_ == NULL);
3907  reply_message_ = reply_message;
3908  // Call MaybeSendResult, because the result might have come in before
3909  // we were waiting on it.
3910  extension_test_result_observer_->MaybeSendResult();
3911}
3912
3913void AutomationProvider::InstallExtensionAndGetHandle(
3914    const FilePath& crx_path, bool with_ui, IPC::Message* reply_message) {
3915  ExtensionsService* service = profile_->GetExtensionsService();
3916  ExtensionProcessManager* manager = profile_->GetExtensionProcessManager();
3917  if (service && manager) {
3918    // The observer will delete itself when done.
3919    new ExtensionReadyNotificationObserver(
3920        manager,
3921        this,
3922        AutomationMsg_InstallExtensionAndGetHandle::ID,
3923        reply_message);
3924
3925    ExtensionInstallUI* client =
3926        (with_ui ? new ExtensionInstallUI(profile_) : NULL);
3927    scoped_refptr<CrxInstaller> installer(
3928        new CrxInstaller(service->install_directory(),
3929                         service,
3930                         client));
3931    installer->set_allow_privilege_increase(true);
3932    installer->InstallCrx(crx_path);
3933  } else {
3934    AutomationMsg_InstallExtensionAndGetHandle::WriteReplyParams(
3935        reply_message, 0);
3936    Send(reply_message);
3937  }
3938}
3939
3940void AutomationProvider::UninstallExtension(int extension_handle,
3941                                            bool* success) {
3942  *success = false;
3943  Extension* extension = GetExtension(extension_handle);
3944  ExtensionsService* service = profile_->GetExtensionsService();
3945  if (extension && service) {
3946    ExtensionUnloadNotificationObserver observer;
3947    service->UninstallExtension(extension->id(), false);
3948    // The extension unload notification should have been sent synchronously
3949    // with the uninstall. Just to be safe, check that it was received.
3950    *success = observer.did_receive_unload_notification();
3951  }
3952}
3953
3954void AutomationProvider::EnableExtension(int extension_handle,
3955                                         IPC::Message* reply_message) {
3956  Extension* extension = GetDisabledExtension(extension_handle);
3957  ExtensionsService* service = profile_->GetExtensionsService();
3958  ExtensionProcessManager* manager = profile_->GetExtensionProcessManager();
3959  // Only enable if this extension is disabled.
3960  if (extension && service && manager) {
3961    // The observer will delete itself when done.
3962    new ExtensionReadyNotificationObserver(
3963        manager,
3964        this,
3965        AutomationMsg_EnableExtension::ID,
3966        reply_message);
3967    service->EnableExtension(extension->id());
3968  } else {
3969    AutomationMsg_EnableExtension::WriteReplyParams(reply_message, false);
3970    Send(reply_message);
3971  }
3972}
3973
3974void AutomationProvider::DisableExtension(int extension_handle,
3975                                          bool* success) {
3976  *success = false;
3977  Extension* extension = GetEnabledExtension(extension_handle);
3978  ExtensionsService* service = profile_->GetExtensionsService();
3979  if (extension && service) {
3980    ExtensionUnloadNotificationObserver observer;
3981    service->DisableExtension(extension->id());
3982    // The extension unload notification should have been sent synchronously
3983    // with the disable. Just to be safe, check that it was received.
3984    *success = observer.did_receive_unload_notification();
3985  }
3986}
3987
3988void AutomationProvider::ExecuteExtensionActionInActiveTabAsync(
3989    int extension_handle, int browser_handle,
3990    IPC::Message* reply_message) {
3991  bool success = false;
3992  Extension* extension = GetEnabledExtension(extension_handle);
3993  ExtensionsService* service = profile_->GetExtensionsService();
3994  ExtensionMessageService* message_service =
3995      profile_->GetExtensionMessageService();
3996  Browser* browser = browser_tracker_->GetResource(browser_handle);
3997  if (extension && service && message_service && browser) {
3998    int tab_id = ExtensionTabUtil::GetTabId(browser->GetSelectedTabContents());
3999    if (extension->page_action()) {
4000      ExtensionBrowserEventRouter::GetInstance()->PageActionExecuted(
4001          browser->profile(), extension->id(), "action", tab_id, "", 1);
4002      success = true;
4003    } else if (extension->browser_action()) {
4004      ExtensionBrowserEventRouter::GetInstance()->BrowserActionExecuted(
4005          browser->profile(), extension->id(), browser);
4006      success = true;
4007    }
4008  }
4009  AutomationMsg_ExecuteExtensionActionInActiveTabAsync::WriteReplyParams(
4010      reply_message, success);
4011  Send(reply_message);
4012}
4013
4014void AutomationProvider::MoveExtensionBrowserAction(
4015    int extension_handle, int index, bool* success) {
4016  *success = false;
4017  Extension* extension = GetEnabledExtension(extension_handle);
4018  ExtensionsService* service = profile_->GetExtensionsService();
4019  if (extension && service) {
4020    ExtensionToolbarModel* toolbar = service->toolbar_model();
4021    if (toolbar) {
4022      if (index >= 0 && index < static_cast<int>(toolbar->size())) {
4023        toolbar->MoveBrowserAction(extension, index);
4024        *success = true;
4025      } else {
4026        DLOG(WARNING) << "Attempted to move browser action to invalid index.";
4027      }
4028    }
4029  }
4030}
4031
4032void AutomationProvider::GetExtensionProperty(
4033    int extension_handle,
4034    AutomationMsg_ExtensionProperty type,
4035    bool* success,
4036    std::string* value) {
4037  *success = false;
4038  Extension* extension = GetExtension(extension_handle);
4039  ExtensionsService* service = profile_->GetExtensionsService();
4040  if (extension && service) {
4041    ExtensionToolbarModel* toolbar = service->toolbar_model();
4042    int found_index = -1;
4043    int index = 0;
4044    switch (type) {
4045      case AUTOMATION_MSG_EXTENSION_ID:
4046        *value = extension->id();
4047        *success = true;
4048        break;
4049      case AUTOMATION_MSG_EXTENSION_NAME:
4050        *value = extension->name();
4051        *success = true;
4052        break;
4053      case AUTOMATION_MSG_EXTENSION_VERSION:
4054        *value = extension->VersionString();
4055        *success = true;
4056        break;
4057      case AUTOMATION_MSG_EXTENSION_BROWSER_ACTION_INDEX:
4058        if (toolbar) {
4059          for (ExtensionList::const_iterator iter = toolbar->begin();
4060               iter != toolbar->end(); iter++) {
4061            // Skip this extension if we are in incognito mode
4062            // and it is not incognito-enabled.
4063            if (profile_->IsOffTheRecord() &&
4064                !service->IsIncognitoEnabled(*iter))
4065              continue;
4066            if (*iter == extension) {
4067              found_index = index;
4068              break;
4069            }
4070            index++;
4071          }
4072          *value = IntToString(found_index);
4073          *success = true;
4074        }
4075        break;
4076      default:
4077        LOG(WARNING) << "Trying to get undefined extension property";
4078        break;
4079    }
4080  }
4081}
4082
4083void AutomationProvider::SaveAsAsync(int tab_handle) {
4084  NavigationController* tab = NULL;
4085  TabContents* tab_contents = GetTabContentsForHandle(tab_handle, &tab);
4086  if (tab_contents)
4087    tab_contents->OnSavePage();
4088}
4089
4090void AutomationProvider::SetContentSetting(
4091    int handle,
4092    const std::string& host,
4093    ContentSettingsType content_type,
4094    ContentSetting setting,
4095    bool* success) {
4096  *success = false;
4097  if (browser_tracker_->ContainsHandle(handle)) {
4098    Browser* browser = browser_tracker_->GetResource(handle);
4099    HostContentSettingsMap* map =
4100        browser->profile()->GetHostContentSettingsMap();
4101    if (host.empty()) {
4102      map->SetDefaultContentSetting(content_type, setting);
4103    } else {
4104      map->SetContentSetting(HostContentSettingsMap::Pattern(host),
4105                             content_type, setting);
4106    }
4107    *success = true;
4108  }
4109}
4110
4111#if !defined(TOOLKIT_VIEWS)
4112void AutomationProvider::GetFocusedViewID(int handle, int* view_id) {
4113  NOTIMPLEMENTED();
4114};
4115
4116void AutomationProvider::WaitForFocusedViewIDToChange(
4117    int handle, int previous_view_id, IPC::Message* reply_message) {
4118  NOTIMPLEMENTED();
4119}
4120
4121void AutomationProvider::StartTrackingPopupMenus(
4122    int browser_handle, bool* success) {
4123  NOTIMPLEMENTED();
4124}
4125
4126void AutomationProvider::WaitForPopupMenuToOpen(IPC::Message* reply_message) {
4127  NOTIMPLEMENTED();
4128}
4129#endif  // !defined(TOOLKIT_VIEWS)
4130
4131void AutomationProvider::ResetToDefaultTheme() {
4132  profile_->ClearTheme();
4133}
4134