blob: 3592d6ae5bc4b5160650458adf4e682f80f08958 [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/automation/testing_automation_provider.h"
#include <map>
#include <set>
#include <string>
#include <vector>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/json/string_escape.h"
#include "base/path_service.h"
#include "base/prefs/pref_service.h"
#include "base/process/process.h"
#include "base/process/process_iterator.h"
#include "base/sequenced_task_runner.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_restrictions.h"
#include "base/time/time.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/autocomplete/autocomplete_controller.h"
#include "chrome/browser/autocomplete/autocomplete_match.h"
#include "chrome/browser/autocomplete/autocomplete_result.h"
#include "chrome/browser/automation/automation_browser_tracker.h"
#include "chrome/browser/automation/automation_provider_json.h"
#include "chrome/browser/automation/automation_provider_list.h"
#include "chrome/browser/automation/automation_provider_observers.h"
#include "chrome/browser/automation/automation_tab_tracker.h"
#include "chrome/browser/automation/automation_util.h"
#include "chrome/browser/automation/automation_window_tracker.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/bookmarks/bookmark_model_factory.h"
#include "chrome/browser/bookmarks/bookmark_storage.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_shutdown.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/content_settings/host_content_settings_map.h"
#include "chrome/browser/devtools/devtools_window.h"
#include "chrome/browser/download/download_prefs.h"
#include "chrome/browser/download/download_service.h"
#include "chrome/browser/download/download_service_factory.h"
#include "chrome/browser/download/download_shelf.h"
#include "chrome/browser/download/save_package_file_picker.h"
#include "chrome/browser/extensions/browser_action_test_util.h"
#include "chrome/browser/extensions/crx_installer.h"
#include "chrome/browser/extensions/extension_action.h"
#include "chrome/browser/extensions/extension_action_manager.h"
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_process_manager.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_system.h"
#include "chrome/browser/extensions/extension_tab_util.h"
#include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/extensions/unpacked_installer.h"
#include "chrome/browser/extensions/updater/extension_updater.h"
#include "chrome/browser/history/history_service_factory.h"
#include "chrome/browser/history/top_sites.h"
#include "chrome/browser/infobars/confirm_infobar_delegate.h"
#include "chrome/browser/infobars/infobar_service.h"
#include "chrome/browser/lifetime/application_lifetime.h"
#include "chrome/browser/notifications/balloon.h"
#include "chrome/browser/notifications/balloon_collection.h"
#include "chrome/browser/notifications/balloon_notification_ui_manager.h"
#include "chrome/browser/notifications/notification.h"
#include "chrome/browser/password_manager/password_store.h"
#include "chrome/browser/password_manager/password_store_change.h"
#include "chrome/browser/password_manager/password_store_factory.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/plugins/plugin_prefs.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_info_cache.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/profiles/profile_window.h"
#include "chrome/browser/profiles/profiles_state.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_service.h"
#include "chrome/browser/search_engines/template_url_service_factory.h"
#include "chrome/browser/sessions/session_service_factory.h"
#include "chrome/browser/sessions/session_tab_helper.h"
#include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog.h"
#include "chrome/browser/ui/app_modal_dialogs/app_modal_dialog_queue.h"
#include "chrome/browser/ui/app_modal_dialogs/javascript_app_modal_dialog.h"
#include "chrome/browser/ui/app_modal_dialogs/native_app_modal_dialog.h"
#include "chrome/browser/ui/bookmarks/bookmark_bar.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_iterator.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_tabstrip.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/extensions/application_launch.h"
#include "chrome/browser/ui/find_bar/find_bar.h"
#include "chrome/browser/ui/find_bar/find_bar_controller.h"
#include "chrome/browser/ui/fullscreen/fullscreen_controller.h"
#include "chrome/browser/ui/fullscreen/fullscreen_exit_bubble_type.h"
#include "chrome/browser/ui/host_desktop.h"
#include "chrome/browser/ui/login/login_prompt.h"
#include "chrome/browser/ui/omnibox/location_bar.h"
#include "chrome/browser/ui/omnibox/omnibox_edit_model.h"
#include "chrome/browser/ui/omnibox/omnibox_view.h"
#include "chrome/browser/ui/search_engines/keyword_editor_controller.h"
#include "chrome/browser/ui/startup/startup_types.h"
#include "chrome/common/automation_constants.h"
#include "chrome/common/automation_messages.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/background_info.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/manifest_url_handler.h"
#include "chrome/common/extensions/permissions/permissions_data.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/render_messages.h"
#include "content/public/browser/browser_child_process_host_iterator.h"
#include "content/public/browser/child_process_data.h"
#include "content/public/browser/favicon_status.h"
#include "content/public/browser/geolocation_provider.h"
#include "content/public/browser/interstitial_page.h"
#include "content/public/browser/interstitial_page_delegate.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/plugin_service.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/child_process_host.h"
#include "content/public/common/common_param_traits.h"
#include "content/public/common/drop_data.h"
#include "content/public/common/geoposition.h"
#include "content/public/common/ssl_status.h"
#include "content/public/common/webplugininfo.h"
#include "extensions/browser/view_type_utils.h"
#include "extensions/common/permissions/permission_set.h"
#include "extensions/common/url_pattern.h"
#include "extensions/common/url_pattern_set.h"
#include "net/cookies/cookie_store.h"
#include "third_party/WebKit/public/web/WebInputEvent.h"
#include "ui/base/ui_base_types.h"
#include "ui/events/event_constants.h"
#include "ui/events/keycodes/keyboard_codes.h"
#if defined(ENABLE_CONFIGURATION_POLICY)
#include "chrome/browser/policy/policy_service.h"
#endif
#if defined(OS_CHROMEOS)
#include "chromeos/dbus/dbus_thread_manager.h"
#endif
#if defined(OS_MACOSX)
#include <mach/mach.h>
#include <mach/mach_vm.h>
#endif
using automation_util::SendErrorIfModalDialogActive;
using content::BrowserChildProcessHostIterator;
using content::BrowserContext;
using content::BrowserThread;
using content::ChildProcessHost;
using content::DownloadItem;
using content::DownloadManager;
using content::InterstitialPage;
using content::NativeWebKeyboardEvent;
using content::NavigationController;
using content::NavigationEntry;
using content::OpenURLParams;
using content::PluginService;
using content::Referrer;
using content::RenderViewHost;
using content::SSLStatus;
using content::WebContents;
using extensions::Extension;
using extensions::ExtensionActionManager;
using extensions::ExtensionList;
using extensions::Manifest;
namespace {
// Helper to reply asynchronously if |automation| is still valid.
void SendSuccessReply(base::WeakPtr<AutomationProvider> automation,
IPC::Message* reply_message) {
if (automation.get())
AutomationJSONReply(automation.get(), reply_message).SendSuccess(NULL);
}
// Helper to process the result of CanEnablePlugin.
void DidEnablePlugin(base::WeakPtr<AutomationProvider> automation,
IPC::Message* reply_message,
const base::FilePath::StringType& path,
const std::string& error_msg,
bool did_enable) {
if (did_enable) {
SendSuccessReply(automation, reply_message);
} else {
if (automation.get()) {
AutomationJSONReply(automation.get(), reply_message)
.SendError(base::StringPrintf(error_msg.c_str(), path.c_str()));
}
}
}
// Helper to resolve the overloading of PostTask.
void PostTask(BrowserThread::ID id, const base::Closure& callback) {
BrowserThread::PostTask(id, FROM_HERE, callback);
}
class AutomationInterstitialPage : public content::InterstitialPageDelegate {
public:
AutomationInterstitialPage(WebContents* tab,
const GURL& url,
const std::string& contents)
: contents_(contents) {
interstitial_page_ = InterstitialPage::Create(tab, true, url, this);
interstitial_page_->Show();
}
virtual std::string GetHTMLContents() OVERRIDE { return contents_; }
private:
const std::string contents_;
InterstitialPage* interstitial_page_; // Owns us.
DISALLOW_COPY_AND_ASSIGN(AutomationInterstitialPage);
};
} // namespace
const int TestingAutomationProvider::kSynchronousCommands[] = {
IDC_HOME,
IDC_SELECT_NEXT_TAB,
IDC_SELECT_PREVIOUS_TAB,
IDC_SHOW_BOOKMARK_MANAGER,
};
TestingAutomationProvider::TestingAutomationProvider(Profile* profile)
: AutomationProvider(profile) {
BrowserList::AddObserver(this);
registrar_.Add(this, chrome::NOTIFICATION_SESSION_END,
content::NotificationService::AllSources());
#if defined(OS_CHROMEOS)
AddChromeosObservers();
#endif
}
TestingAutomationProvider::~TestingAutomationProvider() {
#if defined(OS_CHROMEOS)
RemoveChromeosObservers();
#endif
BrowserList::RemoveObserver(this);
}
IPC::Channel::Mode TestingAutomationProvider::GetChannelMode(
bool use_named_interface) {
if (use_named_interface)
#if defined(OS_POSIX)
return IPC::Channel::MODE_OPEN_NAMED_SERVER;
#else
return IPC::Channel::MODE_NAMED_SERVER;
#endif
else
return IPC::Channel::MODE_CLIENT;
}
void TestingAutomationProvider::OnBrowserAdded(Browser* browser) {
}
void TestingAutomationProvider::OnBrowserRemoved(Browser* browser) {
#if !defined(OS_CHROMEOS) && !defined(OS_MACOSX)
// For backwards compatibility with the testing automation interface, we
// want the automation provider (and hence the process) to go away when the
// last browser goes away.
// The automation layer doesn't support non-native desktops.
if (BrowserList::GetInstance(chrome::HOST_DESKTOP_TYPE_NATIVE)->empty() &&
!CommandLine::ForCurrentProcess()->HasSwitch(
switches::kKeepAliveForTest)) {
// If you change this, update Observer for chrome::SESSION_END
// below.
base::MessageLoop::current()->PostTask(
FROM_HERE,
base::Bind(&TestingAutomationProvider::OnRemoveProvider, this));
}
#endif // !defined(OS_CHROMEOS) && !defined(OS_MACOSX)
}
void TestingAutomationProvider::Observe(
int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
DCHECK(type == chrome::NOTIFICATION_SESSION_END);
// OnBrowserRemoved does a ReleaseLater. When session end is received we exit
// before the task runs resulting in this object not being deleted. This
// Release balance out the Release scheduled by OnBrowserRemoved.
Release();
}
bool TestingAutomationProvider::OnMessageReceived(
const IPC::Message& message) {
base::ThreadRestrictions::ScopedAllowWait allow_wait;
bool handled = true;
bool deserialize_success = true;
IPC_BEGIN_MESSAGE_MAP_EX(TestingAutomationProvider,
message,
deserialize_success)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_CloseBrowser, CloseBrowser)
IPC_MESSAGE_HANDLER(AutomationMsg_ActivateTab, ActivateTab)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_AppendTab, AppendTab)
IPC_MESSAGE_HANDLER(AutomationMsg_GetMachPortCount, GetMachPortCount)
IPC_MESSAGE_HANDLER(AutomationMsg_ActiveTabIndex, GetActiveTabIndex)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_CloseTab, CloseTab)
IPC_MESSAGE_HANDLER(AutomationMsg_GetCookies, GetCookies)
IPC_MESSAGE_HANDLER_DELAY_REPLY(
AutomationMsg_NavigateToURLBlockUntilNavigationsComplete,
NavigateToURLBlockUntilNavigationsComplete)
IPC_MESSAGE_HANDLER(AutomationMsg_NavigationAsync, NavigationAsync)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_Reload, Reload)
IPC_MESSAGE_HANDLER(AutomationMsg_BrowserWindowCount, GetBrowserWindowCount)
IPC_MESSAGE_HANDLER(AutomationMsg_NormalBrowserWindowCount,
GetNormalBrowserWindowCount)
IPC_MESSAGE_HANDLER(AutomationMsg_BrowserWindow, GetBrowserWindow)
IPC_MESSAGE_HANDLER(AutomationMsg_WindowExecuteCommandAsync,
ExecuteBrowserCommandAsync)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WindowExecuteCommand,
ExecuteBrowserCommand)
IPC_MESSAGE_HANDLER(AutomationMsg_TerminateSession, TerminateSession)
IPC_MESSAGE_HANDLER(AutomationMsg_WindowViewBounds, WindowGetViewBounds)
IPC_MESSAGE_HANDLER(AutomationMsg_SetWindowBounds, SetWindowBounds)
IPC_MESSAGE_HANDLER(AutomationMsg_TabCount, GetTabCount)
IPC_MESSAGE_HANDLER(AutomationMsg_Type, GetType)
IPC_MESSAGE_HANDLER(AutomationMsg_Tab, GetTab)
IPC_MESSAGE_HANDLER(AutomationMsg_TabTitle, GetTabTitle)
IPC_MESSAGE_HANDLER(AutomationMsg_TabIndex, GetTabIndex)
IPC_MESSAGE_HANDLER(AutomationMsg_TabURL, GetTabURL)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_DomOperation,
ExecuteJavascript)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_OpenNewBrowserWindowOfType,
OpenNewBrowserWindowOfType)
IPC_MESSAGE_HANDLER(AutomationMsg_WindowForBrowser, GetWindowForBrowser)
IPC_MESSAGE_HANDLER(AutomationMsg_GetMetricEventDuration,
GetMetricEventDuration)
IPC_MESSAGE_HANDLER(AutomationMsg_BringBrowserToFront, BringBrowserToFront)
IPC_MESSAGE_HANDLER(AutomationMsg_FindWindowVisibility,
GetFindWindowVisibility)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WaitForBookmarkModelToLoad,
WaitForBookmarkModelToLoad)
IPC_MESSAGE_HANDLER_DELAY_REPLY(
AutomationMsg_WaitForBrowserWindowCountToBecome,
WaitForBrowserWindowCountToBecome)
IPC_MESSAGE_HANDLER_DELAY_REPLY(
AutomationMsg_GoBackBlockUntilNavigationsComplete,
GoBackBlockUntilNavigationsComplete)
IPC_MESSAGE_HANDLER_DELAY_REPLY(
AutomationMsg_GoForwardBlockUntilNavigationsComplete,
GoForwardBlockUntilNavigationsComplete)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_SendJSONRequest,
SendJSONRequestWithBrowserIndex)
IPC_MESSAGE_HANDLER_DELAY_REPLY(
AutomationMsg_SendJSONRequestWithBrowserHandle,
SendJSONRequestWithBrowserHandle)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WaitForTabCountToBecome,
WaitForTabCountToBecome)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WaitForInfoBarCount,
WaitForInfoBarCount)
IPC_MESSAGE_HANDLER_DELAY_REPLY(
AutomationMsg_WaitForProcessLauncherThreadToGoIdle,
WaitForProcessLauncherThreadToGoIdle)
IPC_MESSAGE_UNHANDLED(
handled = AutomationProvider::OnMessageReceived(message))
IPC_END_MESSAGE_MAP_EX()
if (!deserialize_success)
OnMessageDeserializationFailure();
return handled;
}
void TestingAutomationProvider::OnChannelError() {
if (!reinitialize_on_channel_error_ &&
browser_shutdown::GetShutdownType() == browser_shutdown::NOT_VALID) {
chrome::AttemptExit();
}
AutomationProvider::OnChannelError();
}
void TestingAutomationProvider::CloseBrowser(int browser_handle,
IPC::Message* reply_message) {
if (!browser_tracker_->ContainsHandle(browser_handle))
return;
Browser* browser = browser_tracker_->GetResource(browser_handle);
new BrowserClosedNotificationObserver(browser, this, reply_message, false);
browser->window()->Close();
}
void TestingAutomationProvider::ActivateTab(int handle,
int at_index,
int* status) {
*status = -1;
if (browser_tracker_->ContainsHandle(handle) && at_index > -1) {
Browser* browser = browser_tracker_->GetResource(handle);
if (at_index >= 0 && at_index < browser->tab_strip_model()->count()) {
browser->tab_strip_model()->ActivateTabAt(at_index, true);
*status = 0;
}
}
}
void TestingAutomationProvider::AppendTab(int handle,
const GURL& url,
IPC::Message* reply_message) {
int append_tab_response = -1; // -1 is the error code
TabAppendedNotificationObserver* observer = NULL;
if (browser_tracker_->ContainsHandle(handle)) {
Browser* browser = browser_tracker_->GetResource(handle);
observer = new TabAppendedNotificationObserver(browser, this,
reply_message, false);
WebContents* contents =
chrome::AddSelectedTabWithURL(browser, url,
content::PAGE_TRANSITION_TYPED);
if (contents) {
append_tab_response = GetIndexForNavigationController(
&contents->GetController(), browser);
}
}
if (append_tab_response < 0) {
// Appending tab failed. Clean up and send failure response.
if (observer)
delete observer;
AutomationMsg_AppendTab::WriteReplyParams(reply_message,
append_tab_response);
Send(reply_message);
}
}
void TestingAutomationProvider::GetMachPortCount(int* port_count) {
#if defined(OS_MACOSX)
mach_port_name_array_t names;
mach_msg_type_number_t names_count;
mach_port_type_array_t types;
mach_msg_type_number_t types_count;
mach_port_t port = mach_task_self();
// A friendlier interface would allow NULL buffers to only get the counts.
kern_return_t kr = mach_port_names(port, &names, &names_count,
&types, &types_count);
if (kr != KERN_SUCCESS) {
*port_count = 0;
return;
}
// The documentation states this is an invariant.
DCHECK_EQ(names_count, types_count);
*port_count = names_count;
mach_vm_deallocate(port, reinterpret_cast<mach_vm_address_t>(names),
names_count * sizeof(mach_port_name_array_t));
mach_vm_deallocate(port, reinterpret_cast<mach_vm_address_t>(types),
types_count * sizeof(mach_port_type_array_t));
#else
*port_count = 0;
#endif
}
void TestingAutomationProvider::GetActiveTabIndex(int handle,
int* active_tab_index) {
*active_tab_index = -1; // -1 is the error code
if (browser_tracker_->ContainsHandle(handle)) {
Browser* browser = browser_tracker_->GetResource(handle);
*active_tab_index = browser->tab_strip_model()->active_index();
}
}
void TestingAutomationProvider::CloseTab(int tab_handle,
bool wait_until_closed,
IPC::Message* reply_message) {
if (tab_tracker_->ContainsHandle(tab_handle)) {
NavigationController* controller = tab_tracker_->GetResource(tab_handle);
Browser* browser = chrome::FindBrowserWithWebContents(
controller->GetWebContents());
DCHECK(browser);
new TabClosedNotificationObserver(this, wait_until_closed, reply_message,
false);
chrome::CloseWebContents(browser, controller->GetWebContents(), false);
return;
}
AutomationMsg_CloseTab::WriteReplyParams(reply_message, false);
Send(reply_message);
}
void TestingAutomationProvider::GetCookies(const GURL& url, int handle,
int* value_size,
std::string* value) {
WebContents* contents = tab_tracker_->ContainsHandle(handle) ?
tab_tracker_->GetResource(handle)->GetWebContents() : NULL;
automation_util::GetCookies(url, contents, value_size, value);
}
void TestingAutomationProvider::NavigateToURLBlockUntilNavigationsComplete(
int handle, const GURL& url, int number_of_navigations,
IPC::Message* reply_message) {
if (tab_tracker_->ContainsHandle(handle)) {
NavigationController* tab = tab_tracker_->GetResource(handle);
// Simulate what a user would do. Activate the tab and then navigate.
// We could allow navigating in a background tab in future.
Browser* browser = FindAndActivateTab(tab);
if (browser) {
new NavigationNotificationObserver(tab, this, reply_message,
number_of_navigations, false, false);
// TODO(darin): avoid conversion to GURL.
OpenURLParams params(
url, Referrer(), CURRENT_TAB,
content::PageTransitionFromInt(
content::PAGE_TRANSITION_TYPED |
content::PAGE_TRANSITION_FROM_ADDRESS_BAR),
false);
browser->OpenURL(params);
return;
}
}
AutomationMsg_NavigateToURLBlockUntilNavigationsComplete::WriteReplyParams(
reply_message, AUTOMATION_MSG_NAVIGATION_ERROR);
Send(reply_message);
}
void TestingAutomationProvider::NavigationAsync(int handle,
const GURL& url,
bool* status) {
*status = false;
if (tab_tracker_->ContainsHandle(handle)) {
NavigationController* tab = tab_tracker_->GetResource(handle);
// Simulate what a user would do. Activate the tab and then navigate.
// We could allow navigating in a background tab in future.
Browser* browser = FindAndActivateTab(tab);
if (browser) {
// Don't add any listener unless a callback mechanism is desired.
// TODO(vibhor): Do this if such a requirement arises in future.
OpenURLParams params(
url, Referrer(), CURRENT_TAB,
content::PageTransitionFromInt(
content::PAGE_TRANSITION_TYPED |
content::PAGE_TRANSITION_FROM_ADDRESS_BAR),
false);
browser->OpenURL(params);
*status = true;
}
}
}
void TestingAutomationProvider::Reload(int handle,
IPC::Message* reply_message) {
if (tab_tracker_->ContainsHandle(handle)) {
NavigationController* tab = tab_tracker_->GetResource(handle);
Browser* browser = FindAndActivateTab(tab);
if (chrome::IsCommandEnabled(browser, IDC_RELOAD)) {
new NavigationNotificationObserver(
tab, this, reply_message, 1, false, false);
chrome::ExecuteCommand(browser, IDC_RELOAD);
return;
}
}
AutomationMsg_Reload::WriteReplyParams(
reply_message, AUTOMATION_MSG_NAVIGATION_ERROR);
Send(reply_message);
}
void TestingAutomationProvider::GetBrowserWindowCount(int* window_count) {
// The automation layer doesn't support non-native desktops.
*window_count = static_cast<int>(BrowserList::GetInstance(
chrome::HOST_DESKTOP_TYPE_NATIVE)->size());
}
void TestingAutomationProvider::GetNormalBrowserWindowCount(int* window_count) {
*window_count = static_cast<int>(chrome::GetTabbedBrowserCount(
profile_, chrome::HOST_DESKTOP_TYPE_NATIVE));
}
void TestingAutomationProvider::GetBrowserWindow(int index, int* handle) {
*handle = 0;
Browser* browser = automation_util::GetBrowserAt(index);
if (browser)
*handle = browser_tracker_->Add(browser);
}
void TestingAutomationProvider::ExecuteBrowserCommandAsync(int handle,
int command,
bool* success) {
*success = false;
if (!browser_tracker_->ContainsHandle(handle)) {
LOG(WARNING) << "Browser tracker does not contain handle: " << handle;
return;
}
Browser* browser = browser_tracker_->GetResource(handle);
if (!chrome::SupportsCommand(browser, command)) {
LOG(WARNING) << "Browser does not support command: " << command;
return;
}
if (!chrome::IsCommandEnabled(browser, command)) {
LOG(WARNING) << "Browser command not enabled: " << command;
return;
}
chrome::ExecuteCommand(browser, command);
*success = true;
}
void TestingAutomationProvider::ExecuteBrowserCommand(
int handle, int command, IPC::Message* reply_message) {
if (browser_tracker_->ContainsHandle(handle)) {
Browser* browser = browser_tracker_->GetResource(handle);
if (chrome::SupportsCommand(browser, command) &&
chrome::IsCommandEnabled(browser, command)) {
// First check if we can handle the command without using an observer.
for (size_t i = 0; i < arraysize(kSynchronousCommands); i++) {
if (command == kSynchronousCommands[i]) {
chrome::ExecuteCommand(browser, command);
AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message,
true);
Send(reply_message);
return;
}
}
// Use an observer if we have one, otherwise fail.
if (ExecuteBrowserCommandObserver::CreateAndRegisterObserver(
this, browser, command, reply_message, false)) {
chrome::ExecuteCommand(browser, command);
return;
}
}
}
AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message, false);
Send(reply_message);
}
void TestingAutomationProvider::WebkitMouseClick(DictionaryValue* args,
IPC::Message* reply_message) {
if (SendErrorIfModalDialogActive(this, reply_message))
return;
RenderViewHost* view;
std::string error;
if (!GetRenderViewFromJSONArgs(args, profile(), &view, &error)) {
AutomationJSONReply(this, reply_message).SendError(error);
return;
}
WebKit::WebMouseEvent mouse_event;
if (!args->GetInteger("x", &mouse_event.x) ||
!args->GetInteger("y", &mouse_event.y)) {
AutomationJSONReply(this, reply_message)
.SendError("(X,Y) coordinates missing or invalid");
return;
}
int button;
if (!args->GetInteger("button", &button)) {
AutomationJSONReply(this, reply_message)
.SendError("Mouse button missing or invalid");
return;
}
if (button == automation::kLeftButton) {
mouse_event.button = WebKit::WebMouseEvent::ButtonLeft;
} else if (button == automation::kRightButton) {
mouse_event.button = WebKit::WebMouseEvent::ButtonRight;
} else if (button == automation::kMiddleButton) {
mouse_event.button = WebKit::WebMouseEvent::ButtonMiddle;
} else {
AutomationJSONReply(this, reply_message)
.SendError("Invalid button press requested");
return;
}
mouse_event.type = WebKit::WebInputEvent::MouseDown;
mouse_event.clickCount = 1;
view->ForwardMouseEvent(mouse_event);
mouse_event.type = WebKit::WebInputEvent::MouseUp;
new InputEventAckNotificationObserver(this, reply_message, mouse_event.type,
1);
view->ForwardMouseEvent(mouse_event);
}
void TestingAutomationProvider::WebkitMouseMove(
DictionaryValue* args, IPC::Message* reply_message) {
if (SendErrorIfModalDialogActive(this, reply_message))
return;
RenderViewHost* view;
std::string error;
if (!GetRenderViewFromJSONArgs(args, profile(), &view, &error)) {
AutomationJSONReply(this, reply_message).SendError(error);
return;
}
WebKit::WebMouseEvent mouse_event;
if (!args->GetInteger("x", &mouse_event.x) ||
!args->GetInteger("y", &mouse_event.y)) {
AutomationJSONReply(this, reply_message)
.SendError("(X,Y) coordinates missing or invalid");
return;
}
mouse_event.type = WebKit::WebInputEvent::MouseMove;
new InputEventAckNotificationObserver(this, reply_message, mouse_event.type,
1);
view->ForwardMouseEvent(mouse_event);
}
void TestingAutomationProvider::WebkitMouseDrag(DictionaryValue* args,
IPC::Message* reply_message) {
if (SendErrorIfModalDialogActive(this, reply_message))
return;
RenderViewHost* view;
std::string error;
if (!GetRenderViewFromJSONArgs(args, profile(), &view, &error)) {
AutomationJSONReply(this, reply_message).SendError(error);
return;
}
WebKit::WebMouseEvent mouse_event;
int start_x, start_y, end_x, end_y;
if (!args->GetInteger("start_x", &start_x) ||
!args->GetInteger("start_y", &start_y) ||
!args->GetInteger("end_x", &end_x) ||
!args->GetInteger("end_y", &end_y)) {
AutomationJSONReply(this, reply_message)
.SendError("Invalid start/end positions");
return;
}
mouse_event.type = WebKit::WebInputEvent::MouseMove;
// Step 1- Move the mouse to the start position.
mouse_event.x = start_x;
mouse_event.y = start_y;
view->ForwardMouseEvent(mouse_event);
// Step 2- Left click mouse down, the mouse button is fixed.
mouse_event.type = WebKit::WebInputEvent::MouseDown;
mouse_event.button = WebKit::WebMouseEvent::ButtonLeft;
mouse_event.clickCount = 1;
view->ForwardMouseEvent(mouse_event);
// Step 3 - Move the mouse to the end position.
mouse_event.type = WebKit::WebInputEvent::MouseMove;
mouse_event.x = end_x;
mouse_event.y = end_y;
mouse_event.clickCount = 0;
view->ForwardMouseEvent(mouse_event);
// Step 4 - Release the left mouse button.
mouse_event.type = WebKit::WebInputEvent::MouseUp;
mouse_event.clickCount = 1;
new InputEventAckNotificationObserver(this, reply_message, mouse_event.type,
1);
view->ForwardMouseEvent(mouse_event);
}
void TestingAutomationProvider::WebkitMouseButtonDown(
DictionaryValue* args, IPC::Message* reply_message) {
if (SendErrorIfModalDialogActive(this, reply_message))
return;
RenderViewHost* view;
std::string error;
if (!GetRenderViewFromJSONArgs(args, profile(), &view, &error)) {
AutomationJSONReply(this, reply_message).SendError(error);
return;
}
WebKit::WebMouseEvent mouse_event;
if (!args->GetInteger("x", &mouse_event.x) ||
!args->GetInteger("y", &mouse_event.y)) {
AutomationJSONReply(this, reply_message)
.SendError("(X,Y) coordinates missing or invalid");
return;
}
mouse_event.type = WebKit::WebInputEvent::MouseDown;
mouse_event.button = WebKit::WebMouseEvent::ButtonLeft;
mouse_event.clickCount = 1;
new InputEventAckNotificationObserver(this, reply_message, mouse_event.type,
1);
view->ForwardMouseEvent(mouse_event);
}
void TestingAutomationProvider::WebkitMouseButtonUp(
DictionaryValue* args, IPC::Message* reply_message) {
if (SendErrorIfModalDialogActive(this, reply_message))
return;
RenderViewHost* view;
std::string error;
if (!GetRenderViewFromJSONArgs(args, profile(), &view, &error)) {
AutomationJSONReply(this, reply_message).SendError(error);
return;
}
WebKit::WebMouseEvent mouse_event;
if (!args->GetInteger("x", &mouse_event.x) ||
!args->GetInteger("y", &mouse_event.y)) {
AutomationJSONReply(this, reply_message)
.SendError("(X,Y) coordinates missing or invalid");
return;
}
mouse_event.type = WebKit::WebInputEvent::MouseUp;
mouse_event.button = WebKit::WebMouseEvent::ButtonLeft;
mouse_event.clickCount = 1;
new InputEventAckNotificationObserver(this, reply_message, mouse_event.type,
1);
view->ForwardMouseEvent(mouse_event);
}
void TestingAutomationProvider::WebkitMouseDoubleClick(
DictionaryValue* args, IPC::Message* reply_message) {
if (SendErrorIfModalDialogActive(this, reply_message))
return;
RenderViewHost* view;
std::string error;
if (!GetRenderViewFromJSONArgs(args, profile(), &view, &error)) {
AutomationJSONReply(this, reply_message).SendError(error);
return;
}
WebKit::WebMouseEvent mouse_event;
if (!args->GetInteger("x", &mouse_event.x) ||
!args->GetInteger("y", &mouse_event.y)) {
AutomationJSONReply(this, reply_message)
.SendError("(X,Y) coordinates missing or invalid");
return;
}
mouse_event.type = WebKit::WebInputEvent::MouseDown;
mouse_event.button = WebKit::WebMouseEvent::ButtonLeft;
mouse_event.clickCount = 1;
view->ForwardMouseEvent(mouse_event);
mouse_event.type = WebKit::WebInputEvent::MouseUp;
new InputEventAckNotificationObserver(this, reply_message, mouse_event.type,
2);
view->ForwardMouseEvent(mouse_event);
mouse_event.type = WebKit::WebInputEvent::MouseDown;
mouse_event.clickCount = 2;
view->ForwardMouseEvent(mouse_event);
mouse_event.type = WebKit::WebInputEvent::MouseUp;
view->ForwardMouseEvent(mouse_event);
}
void TestingAutomationProvider::DragAndDropFilePaths(
DictionaryValue* args, IPC::Message* reply_message) {
if (SendErrorIfModalDialogActive(this, reply_message))
return;
RenderViewHost* view;
std::string error;
if (!GetRenderViewFromJSONArgs(args, profile(), &view, &error)) {
AutomationJSONReply(this, reply_message).SendError(error);
return;
}
int x, y;
if (!args->GetInteger("x", &x) || !args->GetInteger("y", &y)) {
AutomationJSONReply(this, reply_message)
.SendError("(X,Y) coordinates missing or invalid");
return;
}
ListValue* paths = NULL;
if (!args->GetList("paths", &paths)) {
AutomationJSONReply(this, reply_message)
.SendError("'paths' missing or invalid");
return;
}
// Emulate drag and drop to set the file paths to the file upload control.
content::DropData drop_data;
for (size_t path_index = 0; path_index < paths->GetSize(); ++path_index) {
string16 path;
if (!paths->GetString(path_index, &path)) {
AutomationJSONReply(this, reply_message)
.SendError("'paths' contains a non-string type");
return;
}
drop_data.filenames.push_back(
content::DropData::FileInfo(path, string16()));
}
const gfx::Point client(x, y);
// We don't set any values in screen variable because DragTarget*** ignore the
// screen argument.
const gfx::Point screen;
int operations = 0;
operations |= WebKit::WebDragOperationCopy;
operations |= WebKit::WebDragOperationLink;
operations |= WebKit::WebDragOperationMove;
view->DragTargetDragEnter(
drop_data, client, screen,
static_cast<WebKit::WebDragOperationsMask>(operations), 0);
new DragTargetDropAckNotificationObserver(this, reply_message);
view->DragTargetDrop(client, screen, 0);
}
void TestingAutomationProvider::GetTabCount(int handle, int* tab_count) {
*tab_count = -1; // -1 is the error code
if (browser_tracker_->ContainsHandle(handle)) {
Browser* browser = browser_tracker_->GetResource(handle);
*tab_count = browser->tab_strip_model()->count();
}
}
void TestingAutomationProvider::GetType(int handle, int* type_as_int) {
*type_as_int = -1; // -1 is the error code
if (browser_tracker_->ContainsHandle(handle)) {
Browser* browser = browser_tracker_->GetResource(handle);
*type_as_int = static_cast<int>(browser->type());
}
}
void TestingAutomationProvider::GetTab(int win_handle,
int tab_index,
int* tab_handle) {
*tab_handle = 0;
if (browser_tracker_->ContainsHandle(win_handle) && (tab_index >= 0)) {
Browser* browser = browser_tracker_->GetResource(win_handle);
if (tab_index < browser->tab_strip_model()->count()) {
WebContents* web_contents =
browser->tab_strip_model()->GetWebContentsAt(tab_index);
*tab_handle = tab_tracker_->Add(&web_contents->GetController());
}
}
}
void TestingAutomationProvider::GetTabTitle(int handle,
int* title_string_size,
std::wstring* title) {
*title_string_size = -1; // -1 is the error code
if (tab_tracker_->ContainsHandle(handle)) {
NavigationController* tab = tab_tracker_->GetResource(handle);
NavigationEntry* entry = tab->GetActiveEntry();
if (entry != NULL) {
*title = UTF16ToWideHack(entry->GetTitleForDisplay(std::string()));
} else {
*title = std::wstring();
}
*title_string_size = static_cast<int>(title->size());
}
}
void TestingAutomationProvider::GetTabIndex(int handle, int* tabstrip_index) {
*tabstrip_index = -1; // -1 is the error code
if (tab_tracker_->ContainsHandle(handle)) {
NavigationController* tab = tab_tracker_->GetResource(handle);
Browser* browser = chrome::FindBrowserWithWebContents(
tab->GetWebContents());
*tabstrip_index = browser->tab_strip_model()->GetIndexOfWebContents(
tab->GetWebContents());
}
}
void TestingAutomationProvider::GetTabURL(int handle,
bool* success,
GURL* url) {
*success = false;
if (tab_tracker_->ContainsHandle(handle)) {
NavigationController* tab = tab_tracker_->GetResource(handle);
// Return what the user would see in the location bar.
*url = tab->GetActiveEntry()->GetVirtualURL();
*success = true;
}
}
void TestingAutomationProvider::ExecuteJavascriptInRenderViewFrame(
const string16& frame_xpath,
const string16& script,
IPC::Message* reply_message,
RenderViewHost* render_view_host) {
// Set the routing id of this message with the controller.
// This routing id needs to be remembered for the reverse
// communication while sending back the response of
// this javascript execution.
render_view_host->ExecuteJavascriptInWebFrame(
frame_xpath,
UTF8ToUTF16("window.domAutomationController.setAutomationId(0);"));
render_view_host->ExecuteJavascriptInWebFrame(
frame_xpath, script);
}
void TestingAutomationProvider::ExecuteJavascript(
int handle,
const std::wstring& frame_xpath,
const std::wstring& script,
IPC::Message* reply_message) {
WebContents* web_contents = GetWebContentsForHandle(handle, NULL);
if (!web_contents) {
AutomationMsg_DomOperation::WriteReplyParams(reply_message, std::string());
Send(reply_message);
return;
}
new DomOperationMessageSender(this, reply_message, false);
ExecuteJavascriptInRenderViewFrame(WideToUTF16Hack(frame_xpath),
WideToUTF16Hack(script), reply_message,
web_contents->GetRenderViewHost());
}
// Sample json input: { "command": "OpenNewBrowserWindowWithNewProfile" }
// Sample output: {}
void TestingAutomationProvider::OpenNewBrowserWindowWithNewProfile(
base::DictionaryValue* args, IPC::Message* reply_message) {
ProfileManager* profile_manager = g_browser_process->profile_manager();
new BrowserOpenedWithNewProfileNotificationObserver(this, reply_message);
profile_manager->CreateMultiProfileAsync(
string16(), string16(), ProfileManager::CreateCallback(), std::string());
}
// Sample json input: { "command": "GetMultiProfileInfo" }
// See GetMultiProfileInfo() in pyauto.py for sample output.
void TestingAutomationProvider::GetMultiProfileInfo(
base::DictionaryValue* args, IPC::Message* reply_message) {
scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
ProfileManager* profile_manager = g_browser_process->profile_manager();
const ProfileInfoCache& profile_info_cache =
profile_manager->GetProfileInfoCache();
return_value->SetBoolean("enabled", profiles::IsMultipleProfilesEnabled());
ListValue* profiles = new ListValue;
for (size_t index = 0; index < profile_info_cache.GetNumberOfProfiles();
++index) {
DictionaryValue* item = new DictionaryValue;
item->SetString("name", profile_info_cache.GetNameOfProfileAtIndex(index));
item->SetString("path",
profile_info_cache.GetPathOfProfileAtIndex(index).value());
profiles->Append(item);
}
return_value->Set("profiles", profiles);
AutomationJSONReply(this, reply_message).SendSuccess(return_value.get());
}
void TestingAutomationProvider::OpenNewBrowserWindowOfType(
int type, bool show, IPC::Message* reply_message) {
new BrowserOpenedNotificationObserver(this, reply_message, false);
// We may have no current browser windows open so don't rely on
// asking an existing browser to execute the IDC_NEWWINDOW command.
Browser* browser = new Browser(
Browser::CreateParams(static_cast<Browser::Type>(type), profile_,
chrome::HOST_DESKTOP_TYPE_NATIVE));
chrome::AddBlankTabAt(browser, -1, true);
if (show)
browser->window()->Show();
}
void TestingAutomationProvider::OpenNewBrowserWindow(
base::DictionaryValue* args,
IPC::Message* reply_message) {
bool show;
if (!args->GetBoolean("show", &show)) {
AutomationJSONReply(this, reply_message)
.SendError("'show' missing or invalid.");
return;
}
new BrowserOpenedNotificationObserver(this, reply_message, true);
Browser* browser = new Browser(
Browser::CreateParams(Browser::TYPE_TABBED, profile_,
chrome::HOST_DESKTOP_TYPE_NATIVE));
chrome::AddBlankTabAt(browser, -1, true);
if (show)
browser->window()->Show();
}
void TestingAutomationProvider::GetBrowserWindowCountJSON(
base::DictionaryValue* args,
IPC::Message* reply_message) {
DictionaryValue dict;
// The automation layer doesn't support non-native desktops.
dict.SetInteger("count",
static_cast<int>(BrowserList::GetInstance(
chrome::HOST_DESKTOP_TYPE_NATIVE)->size()));
AutomationJSONReply(this, reply_message).SendSuccess(&dict);
}
void TestingAutomationProvider::CloseBrowserWindow(
base::DictionaryValue* args,
IPC::Message* reply_message) {
AutomationJSONReply reply(this, reply_message);
Browser* browser;
std::string error_msg;
if (!GetBrowserFromJSONArgs(args, &browser, &error_msg)) {
reply.SendError(error_msg);
return;
}
new BrowserClosedNotificationObserver(browser, this, reply_message, true);
browser->window()->Close();
}
void TestingAutomationProvider::OpenProfileWindow(
base::DictionaryValue* args, IPC::Message* reply_message) {
ProfileManager* profile_manager = g_browser_process->profile_manager();
base::FilePath::StringType path;
if (!args->GetString("path", &path)) {
AutomationJSONReply(this, reply_message).SendError(
"Invalid or missing arg: 'path'");
return;
}
Profile* profile = profile_manager->GetProfileByPath(base::FilePath(path));
if (!profile) {
AutomationJSONReply(this, reply_message).SendError(
base::StringPrintf("Invalid profile path: %s", path.c_str()));
return;
}
int num_loads;
if (!args->GetInteger("num_loads", &num_loads)) {
AutomationJSONReply(this, reply_message).SendError(
"Invalid or missing arg: 'num_loads'");
return;
}
new BrowserOpenedWithExistingProfileNotificationObserver(
this, reply_message, num_loads);
profiles::FindOrCreateNewWindowForProfile(
profile,
chrome::startup::IS_NOT_PROCESS_STARTUP,
chrome::startup::IS_NOT_FIRST_RUN,
chrome::HOST_DESKTOP_TYPE_NATIVE,
false);
}
void TestingAutomationProvider::GetWindowForBrowser(int browser_handle,
bool* success,
int* handle) {
*success = false;
*handle = 0;
if (browser_tracker_->ContainsHandle(browser_handle)) {
Browser* browser = browser_tracker_->GetResource(browser_handle);
gfx::NativeWindow win = browser->window()->GetNativeWindow();
// Add() returns the existing handle for the resource if any.
*handle = window_tracker_->Add(win);
*success = true;
}
}
void TestingAutomationProvider::GetMetricEventDuration(
const std::string& event_name,
int* duration_ms) {
*duration_ms = metric_event_duration_observer_->GetEventDurationMs(
event_name);
}
void TestingAutomationProvider::BringBrowserToFront(int browser_handle,
bool* success) {
*success = false;
if (browser_tracker_->ContainsHandle(browser_handle)) {
Browser* browser = browser_tracker_->GetResource(browser_handle);
browser->window()->Activate();
*success = true;
}
}
void TestingAutomationProvider::GetFindWindowVisibility(int handle,
bool* visible) {
*visible = false;
Browser* browser = browser_tracker_->GetResource(handle);
if (browser) {
FindBarTesting* find_bar =
browser->GetFindBarController()->find_bar()->GetFindBarTesting();
find_bar->GetFindBarWindowInfo(NULL, visible);
}
}
// Bookmark bar visibility is based on the pref (e.g. is it in the toolbar).
// Presence in the NTP is signalled in |detached|.
void TestingAutomationProvider::GetBookmarkBarStatus(
DictionaryValue* args,
IPC::Message* reply_message) {
AutomationJSONReply reply(this, reply_message);
Browser* browser;
std::string error_msg;
if (!GetBrowserFromJSONArgs(args, &browser, &error_msg)) {
reply.SendError(error_msg);
return;
}
// browser->window()->IsBookmarkBarVisible() is not consistent across
// platforms. bookmark_bar_state() also follows prefs::kShowBookmarkBar
// and has a shared implementation on all platforms.
DictionaryValue dict;
dict.SetBoolean("visible",
browser->bookmark_bar_state() == BookmarkBar::SHOW);
dict.SetBoolean("animating", browser->window()->IsBookmarkBarAnimating());
dict.SetBoolean("detached",
browser->bookmark_bar_state() == BookmarkBar::DETACHED);
reply.SendSuccess(&dict);
}
void TestingAutomationProvider::GetBookmarksAsJSON(
DictionaryValue* args,
IPC::Message* reply_message) {
AutomationJSONReply reply(this, reply_message);
Browser* browser;
std::string error_msg, bookmarks_as_json;
if (!GetBrowserFromJSONArgs(args, &browser, &error_msg)) {
reply.SendError(error_msg);
return;
}
BookmarkModel* bookmark_model =
BookmarkModelFactory::GetForProfile(browser->profile());
if (!bookmark_model->loaded()) {
reply.SendError("Bookmark model is not loaded");
return;
}
scoped_refptr<BookmarkStorage> storage(
new BookmarkStorage(browser->profile(),
bookmark_model,
browser->profile()->GetIOTaskRunner().get()));
if (!storage->SerializeData(&bookmarks_as_json)) {
reply.SendError("Failed to serialize bookmarks");
return;
}
DictionaryValue dict;
dict.SetString("bookmarks_as_json", bookmarks_as_json);
reply.SendSuccess(&dict);
}
void TestingAutomationProvider::WaitForBookmarkModelToLoad(
int handle,
IPC::Message* reply_message) {
if (browser_tracker_->ContainsHandle(handle)) {
Browser* browser = browser_tracker_->GetResource(handle);
BookmarkModel* model =
BookmarkModelFactory::GetForProfile(browser->profile());
AutomationProviderBookmarkModelObserver* observer =
new AutomationProviderBookmarkModelObserver(this, reply_message,
model, false);
if (model->loaded()) {
observer->ReleaseReply();
delete observer;
AutomationMsg_WaitForBookmarkModelToLoad::WriteReplyParams(
reply_message, true);
Send(reply_message);
}
}
}
void TestingAutomationProvider::WaitForBookmarkModelToLoadJSON(
DictionaryValue* args,
IPC::Message* reply_message) {
Browser* browser;
std::string error_msg;
if (!GetBrowserFromJSONArgs(args, &browser, &error_msg)) {
AutomationJSONReply(this, reply_message).SendError(error_msg);
return;
}
BookmarkModel* model =
BookmarkModelFactory::GetForProfile(browser->profile());
AutomationProviderBookmarkModelObserver* observer =
new AutomationProviderBookmarkModelObserver(this, reply_message, model,
true);
if (model->loaded()) {
observer->ReleaseReply();
delete observer;
AutomationJSONReply(this, reply_message).SendSuccess(NULL);
return;
}
}
void TestingAutomationProvider::AddBookmark(
DictionaryValue* args,
IPC::Message* reply_message) {
AutomationJSONReply reply(this, reply_message);
Browser* browser;
std::string error_msg, url;
string16 title;
int parent_id, index;
bool folder;
if (!GetBrowserFromJSONArgs(args, &browser, &error_msg)) {
reply.SendError(error_msg);
return;
}
if (!args->GetBoolean("is_folder", &folder)) {
reply.SendError("'is_folder' missing or invalid");
return;
}
if (!folder && !args->GetString("url", &url)) {
reply.SendError("'url' missing or invalid");
return;
}
if (!args->GetInteger("parent_id", &parent_id)) {
reply.SendError("'parent_id' missing or invalid");
return;
}
if (!args->GetInteger("index", &index)) {
reply.SendError("'index' missing or invalid");
return;
}
if (!args->GetString("title", &title)) {
reply.SendError("'title' missing or invalid");
return;
}
BookmarkModel* model =
BookmarkModelFactory::GetForProfile(browser->profile());
if (!model->loaded()) {
reply.SendError("Bookmark model is not loaded");
return;
}
const BookmarkNode* parent = model->GetNodeByID(parent_id);
if (!parent) {
reply.SendError("Failed to get parent bookmark node");
return;
}
const BookmarkNode* child;
if (folder) {
child = model->AddFolder(parent, index, title);
} else {
child = model->AddURL(parent, index, title, GURL(url));
}
if (!child) {
reply.SendError("Failed to add bookmark");
return;
}
reply.SendSuccess(NULL);
}
void TestingAutomationProvider::ReparentBookmark(DictionaryValue* args,
IPC::Message* reply_message) {
AutomationJSONReply reply(this, reply_message);
Browser* browser;
std::string error_msg;
int new_parent_id, id, index;
if (!GetBrowserFromJSONArgs(args, &browser, &error_msg)) {
reply.SendError(error_msg);
return;
}
if (!args->GetInteger("id", &id)) {
reply.SendError("'id' missing or invalid");
return;
}
if (!args->GetInteger("new_parent_id", &new_parent_id)) {
reply.SendError("'new_parent_id' missing or invalid");
return;
}
if (!args->GetInteger("index", &index)) {
reply.SendError("'index' missing or invalid");
return;
}
BookmarkModel* model =
BookmarkModelFactory::GetForProfile(browser->profile());
if (!model->loaded()) {
reply.SendError("Bookmark model is not loaded");
return;
}
const BookmarkNode* node = model->GetNodeByID(id);
const BookmarkNode* new_parent = model->GetNodeByID(new_parent_id);
if (!node) {
reply.SendError("Failed to get bookmark node");
return;
}
if (!new_parent) {
reply.SendError("Failed to get new parent bookmark node");
return;
}
model->Move(node, new_parent, index);
reply.SendSuccess(NULL);
}
void TestingAutomationProvider::SetBookmarkTitle(DictionaryValue* args,
IPC::Message* reply_message) {
AutomationJSONReply reply(this, reply_message);
Browser* browser;
std::string error_msg;
string16 title;
int id;
if (!GetBrowserFromJSONArgs(args, &browser, &error_msg)) {
reply.SendError(error_msg);
return;
}
if (!args->GetInteger("id", &id)) {
reply.SendError("'id' missing or invalid");
return;
}
if (!args->GetString("title", &title)) {
reply.SendError("'title' missing or invalid");
return;
}
BookmarkModel* model =
BookmarkModelFactory::GetForProfile(browser->profile());
if (!model->loaded()) {
reply.SendError("Bookmark model is not loaded");
return;
}
const BookmarkNode* node = model->GetNodeByID(id);
if (!node) {
reply.SendError("Failed to get bookmark node");
return;
}
model->SetTitle(node, title);
reply.SendSuccess(NULL);
}
void TestingAutomationProvider::SetBookmarkURL(DictionaryValue* args,
IPC::Message* reply_message) {
AutomationJSONReply reply(this, reply_message);
Browser* browser;
std::string error_msg, url;
int id;
if (!GetBrowserFromJSONArgs(args, &browser, &error_msg)) {
reply.SendError(error_msg);
return;
}
if (!args->GetInteger("id", &id)) {
reply.SendError("'id' missing or invalid");
return;
}
if (!args->GetString("url", &url)) {
reply.SendError("'url' missing or invalid");
return;
}
BookmarkModel* model =
BookmarkModelFactory::GetForProfile(browser->profile());
if (!model->loaded()) {
reply.SendError("Bookmark model is not loaded");
return;
}
const BookmarkNode* node = model->GetNodeByID(id);
if (!node) {
reply.SendError("Failed to get bookmark node");
return;
}
model->SetURL(node, GURL(url));
reply.SendSuccess(NULL);
}
void TestingAutomationProvider::RemoveBookmark(DictionaryValue* args,
IPC::Message* reply_message) {
AutomationJSONReply reply(this, reply_message);
Browser* browser;
std::string error_msg;
int id;
if (!GetBrowserFromJSONArgs(args, &browser, &error_msg)) {
reply.SendError(error_msg);
return;
}
if (!args->GetInteger("id", &id)) {
reply.SendError("'id' missing or invalid");
return;
}
BookmarkModel* model =
BookmarkModelFactory::GetForProfile(browser->profile());
if (!model->loaded()) {
reply.SendError("Bookmark model is not loaded");
return;
}
const BookmarkNode* node = model->GetNodeByID(id);
if (!node) {
reply.SendError("Failed to get bookmark node");
return;
}
const BookmarkNode* parent = node->parent();
if (!parent) {
reply.SendError("Failed to get parent bookmark node");
return;
}
model->Remove(parent, parent->GetIndexOf(node));
reply.SendSuccess(NULL);
}
void TestingAutomationProvider::WaitForBrowserWindowCountToBecome(
int target_count,
IPC::Message* reply_message) {
// The automation layer doesn't support non-native desktops.
int current_count = static_cast<int>(BrowserList::GetInstance(
chrome::HOST_DESKTOP_TYPE_NATIVE)->size());
if (current_count == target_count) {
AutomationMsg_WaitForBrowserWindowCountToBecome::WriteReplyParams(
reply_message, true);
Send(reply_message);
return;
}
// Set up an observer (it will delete itself).
new BrowserCountChangeNotificationObserver(target_count, this, reply_message);
}
void TestingAutomationProvider::GoBackBlockUntilNavigationsComplete(
int handle, int number_of_navigations, IPC::Message* reply_message) {
if (tab_tracker_->ContainsHandle(handle)) {
NavigationController* tab = tab_tracker_->GetResource(handle);
Browser* browser = FindAndActivateTab(tab);
if (chrome::IsCommandEnabled(browser, IDC_BACK)) {
new NavigationNotificationObserver(tab, this, reply_message,
number_of_navigations, false, false);
chrome::ExecuteCommand(browser, IDC_BACK);
return;
}
}
AutomationMsg_GoBackBlockUntilNavigationsComplete::WriteReplyParams(
reply_message, AUTOMATION_MSG_NAVIGATION_ERROR);
Send(reply_message);
}
void TestingAutomationProvider::GoForwardBlockUntilNavigationsComplete(
int handle, int number_of_navigations, IPC::Message* reply_message) {
if (tab_tracker_->ContainsHandle(handle)) {
NavigationController* tab = tab_tracker_->GetResource(handle);
Browser* browser = FindAndActivateTab(tab);
if (chrome::IsCommandEnabled(browser, IDC_FORWARD)) {
new NavigationNotificationObserver(tab, this, reply_message,
number_of_navigations, false, false);
chrome::ExecuteCommand(browser, IDC_FORWARD);
return;
}
}
AutomationMsg_GoForwardBlockUntilNavigationsComplete::WriteReplyParams(
reply_message, AUTOMATION_MSG_NAVIGATION_ERROR);
Send(reply_message);
}
void TestingAutomationProvider::BuildJSONHandlerMaps() {
// Map json commands to their handlers.
handler_map_["ApplyAccelerator"] =
&TestingAutomationProvider::ExecuteBrowserCommandAsyncJSON;
handler_map_["RunCommand"] =
&TestingAutomationProvider::ExecuteBrowserCommandJSON;
handler_map_["IsMenuCommandEnabled"] =
&TestingAutomationProvider::IsMenuCommandEnabledJSON;
handler_map_["ActivateTab"] =
&TestingAutomationProvider::ActivateTabJSON;
handler_map_["BringBrowserToFront"] =
&TestingAutomationProvider::BringBrowserToFrontJSON;
handler_map_["GetIndicesFromTab"] =
&TestingAutomationProvider::GetIndicesFromTab;
handler_map_["NavigateToURL"] =
&TestingAutomationProvider::NavigateToURL;
handler_map_["GetActiveTabIndex"] =
&TestingAutomationProvider::GetActiveTabIndexJSON;
handler_map_["AppendTab"] =
&TestingAutomationProvider::AppendTabJSON;
handler_map_["OpenNewBrowserWindow"] =
&TestingAutomationProvider::OpenNewBrowserWindow;
handler_map_["CloseBrowserWindow"] =
&TestingAutomationProvider::CloseBrowserWindow;
handler_map_["WaitUntilNavigationCompletes"] =
&TestingAutomationProvider::WaitUntilNavigationCompletes;
handler_map_["GetLocalStatePrefsInfo"] =
&TestingAutomationProvider::GetLocalStatePrefsInfo;
handler_map_["SetLocalStatePrefs"] =
&TestingAutomationProvider::SetLocalStatePrefs;
handler_map_["GetPrefsInfo"] = &TestingAutomationProvider::GetPrefsInfo;
handler_map_["SetPrefs"] = &TestingAutomationProvider::SetPrefs;
handler_map_["ExecuteJavascript"] =
&TestingAutomationProvider::ExecuteJavascriptJSON;
handler_map_["AddDomEventObserver"] =
&TestingAutomationProvider::AddDomEventObserver;
handler_map_["RemoveEventObserver"] =
&TestingAutomationProvider::RemoveEventObserver;
handler_map_["GetNextEvent"] =
&TestingAutomationProvider::GetNextEvent;
handler_map_["ClearEventQueue"] =
&TestingAutomationProvider::ClearEventQueue;
handler_map_["ExecuteJavascriptInRenderView"] =
&TestingAutomationProvider::ExecuteJavascriptInRenderView;
handler_map_["GoForward"] =
&TestingAutomationProvider::GoForward;
handler_map_["GoBack"] =
&TestingAutomationProvider::GoBack;
handler_map_["Reload"] =
&TestingAutomationProvider::ReloadJSON;
handler_map_["OpenFindInPage"] =
&TestingAutomationProvider::OpenFindInPage;
handler_map_["IsFindInPageVisible"] =
&TestingAutomationProvider::IsFindInPageVisible;
handler_map_["SetDownloadShelfVisible"] =
&TestingAutomationProvider::SetDownloadShelfVisibleJSON;
handler_map_["IsDownloadShelfVisible"] =
&TestingAutomationProvider::IsDownloadShelfVisibleJSON;
handler_map_["GetDownloadDirectory"] =
&TestingAutomationProvider::GetDownloadDirectoryJSON;
handler_map_["GetCookies"] =
&TestingAutomationProvider::GetCookiesJSON;
handler_map_["DeleteCookie"] =
&TestingAutomationProvider::DeleteCookieJSON;
handler_map_["SetCookie"] =
&TestingAutomationProvider::SetCookieJSON;
handler_map_["GetCookiesInBrowserContext"] =
&TestingAutomationProvider::GetCookiesInBrowserContext;
handler_map_["DeleteCookieInBrowserContext"] =
&TestingAutomationProvider::DeleteCookieInBrowserContext;
handler_map_["SetCookieInBrowserContext"] =
&TestingAutomationProvider::SetCookieInBrowserContext;
handler_map_["WaitForBookmarkModelToLoad"] =
&TestingAutomationProvider::WaitForBookmarkModelToLoadJSON;
handler_map_["GetBookmarksAsJSON"] =
&TestingAutomationProvider::GetBookmarksAsJSON;
handler_map_["GetBookmarkBarStatus"] =
&TestingAutomationProvider::GetBookmarkBarStatus;
handler_map_["AddBookmark"] =
&TestingAutomationProvider::AddBookmark;
handler_map_["ReparentBookmark"] =
&TestingAutomationProvider::ReparentBookmark;
handler_map_["SetBookmarkTitle"] =
&TestingAutomationProvider::SetBookmarkTitle;
handler_map_["SetBookmarkURL"] =
&TestingAutomationProvider::SetBookmarkURL;
handler_map_["RemoveBookmark"] =
&TestingAutomationProvider::RemoveBookmark;
handler_map_["GetTabIds"] =
&TestingAutomationProvider::GetTabIds;
handler_map_["IsTabIdValid"] =
&TestingAutomationProvider::IsTabIdValid;
handler_map_["CloseTab"] =
&TestingAutomationProvider::CloseTabJSON;
handler_map_["SetViewBounds"] =
&TestingAutomationProvider::SetViewBounds;
handler_map_["MaximizeView"] =
&TestingAutomationProvider::MaximizeView;
handler_map_["WebkitMouseMove"] =
&TestingAutomationProvider::WebkitMouseMove;
handler_map_["WebkitMouseClick"] =
&TestingAutomationProvider::WebkitMouseClick;
handler_map_["WebkitMouseDrag"] =
&TestingAutomationProvider::WebkitMouseDrag;
handler_map_["WebkitMouseButtonUp"] =
&TestingAutomationProvider::WebkitMouseButtonUp;
handler_map_["WebkitMouseButtonDown"] =
&TestingAutomationProvider::WebkitMouseButtonDown;
handler_map_["WebkitMouseDoubleClick"] =
&TestingAutomationProvider::WebkitMouseDoubleClick;
handler_map_["DragAndDropFilePaths"] =
&TestingAutomationProvider::DragAndDropFilePaths;
handler_map_["SendWebkitKeyEvent"] =
&TestingAutomationProvider::SendWebkitKeyEvent;
handler_map_["ActivateTab"] =
&TestingAutomationProvider::ActivateTabJSON;
handler_map_["GetAppModalDialogMessage"] =
&TestingAutomationProvider::GetAppModalDialogMessage;
handler_map_["AcceptOrDismissAppModalDialog"] =
&TestingAutomationProvider::AcceptOrDismissAppModalDialog;
handler_map_["ActionOnSSLBlockingPage"] =
&TestingAutomationProvider::ActionOnSSLBlockingPage;
handler_map_["GetSecurityState"] =
&TestingAutomationProvider::GetSecurityState;
handler_map_["IsPageActionVisible"] =
&TestingAutomationProvider::IsPageActionVisible;
handler_map_["CreateNewAutomationProvider"] =
&TestingAutomationProvider::CreateNewAutomationProvider;
handler_map_["GetBrowserWindowCount"] =
&TestingAutomationProvider::GetBrowserWindowCountJSON;
handler_map_["GetBrowserInfo"] =
&TestingAutomationProvider::GetBrowserInfo;
handler_map_["GetTabInfo"] =
&TestingAutomationProvider::GetTabInfo;
handler_map_["GetTabCount"] =
&TestingAutomationProvider::GetTabCountJSON;
handler_map_["OpenNewBrowserWindowWithNewProfile"] =
&TestingAutomationProvider::OpenNewBrowserWindowWithNewProfile;
handler_map_["GetMultiProfileInfo"] =
&TestingAutomationProvider::GetMultiProfileInfo;
handler_map_["OpenProfileWindow"] =
&TestingAutomationProvider::OpenProfileWindow;
handler_map_["GetProcessInfo"] =
&TestingAutomationProvider::GetProcessInfo;
handler_map_["RefreshPolicies"] =
&TestingAutomationProvider::RefreshPolicies;
handler_map_["InstallExtension"] =
&TestingAutomationProvider::InstallExtension;
handler_map_["GetExtensionsInfo"] =
&TestingAutomationProvider::GetExtensionsInfo;
handler_map_["UninstallExtensionById"] =
&TestingAutomationProvider::UninstallExtensionById;
handler_map_["SetExtensionStateById"] =
&TestingAutomationProvider::SetExtensionStateById;
handler_map_["TriggerPageActionById"] =
&TestingAutomationProvider::TriggerPageActionById;
handler_map_["TriggerBrowserActionById"] =
&TestingAutomationProvider::TriggerBrowserActionById;
handler_map_["UpdateExtensionsNow"] =
&TestingAutomationProvider::UpdateExtensionsNow;
handler_map_["OverrideGeoposition"] =
&TestingAutomationProvider::OverrideGeoposition;
handler_map_["SimulateAsanMemoryBug"] =
&TestingAutomationProvider::SimulateAsanMemoryBug;
#if defined(OS_CHROMEOS)
handler_map_["AcceptOOBENetworkScreen"] =
&TestingAutomationProvider::AcceptOOBENetworkScreen;
handler_map_["AcceptOOBEEula"] = &TestingAutomationProvider::AcceptOOBEEula;
handler_map_["CancelOOBEUpdate"] =
&TestingAutomationProvider::CancelOOBEUpdate;
handler_map_["PickUserImage"] = &TestingAutomationProvider::PickUserImage;
handler_map_["SkipToLogin"] = &TestingAutomationProvider::SkipToLogin;
handler_map_["GetOOBEScreenInfo"] =
&TestingAutomationProvider::GetOOBEScreenInfo;
handler_map_["GetLoginInfo"] = &TestingAutomationProvider::GetLoginInfo;
handler_map_["ShowCreateAccountUI"] =
&TestingAutomationProvider::ShowCreateAccountUI;
handler_map_["ExecuteJavascriptInOOBEWebUI"] =
&TestingAutomationProvider::ExecuteJavascriptInOOBEWebUI;
handler_map_["LoginAsGuest"] = &TestingAutomationProvider::LoginAsGuest;
handler_map_["SubmitLoginForm"] =
&TestingAutomationProvider::SubmitLoginForm;
handler_map_["AddLoginEventObserver"] =
&TestingAutomationProvider::AddLoginEventObserver;
handler_map_["SignOut"] = &TestingAutomationProvider::SignOut;
handler_map_["LockScreen"] = &TestingAutomationProvider::LockScreen;
handler_map_["UnlockScreen"] = &TestingAutomationProvider::UnlockScreen;
handler_map_["SignoutInScreenLocker"] =
&TestingAutomationProvider::SignoutInScreenLocker;
handler_map_["GetBatteryInfo"] = &TestingAutomationProvider::GetBatteryInfo;
handler_map_["EnableSpokenFeedback"] =
&TestingAutomationProvider::EnableSpokenFeedback;
handler_map_["IsSpokenFeedbackEnabled"] =
&TestingAutomationProvider::IsSpokenFeedbackEnabled;
handler_map_["GetTimeInfo"] = &TestingAutomationProvider::GetTimeInfo;
handler_map_["SetTimezone"] = &TestingAutomationProvider::SetTimezone;
handler_map_["UpdateCheck"] = &TestingAutomationProvider::UpdateCheck;
handler_map_["GetVolumeInfo"] = &TestingAutomationProvider::GetVolumeInfo;
handler_map_["SetVolume"] = &TestingAutomationProvider::SetVolume;
handler_map_["SetMute"] = &TestingAutomationProvider::SetMute;
handler_map_["OpenCrosh"] = &TestingAutomationProvider::OpenCrosh;
browser_handler_map_["GetTimeInfo"] =
&TestingAutomationProvider::GetTimeInfo;
#endif // defined(OS_CHROMEOS)
browser_handler_map_["DisablePlugin"] =
&TestingAutomationProvider::DisablePlugin;
browser_handler_map_["EnablePlugin"] =
&TestingAutomationProvider::EnablePlugin;
browser_handler_map_["GetPluginsInfo"] =
&TestingAutomationProvider::GetPluginsInfo;
browser_handler_map_["GetNavigationInfo"] =
&TestingAutomationProvider::GetNavigationInfo;
browser_handler_map_["PerformActionOnInfobar"] =
&TestingAutomationProvider::PerformActionOnInfobar;
browser_handler_map_["GetHistoryInfo"] =
&TestingAutomationProvider::GetHistoryInfo;
browser_handler_map_["GetOmniboxInfo"] =
&TestingAutomationProvider::GetOmniboxInfo;
browser_handler_map_["SetOmniboxText"] =
&TestingAutomationProvider::SetOmniboxText;
browser_handler_map_["OmniboxAcceptInput"] =
&TestingAutomationProvider::OmniboxAcceptInput;
browser_handler_map_["OmniboxMovePopupSelection"] =
&TestingAutomationProvider::OmniboxMovePopupSelection;
browser_handler_map_["LoadSearchEngineInfo"] =
&TestingAutomationProvider::LoadSearchEngineInfo;
browser_handler_map_["GetSearchEngineInfo"] =
&TestingAutomationProvider::GetSearchEngineInfo;
browser_handler_map_["AddOrEditSearchEngine"] =
&TestingAutomationProvider::AddOrEditSearchEngine;
browser_handler_map_["PerformActionOnSearchEngine"] =
&TestingAutomationProvider::PerformActionOnSearchEngine;
browser_handler_map_["SetWindowDimensions"] =
&TestingAutomationProvider::SetWindowDimensions;
browser_handler_map_["GetDownloadsInfo"] =
&TestingAutomationProvider::GetDownloadsInfo;
browser_handler_map_["WaitForAllDownloadsToComplete"] =
&TestingAutomationProvider::WaitForAllDownloadsToComplete;
browser_handler_map_["PerformActionOnDownload"] =
&TestingAutomationProvider::PerformActionOnDownload;
browser_handler_map_["GetInitialLoadTimes"] =
&TestingAutomationProvider::GetInitialLoadTimes;
browser_handler_map_["SaveTabContents"] =
&TestingAutomationProvider::SaveTabContents;
browser_handler_map_["AddSavedPassword"] =
&TestingAutomationProvider::AddSavedPassword;
browser_handler_map_["RemoveSavedPassword"] =
&TestingAutomationProvider::RemoveSavedPassword;
browser_handler_map_["GetSavedPasswords"] =
&TestingAutomationProvider::GetSavedPasswords;
browser_handler_map_["FindInPage"] = &TestingAutomationProvider::FindInPage;
browser_handler_map_["GetAllNotifications"] =
&TestingAutomationProvider::GetAllNotifications;
browser_handler_map_["CloseNotification"] =
&TestingAutomationProvider::CloseNotification;
browser_handler_map_["WaitForNotificationCount"] =
&TestingAutomationProvider::WaitForNotificationCount;
browser_handler_map_["GetNTPInfo"] =
&TestingAutomationProvider::GetNTPInfo;
browser_handler_map_["RemoveNTPMostVisitedThumbnail"] =
&TestingAutomationProvider::RemoveNTPMostVisitedThumbnail;
browser_handler_map_["RestoreAllNTPMostVisitedThumbnails"] =
&TestingAutomationProvider::RestoreAllNTPMostVisitedThumbnails;
browser_handler_map_["KillRendererProcess"] =
&TestingAutomationProvider::KillRendererProcess;
browser_handler_map_["LaunchApp"] = &TestingAutomationProvider::LaunchApp;
browser_handler_map_["SetAppLaunchType"] =
&TestingAutomationProvider::SetAppLaunchType;
browser_handler_map_["GetV8HeapStats"] =
&TestingAutomationProvider::GetV8HeapStats;
browser_handler_map_["GetFPS"] =
&TestingAutomationProvider::GetFPS;
browser_handler_map_["IsFullscreenForBrowser"] =
&TestingAutomationProvider::IsFullscreenForBrowser;
browser_handler_map_["IsFullscreenForTab"] =
&TestingAutomationProvider::IsFullscreenForTab;
browser_handler_map_["IsMouseLocked"] =
&TestingAutomationProvider::IsMouseLocked;
browser_handler_map_["IsMouseLockPermissionRequested"] =
&TestingAutomationProvider::IsMouseLockPermissionRequested;
browser_handler_map_["IsFullscreenPermissionRequested"] =
&TestingAutomationProvider::IsFullscreenPermissionRequested;
browser_handler_map_["IsFullscreenBubbleDisplayed"] =
&TestingAutomationProvider::IsFullscreenBubbleDisplayed;
browser_handler_map_["IsFullscreenBubbleDisplayingButtons"] =
&TestingAutomationProvider::IsFullscreenBubbleDisplayingButtons;
browser_handler_map_["AcceptCurrentFullscreenOrMouseLockRequest"] =
&TestingAutomationProvider::AcceptCurrentFullscreenOrMouseLockRequest;
browser_handler_map_["DenyCurrentFullscreenOrMouseLockRequest"] =
&TestingAutomationProvider::DenyCurrentFullscreenOrMouseLockRequest;
}
scoped_ptr<DictionaryValue> TestingAutomationProvider::ParseJSONRequestCommand(
const std::string& json_request,
std::string* command,
std::string* error) {
scoped_ptr<DictionaryValue> dict_value;
scoped_ptr<Value> values(base::JSONReader::ReadAndReturnError(json_request,
base::JSON_ALLOW_TRAILING_COMMAS, NULL, error));
if (values.get()) {
// Make sure input is a dict with a string command.
if (values->GetType() != Value::TYPE_DICTIONARY) {
*error = "Command dictionary is not a dictionary.";
} else {
dict_value.reset(static_cast<DictionaryValue*>(values.release()));
if (!dict_value->GetStringASCII("command", command)) {
*error = "Command key string missing from dictionary.";
dict_value.reset(NULL);
}
}
}
return dict_value.Pass();
}
void TestingAutomationProvider::SendJSONRequestWithBrowserHandle(
int handle,
const std::string& json_request,
IPC::Message* reply_message) {
Browser* browser = NULL;
if (browser_tracker_->ContainsHandle(handle))
browser = browser_tracker_->GetResource(handle);
if (browser || handle < 0) {
SendJSONRequest(browser, json_request, reply_message);
} else {
AutomationJSONReply(this, reply_message).SendError(
"The browser window does not exist.");
}
}
void TestingAutomationProvider::SendJSONRequestWithBrowserIndex(
int index,
const std::string& json_request,
IPC::Message* reply_message) {
Browser* browser = index < 0 ? NULL : automation_util::GetBrowserAt(index);
if (!browser && index >= 0) {
AutomationJSONReply(this, reply_message).SendError(base::StringPrintf(
"Browser window with index=%d does not exist.", index));
} else {
SendJSONRequest(browser, json_request, reply_message);
}
}
void TestingAutomationProvider::SendJSONRequest(Browser* browser,
const std::string& json_request,
IPC::Message* reply_message) {
std::string command, error_string;
scoped_ptr<DictionaryValue> dict_value(
ParseJSONRequestCommand(json_request, &command, &error_string));
if (!dict_value.get() || command.empty()) {
AutomationJSONReply(this, reply_message).SendError(error_string);
return;
}
if (handler_map_.empty() || browser_handler_map_.empty())
BuildJSONHandlerMaps();
// Look for command in handlers that take a Browser.
if (browser_handler_map_.find(std::string(command)) !=
browser_handler_map_.end() && browser) {
(this->*browser_handler_map_[command])(browser, dict_value.get(),
reply_message);
// Look for command in handlers that don't take a Browser.
} else if (handler_map_.find(std::string(command)) != handler_map_.end()) {
(this->*handler_map_[command])(dict_value.get(), reply_message);
// Command has no handler.
} else {
error_string = base::StringPrintf("Unknown command '%s'. Options: ",
command.c_str());
for (std::map<std::string, JsonHandler>::const_iterator it =
handler_map_.begin(); it != handler_map_.end(); ++it) {
error_string += it->first + ", ";
}
for (std::map<std::string, BrowserJsonHandler>::const_iterator it =
browser_handler_map_.begin(); it != browser_handler_map_.end(); ++it) {
error_string += it->first + ", ";
}
AutomationJSONReply(this, reply_message).SendError(error_string);
}
}
void TestingAutomationProvider::BringBrowserToFrontJSON(
DictionaryValue* args,
IPC::Message* reply_message) {
AutomationJSONReply reply(this, reply_message);
Browser* browser;
std::string error_msg;
if (!GetBrowserFromJSONArgs(args, &browser, &error_msg)) {
reply.SendError(error_msg);
return;
}
browser->window()->Activate();
reply.SendSuccess(NULL);
}
// Sample json input: { "command": "SetWindowDimensions",
// "x": 20, # optional
// "y": 20, # optional
// "width": 800, # optional
// "height": 600 } # optional
void TestingAutomationProvider::SetWindowDimensions(
Browser* browser,
DictionaryValue* args,
IPC::Message* reply_message) {
gfx::Rect rect = browser->window()->GetRestoredBounds();
int x, y, width, height;
if (args->GetInteger("x", &x))
rect.set_x(x);
if (args->GetInteger("y", &y))
rect.set_y(y);
if (args->GetInteger("width", &width))
rect.set_width(width);
if (args->GetInteger("height", &height))
rect.set_height(height);
browser->window()->SetBounds(rect);
AutomationJSONReply(this, reply_message).SendSuccess(NULL);
}
ListValue* TestingAutomationProvider::GetInfobarsInfo(WebContents* wc) {
// Each infobar may have different properties depending on the type.
ListValue* infobars = new ListValue;
InfoBarService* infobar_service = InfoBarService::FromWebContents(wc);
for (size_t i = 0; i < infobar_service->infobar_count(); ++i) {
DictionaryValue* infobar_item = new DictionaryValue;
InfoBarDelegate* infobar = infobar_service->infobar_at(i);
switch (infobar->GetInfoBarAutomationType()) {
case InfoBarDelegate::CONFIRM_INFOBAR:
infobar_item->SetString("type", "confirm_infobar");
break;
case InfoBarDelegate::PASSWORD_INFOBAR:
infobar_item->SetString("type", "password_infobar");
break;
case InfoBarDelegate::RPH_INFOBAR:
infobar_item->SetString("type", "rph_infobar");
break;
case InfoBarDelegate::UNKNOWN_INFOBAR:
infobar_item->SetString("type", "unknown_infobar");
break;
}
if (infobar->AsConfirmInfoBarDelegate()) {
// Also covers ThemeInstalledInfoBarDelegate.
ConfirmInfoBarDelegate* confirm_infobar =
infobar->AsConfirmInfoBarDelegate();
infobar_item->SetString("text", confirm_infobar->GetMessageText());
infobar_item->SetString("link_text", confirm_infobar->GetLinkText());
ListValue* buttons_list = new ListValue;
int buttons = confirm_infobar->GetButtons();
if (buttons & ConfirmInfoBarDelegate::BUTTON_OK) {
StringValue* button_label = new StringValue(
confirm_infobar->GetButtonLabel(
ConfirmInfoBarDelegate::BUTTON_OK));
buttons_list->Append(button_label);
}
if (buttons & ConfirmInfoBarDelegate::BUTTON_CANCEL) {
StringValue* button_label = new StringValue(
confirm_infobar->GetButtonLabel(
ConfirmInfoBarDelegate::BUTTON_CANCEL));
buttons_list->Append(button_label);
}
infobar_item->Set("buttons", buttons_list);
} else if (infobar->AsExtensionInfoBarDelegate()) {
infobar_item->SetString("type", "extension_infobar");
} else {
infobar_item->SetString("type", "unknown_infobar");
}
infobars->Append(infobar_item);
}
return infobars;
}
// Sample json input: { "command": "PerformActionOnInfobar",
// "action": "dismiss",
// "infobar_index": 0,
// "tab_index": 0 }
// Sample output: {}
void TestingAutomationProvider::PerformActionOnInfobar(
Browser* browser,
DictionaryValue* args,
IPC::Message* reply_message) {
AutomationJSONReply reply(this, reply_message);
int tab_index;
int infobar_index_int;
std::string action;
if (!args->GetInteger("tab_index", &tab_index) ||
!args->GetInteger("infobar_index", &infobar_index_int) ||
!args->GetString("action", &action)) {
reply.SendError("Invalid or missing args");
return;
}
size_t infobar_index = static_cast<size_t>(infobar_index_int);
WebContents* web_contents =
browser->tab_strip_model()->GetWebContentsAt(tab_index);
if (!web_contents) {
reply.SendError(base::StringPrintf("No such tab at index %d", tab_index));
return;
}
InfoBarService* infobar_service =
InfoBarService::FromWebContents(web_contents);
if (infobar_index >= infobar_service->infobar_count()) {
reply.SendError(base::StringPrintf("No such infobar at index %" PRIuS,
infobar_index));
return;
}
InfoBarDelegate* infobar_delegate =
infobar_service->infobar_at(infobar_index);
if (action == "dismiss") {
infobar_delegate->InfoBarDismissed();
infobar_service->RemoveInfoBar(infobar_delegate);
reply.SendSuccess(NULL);
return;
}
if ((action == "accept") || (action == "cancel")) {
ConfirmInfoBarDelegate* confirm_infobar_delegate =
infobar_delegate->AsConfirmInfoBarDelegate();
if (!confirm_infobar_delegate) {
reply.SendError("Not a confirm infobar");
return;
}
if ((action == "accept") ?
confirm_infobar_delegate->Accept() : confirm_infobar_delegate->Cancel())
infobar_service->RemoveInfoBar(infobar_delegate);
reply.SendSuccess(NULL);
return;
}
reply.SendError("Invalid action");
}
namespace {
// Gets info about BrowserChildProcessHost. Must run on IO thread to
// honor the semantics of BrowserChildProcessHostIterator.
// Used by AutomationProvider::GetBrowserInfo().
void GetChildProcessHostInfo(ListValue* child_processes) {
for (BrowserChildProcessHostIterator iter; !iter.Done(); ++iter) {
// Only add processes which are already started, since we need their handle.
if (iter.GetData().handle == base::kNullProcessHandle)
continue;
DictionaryValue* item = new DictionaryValue;
item->SetString("name", iter.GetData().name);
item->SetString(
"type",
content::GetProcessTypeNameInEnglish(iter.GetData().process_type));
item->SetInteger("pid", base::GetProcId(iter.GetData().handle));
child_processes->Append(item);
}
}
} // namespace
// Sample json input: { "command": "GetBrowserInfo" }
// Refer to GetBrowserInfo() in chrome/test/pyautolib/pyauto.py for
// sample json output.
void TestingAutomationProvider::GetBrowserInfo(
DictionaryValue* args,
IPC::Message* reply_message) {
base::ThreadRestrictions::ScopedAllowIO allow_io; // needed for PathService
DictionaryValue* properties = new DictionaryValue;
properties->SetString("ChromeVersion", chrome::kChromeVersion);
properties->SetString("BrowserProcessExecutableName",
chrome::kBrowserProcessExecutableName);
properties->SetString("HelperProcessExecutableName",
chrome::kHelperProcessExecutableName);
properties->SetString("BrowserProcessExecutablePath",
chrome::kBrowserProcessExecutablePath);
properties->SetString("HelperProcessExecutablePath",
chrome::kHelperProcessExecutablePath);
properties->SetString("command_line_string",
CommandLine::ForCurrentProcess()->GetCommandLineString());
base::FilePath dumps_path;
PathService::Get(chrome::DIR_CRASH_DUMPS, &dumps_path);
properties->SetString("DIR_CRASH_DUMPS", dumps_path.value());
#if defined(USE_AURA)
properties->SetBoolean("aura", true);
#else
properties->SetBoolean("aura", false);
#endif
std::string branding;
#if defined(GOOGLE_CHROME_BUILD)
branding = "Google Chrome";
#elif defined(CHROMIUM_BUILD)
branding = "Chromium";
#else
branding = "Unknown Branding";
#endif
properties->SetString("branding", branding);
bool is_official_build = false;
#if defined(OFFICIAL_BUILD)
is_official_build = true;
#endif
properties->SetBoolean("is_official", is_official_build);
scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
return_value->Set("properties", properties);
return_value->SetInteger("browser_pid", base::GetCurrentProcId());
// Add info about all windows in a list of dictionaries, one dictionary
// item per window.
ListValue* windows = new ListValue;
int windex = 0;
for (chrome::BrowserIterator it; !it.done(); it.Next(), ++windex) {
DictionaryValue* browser_item = new DictionaryValue;
Browser* browser = *it;
browser_item->SetInteger("index", windex);
// Window properties
gfx::Rect rect = browser->window()->GetRestoredBounds();
browser_item->SetInteger("x", rect.x());
browser_item->SetInteger("y", rect.y());
browser_item->SetInteger("width", rect.width());
browser_item->SetInteger("height", rect.height());
browser_item->SetBoolean("fullscreen",
browser->window()->IsFullscreen());
ListValue* visible_page_actions = new ListValue;
// Add info about all visible page actions. Skipped on panels, which do not
// have a location bar.
LocationBar* loc_bar = browser->window()->GetLocationBar();
if (loc_bar) {
LocationBarTesting* loc_bar_test =
loc_bar->GetLocationBarForTesting();
size_t page_action_visible_count =
static_cast<size_t>(loc_bar_test->PageActionVisibleCount());
for (size_t i = 0; i < page_action_visible_count; ++i) {
StringValue* extension_id = new StringValue(
loc_bar_test->GetVisiblePageAction(i)->extension_id());
visible_page_actions->Append(extension_id);
}
}
browser_item->Set("visible_page_actions", visible_page_actions);
browser_item->SetInteger("selected_tab",
browser->tab_strip_model()->active_index());
browser_item->SetBoolean("incognito",
browser->profile()->IsOffTheRecord());
browser_item->SetString("profile_path",
browser->profile()->GetPath().BaseName().MaybeAsASCII());
std::string type;
switch (browser->type()) {
case Browser::TYPE_TABBED:
type = "tabbed";
break;
case Browser::TYPE_POPUP:
type = "popup";
break;
default:
type = "unknown";
break;
}
browser_item->SetString("type", type);
// For each window, add info about all tabs in a list of dictionaries,
// one dictionary item per tab.
ListValue* tabs = new ListValue;
for (int i = 0; i < browser->tab_strip_model()->count(); ++i) {
WebContents* wc = browser->tab_strip_model()->GetWebContentsAt(i);
DictionaryValue* tab = new DictionaryValue;
tab->SetInteger("index", i);
tab->SetString("url", wc->GetURL().spec());
tab->SetInteger("renderer_pid",
base::GetProcId(wc->GetRenderProcessHost()->GetHandle()));
tab->Set("infobars", GetInfobarsInfo(wc));
tab->SetBoolean("pinned", browser->tab_strip_model()->IsTabPinned(i));
tabs->Append(tab);
}
browser_item->Set("tabs", tabs);
windows->Append(browser_item);
}
return_value->Set("windows", windows);
#if defined(OS_LINUX)
int flags = ChildProcessHost::CHILD_ALLOW_SELF;
#else
int flags = ChildProcessHost::CHILD_NORMAL;
#endif
// Add all extension processes in a list of dictionaries, one dictionary
// item per extension process.
ListValue* extension_views = new ListValue;
ProfileManager* profile_manager = g_browser_process->profile_manager();
std::vector<Profile*> profiles(profile_manager->GetLoadedProfiles());
for (size_t i = 0; i < profiles.size(); ++i) {
ExtensionProcessManager* process_manager =
extensions::ExtensionSystem::Get(profiles[i])->process_manager();
if (!process_manager)
continue;
const ExtensionProcessManager::ViewSet view_set =
process_manager->GetAllViews();
for (ExtensionProcessManager::ViewSet::const_iterator jt =
view_set.begin();
jt != view_set.end(); ++jt) {
content::RenderViewHost* render_view_host = *jt;
// Don't add dead extension processes.
if (!render_view_host->IsRenderViewLive())
continue;
// Don't add views for which we can't obtain an extension.
// TODO(benwells): work out why this happens. It only happens for one
// test, and only on the bots.
const Extension* extension =
process_manager->GetExtensionForRenderViewHost(render_view_host);
if (!extension)
continue;
DictionaryValue* item = new DictionaryValue;
item->SetString("name", extension->name());
item->SetString("extension_id", extension->id());
item->SetInteger(
"pid",
base::GetProcId(render_view_host->GetProcess()->GetHandle()));
DictionaryValue* view = new DictionaryValue;
view->SetInteger(
"render_process_id",
render_view_host->GetProcess()->GetID());
view->SetInteger(
"render_view_id",
render_view_host->GetRoutingID());
item->Set("view", view);
std::string type;
WebContents* web_contents =
WebContents::FromRenderViewHost(render_view_host);
extensions::ViewType view_type = extensions::GetViewType(web_contents);
switch (view_type) {
case extensions::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE:
type = "EXTENSION_BACKGROUND_PAGE";
break;
case extensions::VIEW_TYPE_EXTENSION_POPUP:
type = "EXTENSION_POPUP";
break;
case extensions::VIEW_TYPE_EXTENSION_INFOBAR:
type = "EXTENSION_INFOBAR";
break;
case extensions::VIEW_TYPE_EXTENSION_DIALOG:
type = "EXTENSION_DIALOG";
break;
case extensions::VIEW_TYPE_APP_SHELL:
type = "APP_SHELL";
break;
case extensions::VIEW_TYPE_PANEL:
type = "PANEL";
break;
default:
type = "unknown";
break;
}
item->SetString("view_type", type);
item->SetString("url", web_contents->GetURL().spec());
item->SetBoolean("loaded", !render_view_host->IsLoading());
extension_views->Append(item);
}
}
return_value->Set("extension_views", extension_views);
return_value->SetString("child_process_path",
ChildProcessHost::GetChildPath(flags).value());
// Child processes are the processes for plugins and other workers.
// Add all child processes in a list of dictionaries, one dictionary item
// per child process.
ListValue* child_processes = new ListValue;
return_value->Set("child_processes", child_processes);
BrowserThread::PostTaskAndReply(
BrowserThread::IO, FROM_HERE,
base::Bind(&GetChildProcessHostInfo, child_processes),
base::Bind(&AutomationJSONReply::SendSuccess,
base::Owned(new AutomationJSONReply(this, reply_message)),
base::Owned(return_value.release())));
}
// Sample json input: { "command": "GetProcessInfo" }
// Refer to GetProcessInfo() in chrome/test/pyautolib/pyauto.py for
// sample json output.
void TestingAutomationProvider::GetProcessInfo(
DictionaryValue* args,
IPC::Message* reply_message) {
scoped_refptr<ProcessInfoObserver>
proc_observer(new ProcessInfoObserver(this, reply_message));
// TODO(jamescook): Maybe this shouldn't update UMA stats?
proc_observer->StartFetch(MemoryDetails::UPDATE_USER_METRICS);
}
// Sample json input: { "command": "GetNavigationInfo" }
// Refer to GetNavigationInfo() in chrome/test/pyautolib/pyauto.py for
// sample json output.
void TestingAutomationProvider::GetNavigationInfo(
Browser* browser,
DictionaryValue* args,
IPC::Message* reply_message) {
AutomationJSONReply reply(this, reply_message);
int tab_index;
WebContents* web_contents = NULL;
if (!args->GetInteger("tab_index", &tab_index) ||
!(web_contents =
browser->tab_strip_model()->GetWebContentsAt(tab_index))) {
reply.SendError("tab_index missing or invalid.");
return;
}
scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
const NavigationController& controller = web_contents->GetController();
NavigationEntry* nav_entry = controller.GetActiveEntry();
DCHECK(nav_entry);
// Security info.
DictionaryValue* ssl = new DictionaryValue;
std::map<content::SecurityStyle, std::string> style_to_string;
style_to_string[content::SECURITY_STYLE_UNKNOWN] = "SECURITY_STYLE_UNKNOWN";
style_to_string[content::SECURITY_STYLE_UNAUTHENTICATED] =
"SECURITY_STYLE_UNAUTHENTICATED";
style_to_string[content::SECURITY_STYLE_AUTHENTICATION_BROKEN] =
"SECURITY_STYLE_AUTHENTICATION_BROKEN";
style_to_string[content::SECURITY_STYLE_AUTHENTICATED] =
"SECURITY_STYLE_AUTHENTICATED";
SSLStatus ssl_status = nav_entry->GetSSL();
ssl->SetString("security_style",
style_to_string[ssl_status.security_style]);
ssl->SetBoolean("ran_insecure_content",
!!(ssl_status.content_status & SSLStatus::RAN_INSECURE_CONTENT));
ssl->SetBoolean("displayed_insecure_content",
!!(ssl_status.content_status & SSLStatus::DISPLAYED_INSECURE_CONTENT));
return_value->Set("ssl", ssl);
// Page type.
std::map<content::PageType, std::string> pagetype_to_string;
pagetype_to_string[content::PAGE_TYPE_NORMAL] = "NORMAL_PAGE";
pagetype_to_string[content::PAGE_TYPE_ERROR] = "ERROR_PAGE";
pagetype_to_string[content::PAGE_TYPE_INTERSTITIAL] =
"INTERSTITIAL_PAGE";
return_value->SetString("page_type",
pagetype_to_string[nav_entry->GetPageType()]);
return_value->SetString("favicon_url", nav_entry->GetFavicon().url.spec());
reply.SendSuccess(return_value.get());
}
// Sample json input: { "command": "GetHistoryInfo",
// "search_text": "some text" }
// Refer chrome/test/pyautolib/history_info.py for sample json output.
void TestingAutomationProvider::GetHistoryInfo(Browser* browser,
DictionaryValue* args,
IPC::Message* reply_message) {
consumer_.CancelAllRequests();
string16 search_text;
args->GetString("search_text", &search_text);
// Fetch history.
HistoryService* hs = HistoryServiceFactory::GetForProfile(
browser->profile(), Profile::EXPLICIT_ACCESS);
history::QueryOptions options;
// The observer owns itself. It deletes itself after it fetches history.
AutomationProviderHistoryObserver* history_observer =
new AutomationProviderHistoryObserver(this, reply_message);
hs->QueryHistory(
search_text,
options,
&consumer_,
base::Bind(&AutomationProviderHistoryObserver::HistoryQueryComplete,
base::Unretained(history_observer)));
}
// Sample json input: { "command": "GetDownloadsInfo" }
// Refer chrome/test/pyautolib/download_info.py for sample json output.
void TestingAutomationProvider::GetDownloadsInfo(Browser* browser,
DictionaryValue* args,
IPC::Message* reply_message) {
AutomationJSONReply reply(this, reply_message);
scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
ListValue* list_of_downloads = new ListValue;
DownloadService* download_service(
DownloadServiceFactory::GetForBrowserContext(browser->profile()));
if (download_service->HasCreatedDownloadManager()) {
std::vector<DownloadItem*> downloads;
BrowserContext::GetDownloadManager(browser->profile())->GetAllDownloads(
&downloads);
for (std::vector<DownloadItem*>::iterator it = downloads.begin();
it != downloads.end();
it++) { // Fill info about each download item.
list_of_downloads->Append(GetDictionaryFromDownloadItem(
*it, browser->profile()->IsOffTheRecord()));
}
}
return_value->Set("downloads", list_of_downloads);
reply.SendSuccess(return_value.get());
}
void TestingAutomationProvider::WaitForAllDownloadsToComplete(
Browser* browser,
DictionaryValue* args,
IPC::Message* reply_message) {
ListValue* pre_download_ids = NULL;
if (!args->GetList("pre_download_ids", &pre_download_ids)) {
AutomationJSONReply(this, reply_message)
.SendError(
base::StringPrintf("List of IDs of previous downloads required."));
return;
}
DownloadService* download_service =
DownloadServiceFactory::GetForBrowserContext(browser->profile());
if (!download_service->HasCreatedDownloadManager()) {
// No download manager, so no downloads to wait for.
AutomationJSONReply(this, reply_message).SendSuccess(NULL);
return;
}
// This observer will delete itself.
new AllDownloadsCompleteObserver(
this, reply_message,
BrowserContext::GetDownloadManager(browser->profile()),
pre_download_ids);
}
// See PerformActionOnDownload() in chrome/test/pyautolib/pyauto.py for sample
// json input and output.
void TestingAutomationProvider::PerformActionOnDownload(
Browser* browser,
DictionaryValue* args,
IPC::Message* reply_message) {
int id;
std::string action;
DownloadService* download_service =
DownloadServiceFactory::GetForBrowserContext(browser->profile());
if (!download_service->HasCreatedDownloadManager()) {
AutomationJSONReply(this, reply_message).SendError("No download manager.");
return;
}
if (!args->GetInteger("id", &id) || !args->GetString("action", &action)) {
AutomationJSONReply(this, reply_message)
.SendError("Must include int id and string action.");
return;
}
DownloadManager* download_manager =
BrowserContext::GetDownloadManager(browser->profile());
DownloadItem* selected_item = download_manager->GetDownload(id);
if (!selected_item) {
AutomationJSONReply(this, reply_message)
.SendError(base::StringPrintf("No download with an id of %d\n", id));
return;
}
DownloadItem::DownloadState download_state = selected_item->GetState();
// We need to be IN_PROGRESS for these actions.
if ((action == "pause" || action == "resume" || action == "cancel") &&
download_state != DownloadItem::IN_PROGRESS) {
AutomationJSONReply(this, reply_message)
.SendError(base::StringPrintf(
"Action '%s' called on download that is not in progress.",
action.c_str()));
return;
}
if (action == "open") {
selected_item->AddObserver(
new AutomationProviderDownloadUpdatedObserver(
this, reply_message, true, browser->profile()->IsOffTheRecord()));
selected_item->OpenDownload();
} else if (action == "toggle_open_files_like_this") {
DownloadPrefs* prefs =
DownloadPrefs::FromBrowserContext(selected_item->GetBrowserContext());
base::FilePath path = selected_item->GetTargetFilePath();
if (!selected_item->ShouldOpenFileBasedOnExtension())
prefs->EnableAutoOpenBasedOnExtension(path);
else
prefs->DisableAutoOpenBasedOnExtension(path);
AutomationJSONReply(this, reply_message).SendSuccess(NULL);
} else if (action == "remove") {
new AutomationProviderDownloadModelChangedObserver(
this, reply_message, download_manager);
selected_item->Remove();
} else if (action == "decline_dangerous_download") {
new AutomationProviderDownloadModelChangedObserver(
this, reply_message, download_manager);
selected_item->Remove();
} else if (action == "save_dangerous_download") {
selected_item->AddObserver(new AutomationProviderDownloadUpdatedObserver(
this, reply_message, false, browser->profile()->IsOffTheRecord()));
selected_item->ValidateDangerousDownload();
} else if (action == "pause") {
if (selected_item->IsPaused()) {
// Action would be a no-op; respond right from here. No-op implies
// the test is poorly written or failing, so make it an error return.
AutomationJSONReply(this, reply_message)
.SendError("Action 'pause' called on already paused download.");
} else {
selected_item->AddObserver(new AutomationProviderDownloadUpdatedObserver(
this, reply_message, false, browser->profile()->IsOffTheRecord()));
selected_item->Pause();
}
} else if (action == "resume") {
if (!selected_item->IsPaused()) {
// Action would be a no-op; respond right from here. No-op implies
// the test is poorly written or failing, so make it an error return.
AutomationJSONReply(this, reply_message)
.SendError("Action 'resume' called on unpaused download.");
} else {
selected_item->AddObserver(new AutomationProviderDownloadUpdatedObserver(
this, reply_message, false, browser->profile()->IsOffTheRecord()));
selected_item->Resume();
}
} else if (action == "cancel") {
selected_item->AddObserver(new AutomationProviderDownloadUpdatedObserver(
this, reply_message, false, browser->profile()->IsOffTheRecord()));
selected_item->Cancel(true);
} else {
AutomationJSONReply(this, reply_message)
.SendError(
base::StringPrintf("Invalid action '%s' given.", action.c_str()));
}
}
void TestingAutomationProvider::SetDownloadShelfVisibleJSON(
DictionaryValue* args,
IPC::Message* reply_message) {
AutomationJSONReply reply(this, reply_message);
Browser* browser;
std::string error_msg;
bool is_visible;
if (!GetBrowserFromJSONArgs(args, &browser, &error_msg)) {
reply.SendError(error_msg);
return;
}
if (!args->GetBoolean("is_visible", &is_visible)) {
reply.SendError("'is_visible' missing or invalid.");
return;
}
if (is_visible) {
browser->window()->GetDownloadShelf()->Show();
} else {
browser->window()->GetDownloadShelf()->Close(DownloadShelf::AUTOMATIC);
}
reply.SendSuccess(NULL);
}
void TestingAutomationProvider::IsDownloadShelfVisibleJSON(
DictionaryValue* args,
IPC::Message* reply_message) {
AutomationJSONReply reply(this, reply_message);
Browser* browser;
std::string error_msg;
if (!GetBrowserFromJSONArgs(args, &browser, &error_msg)) {
reply.SendError(error_msg);
return;
}
DictionaryValue dict;
dict.SetBoolean("is_visible", browser->window()->IsDownloadShelfVisible());
reply.SendSuccess(&dict);
}
void TestingAutomationProvider::GetDownloadDirectoryJSON(
DictionaryValue* args,
IPC::Message* reply_message) {
AutomationJSONReply reply(this, reply_message);
WebContents* web_contents;
std::string error;
if (!GetTabFromJSONArgs(args, &web_contents, &error)) {
reply.SendError(error);
return;
}
DownloadManager* dlm =
BrowserContext::GetDownloadManager(
web_contents->GetController().GetBrowserContext());
DictionaryValue dict;
dict.SetString("path",
DownloadPrefs::FromDownloadManager(dlm)->DownloadPath().value());
reply.SendSuccess(&dict);
}
// Sample JSON input { "command": "LoadSearchEngineInfo" }
void TestingAutomationProvider::LoadSearchEngineInfo(
Browser* browser,
DictionaryValue* args,
IPC::Message* reply_message) {
TemplateURLService* url_model =
TemplateURLServiceFactory::GetForProfile(browser->profile());
if (url_model->loaded()) {
AutomationJSONReply(this, reply_message).SendSuccess(NULL);
return;
}
url_model->AddObserver(new AutomationProviderSearchEngineObserver(
this, browser->profile(), reply_message));
url_model->Load();
}
// Sample JSON input { "command": "GetSearchEngineInfo" }
// Refer to pyauto.py for sample output.
void TestingAutomationProvider::GetSearchEngineInfo(
Browser* browser,
DictionaryValue* args,
IPC::Message* reply_message) {
TemplateURLService* url_model =
TemplateURLServiceFactory::GetForProfile(browser->profile());
scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
ListValue* search_engines = new ListValue;
TemplateURLService::TemplateURLVector template_urls =
url_model->GetTemplateURLs();
for (TemplateURLService::TemplateURLVector::const_iterator it =
template_urls.begin(); it != template_urls.end(); ++it) {
DictionaryValue* search_engine = new DictionaryValue;
search_engine->SetString("short_name", UTF16ToUTF8((*it)->short_name()));
search_engine->SetString("keyword", UTF16ToUTF8((*it)->keyword()));
search_engine->SetBoolean("in_default_list", (*it)->ShowInDefaultList());
search_engine->SetBoolean("is_default",
(*it) == url_model->GetDefaultSearchProvider());
search_engine->SetBoolean("is_valid", (*it)->url_ref().IsValid());
search_engine->SetBoolean("supports_replacement",
(*it)->url_ref().SupportsReplacement());
search_engine->SetString("url", (*it)->url());
search_engine->SetString("host", (*it)->url_ref().GetHost());
search_engine->SetString("path", (*it)->url_ref().GetPath());
search_engine->SetString("display_url",
UTF16ToUTF8((*it)->url_ref().DisplayURL()));
search_engines->Append(search_engine);
}
return_value->Set("search_engines", search_engines);
AutomationJSONReply(this, reply_message).SendSuccess(return_value.get());
}
// Refer to pyauto.py for sample JSON input.
void TestingAutomationProvider::AddOrEditSearchEngine(
Browser* browser,
DictionaryValue* args,
IPC::Message* reply_message) {
TemplateURLService* url_model =
TemplateURLServiceFactory::GetForProfile(browser->profile());
string16 new_title;
string16 new_keyword;
std::string new_url;
std::string keyword;
if (!args->GetString("new_title", &new_title) ||
!args->GetString("new_keyword", &new_keyword) ||
!args->GetString("new_url", &new_url)) {
AutomationJSONReply(this, reply_message).SendError(
"One or more inputs invalid");
return;
}
std::string new_ref_url = TemplateURLRef::DisplayURLToURLRef(
UTF8ToUTF16(new_url));
scoped_ptr<KeywordEditorController> controller(
new KeywordEditorController(browser->profile()));
if (args->GetString("keyword", &keyword)) {
TemplateURL* template_url =
url_model->GetTemplateURLForKeyword(UTF8ToUTF16(keyword));
if (template_url == NULL) {
AutomationJSONReply(this, reply_message).SendError(
"No match for keyword: " + keyword);
return;
}
url_model->AddObserver(new AutomationProviderSearchEngineObserver(
this, browser->profile(), reply_message));
controller->ModifyTemplateURL(template_url, new_title, new_keyword,
new_ref_url);
} else {
url_model->AddObserver(new AutomationProviderSearchEngineObserver(
this, browser->profile(), reply_message));
controller->AddTemplateURL(new_title, new_keyword, new_ref_url);
}
}
// Sample json input: { "command": "PerformActionOnSearchEngine",
// "keyword": keyword, "action": action }
void TestingAutomationProvider::PerformActionOnSearchEngine(
Browser* browser,
DictionaryValue* args,
IPC::Message* reply_message) {
TemplateURLService* url_model =
TemplateURLServiceFactory::GetForProfile(browser->profile());
std::string keyword;
std::string action;
if (!args->GetString("keyword", &keyword) ||
!args->GetString("action", &action)) {
AutomationJSONReply(this, reply_message).SendError(
"One or more inputs invalid");
return;
}
TemplateURL* template_url =
url_model->GetTemplateURLForKeyword(UTF8ToUTF16(keyword));
if (template_url == NULL) {
AutomationJSONReply(this, reply_message).SendError(
"No match for keyword: " + keyword);
return;
}
if (action == "delete") {
url_model->AddObserver(new AutomationProviderSearchEngineObserver(
this, browser->profile(), reply_message));
url_model->Remove(template_url);
} else if (action == "default") {
url_model->AddObserver(new AutomationProviderSearchEngineObserver(
this, browser->profile(), reply_message));
url_model->SetDefaultSearchProvider(template_url);
} else {
AutomationJSONReply(this, reply_message).SendError(
"Invalid action: " + action);
}
}
// Sample json input: { "command": "GetLocalStatePrefsInfo" }
// Refer chrome/test/pyautolib/prefs_info.py for sample json output.
void TestingAutomationProvider::GetLocalStatePrefsInfo(
DictionaryValue* args,
IPC::Message* reply_message) {
scoped_ptr<DictionaryValue> items(
g_browser_process->local_state()->GetPreferenceValues());
scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
return_value->Set("prefs", items.release()); // return_value owns items.
AutomationJSONReply(this, reply_message).SendSuccess(return_value.get());
}
// Sample json input: { "command": "SetLocalStatePrefs", "path": path,
// "value": value }
void TestingAutomationProvider::SetLocalStatePrefs(
DictionaryValue* args,
IPC::Message* reply_message) {
std::string path;
Value* val = NULL;
AutomationJSONReply reply(this, reply_message);
if (args->GetString("path", &path) && args->Get("value", &val)) {
PrefService* pref_service = g_browser_process->local_state();
const PrefService::Preference* pref =
pref_service->FindPreference(path.c_str());
if (!pref) { // Not a registered pref.
reply.SendError("pref not registered.");
return;
} else if (pref->IsManaged()) { // Do not attempt to change a managed pref.
reply.SendError("pref is managed. cannot be changed.");
return;
} else { // Set the pref.
pref_service->Set(path.c_str(), *val);
}
} else {
reply.SendError("no pref path or value given.");
return;
}
reply.SendSuccess(NULL);
}
// Sample json input: { "command": "GetPrefsInfo", "windex": 0 }
// Refer chrome/test/pyautolib/prefs_info.py for sample json output.
void TestingAutomationProvider::GetPrefsInfo(DictionaryValue* args,
IPC::Message* reply_message) {
AutomationJSONReply reply(this, reply_message);
Browser* browser;
std::string error_msg;
if (!GetBrowserFromJSONArgs(args, &browser, &error_msg)) {
reply.SendError(error_msg);
return;
}
scoped_ptr<DictionaryValue> items(
browser->profile()->GetPrefs()->GetPreferenceValues());
scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
return_value->Set("prefs", items.release()); // return_value owns items.
reply.SendSuccess(return_value.get());
}
// Sample json input:
// { "command": "SetPrefs",
// "windex": 0,
// "path": path,
// "value": value }
void TestingAutomationProvider::SetPrefs(DictionaryValue* args,
IPC::Message* reply_message) {
AutomationJSONReply reply(this, reply_message);
Browser* browser;
std::string error_msg;
if (!GetBrowserFromJSONArgs(args, &browser, &error_msg)) {
reply.SendError(error_msg);
return;
}
std::string path;
Value* val = NULL;
if (args->GetString("path", &path) && args->Get("value", &val)) {
PrefService* pref_service = browser->profile()->GetPrefs();
const PrefService::Preference* pref =
pref_service->FindPreference(path.c_str());
if (!pref) { // Not a registered pref.
reply.SendError("pref not registered.");
return;
} else if (pref->IsManaged()) { // Do not attempt to change a managed pref.
reply.SendError("pref is managed. cannot be changed.");
return;
} else { // Set the pref.
pref_service->Set(path.c_str(), *val);
}
} else {
reply.SendError("no pref path or value given.");
return;
}
reply.SendSuccess(NULL);
}
// Sample json input: { "command": "GetOmniboxInfo" }
// Refer chrome/test/pyautolib/omnibox_info.py for sample json output.
void TestingAutomationProvider::GetOmniboxInfo(Browser* browser,
DictionaryValue* args,
IPC::Message* reply_message) {
scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
AutomationJSONReply reply(this, reply_message);
LocationBar* loc_bar = browser->window()->GetLocationBar();
if (!loc_bar) {
reply.SendError("The specified browser does not have a location bar.");
return;
}
const OmniboxView* omnibox_view = loc_bar->GetLocationEntry();
const OmniboxEditModel* model = omnibox_view->model();
// Fill up matches.
ListValue* matches = new ListValue;
const AutocompleteResult& result = model->result();
for (AutocompleteResult::const_iterator i(result.begin()); i != result.end();
++i) {
const AutocompleteMatch& match = *i;
DictionaryValue* item = new DictionaryValue; // owned by return_value
item->SetString("type", AutocompleteMatchType::ToString(match.type));
item->SetBoolean("starred", match.starred);
item->SetString("destination_url", match.destination_url.spec());
item->SetString("contents", match.contents);
item->SetString("description", match.description);
matches->Append(item);
}
return_value->Set("matches", matches);
// Fill up other properties.
DictionaryValue* properties = new DictionaryValue; // owned by return_value
properties->SetBoolean("has_focus", model->has_focus());
properties->SetBoolean("query_in_progress",
!model->autocomplete_controller()->done());
properties->SetString("keyword", model->keyword());
properties->SetString("text", omnibox_view->GetText());
return_value->Set("properties", properties);
reply.SendSuccess(return_value.get());
}
// Sample json input: { "command": "SetOmniboxText",
// "text": "goog" }
void TestingAutomationProvider::SetOmniboxText(Browser* browser,
DictionaryValue* args,
IPC::Message* reply_message) {
string16 text;
AutomationJSONReply reply(this, reply_message);
if (!args->GetString("text", &text)) {
reply.SendError("text missing");
return;
}
chrome::FocusLocationBar(browser);
LocationBar* loc_bar = browser->window()->GetLocationBar();
if (!loc_bar) {
reply.SendError("The specified browser does not have a location bar.");
return;
}
OmniboxView* omnibox_view = loc_bar->GetLocationEntry();
omnibox_view->model()->OnSetFocus(false);
omnibox_view->SetUserText(text);
reply.SendSuccess(NULL);
}
// Sample json input: { "command": "OmniboxMovePopupSelection",
// "count": 1 }
// Negative count implies up, positive implies down. Count values will be
// capped by the size of the popup list.
void TestingAutomationProvider::OmniboxMovePopupSelection(
Browser* browser,
DictionaryValue* args,
IPC::Message* reply_message) {
int count;
AutomationJSONReply reply(this, reply_message);
if (!args->GetInteger("count", &count)) {
reply.SendError("count missing");
return;
}
LocationBar* loc_bar = browser->window()->GetLocationBar();
if (!loc_bar) {
reply.SendError("The specified browser does not have a location bar.");
return;
}
loc_bar->GetLocationEntry()->model()->OnUpOrDownKeyPressed(count);
reply.SendSuccess(NULL);
}
// Sample json input: { "command": "OmniboxAcceptInput" }
void TestingAutomationProvider::OmniboxAcceptInput(
Browser* browser,
DictionaryValue* args,
IPC::Message* reply_message) {
NavigationController& controller =
browser->tab_strip_model()->GetActiveWebContents()->GetController();
LocationBar* loc_bar = browser->window()->GetLocationBar();
if (!loc_bar) {
AutomationJSONReply(this, reply_message).SendError(
"The specified browser does not have a location bar.");
return;
}
new OmniboxAcceptNotificationObserver(&controller, this, reply_message);
loc_bar->AcceptInput();
}
// Sample json input: { "command": "GetInitialLoadTimes" }
// Refer to InitialLoadObserver::GetTimingInformation() for sample output.
void TestingAutomationProvider::GetInitialLoadTimes(
Browser*,
DictionaryValue*,
IPC::Message* reply_message) {
scoped_ptr<DictionaryValue> return_value(
initial_load_observer_->GetTimingInformation());
std::string json_return;
base::JSONWriter::Write(return_value.get(), &json_return);
AutomationMsg_SendJSONRequest::WriteReplyParams(
reply_message, json_return, true);
Send(reply_message);
}
// Sample json input: { "command": "GetPluginsInfo" }
// Refer chrome/test/pyautolib/plugins_info.py for sample json output.
void TestingAutomationProvider::GetPluginsInfo(
Browser* browser,
DictionaryValue* args,
IPC::Message* reply_message) {
PluginService::GetInstance()->GetPlugins(
base::Bind(&TestingAutomationProvider::GetPluginsInfoCallback,
this, browser, args, reply_message));
}
void TestingAutomationProvider::GetPluginsInfoCallback(
Browser* browser,
DictionaryValue* args,
IPC::Message* reply_message,
const std::vector<content::WebPluginInfo>& plugins) {
PluginPrefs* plugin_prefs =
PluginPrefs::GetForProfile(browser->profile()).get();
ListValue* items = new ListValue;
for (std::vector<content::WebPluginInfo>::const_iterator it =
plugins.begin();
it != plugins.end();
++it) {
DictionaryValue* item = new DictionaryValue;
item->SetString("name", it->name);
item->SetString("path", it->path.value());
item->SetString("version", it->version);
item->SetString("desc", it->desc);
item->SetBoolean("enabled", plugin_prefs->IsPluginEnabled(*it));
// Add info about mime types.
ListValue* mime_types = new ListValue();
for (std::vector<content::WebPluginMimeType>::const_iterator type_it =
it->mime_types.begin();
type_it != it->mime_types.end();
++type_it) {
DictionaryValue* mime_type = new DictionaryValue();
mime_type->SetString("mimeType", type_it->mime_type);
mime_type->SetString("description", type_it->description);
ListValue* file_extensions = new ListValue();
for (std::vector<std::string>::const_iterator ext_it =
type_it->file_extensions.begin();
ext_it != type_it->file_extensions.end();
++ext_it) {
file_extensions->Append(new StringValue(*ext_it));
}
mime_type->Set("fileExtensions", file_extensions);
mime_types->Append(mime_type);
}
item->Set("mimeTypes", mime_types);
items->Append(item);
}
scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
return_value->Set("plugins", items); // return_value owns items.
AutomationJSONReply(this, reply_message).SendSuccess(return_value.get());
}
// Sample json input:
// { "command": "EnablePlugin",
// "path": "/Library/Internet Plug-Ins/Flash Player.plugin" }
void TestingAutomationProvider::EnablePlugin(Browser* browser,
DictionaryValue* args,
IPC::Message* reply_message) {
base::FilePath::StringType path;
if (!args->GetString("path", &path)) {
AutomationJSONReply(this, reply_message).SendError("path not specified.");
return;
}
PluginPrefs* plugin_prefs =
PluginPrefs::GetForProfile(browser->profile()).get();
plugin_prefs->EnablePlugin(
true,
base::FilePath(path),
base::Bind(&DidEnablePlugin,
AsWeakPtr(),
reply_message,
path,
"Could not enable plugin for path %s."));
}
// Sample json input:
// { "command": "DisablePlugin",
// "path": "/Library/Internet Plug-Ins/Flash Player.plugin" }
void TestingAutomationProvider::DisablePlugin(Browser* browser,
DictionaryValue* args,
IPC::Message* reply_message) {
base::FilePath::StringType path;
if (!args->GetString("path", &path)) {
AutomationJSONReply(this, reply_message).SendError("path not specified.");
return;
}
PluginPrefs* plugin_prefs =
PluginPrefs::GetForProfile(browser->profile()).get();
plugin_prefs->EnablePlugin(
false,
base::FilePath(path),
base::Bind(&DidEnablePlugin,
AsWeakPtr(),
reply_message,
path,
"Could not disable plugin for path %s."));
}
// Sample json input:
// { "command": "SaveTabContents",
// "tab_index": 0,
// "filename": <a full pathname> }
// Sample json output:
// {}
void TestingAutomationProvider::SaveTabContents(
Browser* browser,
DictionaryValue* args,
IPC::Message* reply_message) {
int tab_index = 0;
base::FilePath::StringType filename;
base::FilePath::StringType parent_directory;
WebContents* web_contents = NULL;
if (!args->GetInteger("tab_index", &tab_index) ||
!args->GetString("filename", &filename)) {
AutomationJSONReply(this, reply_message)
.SendError("tab_index or filename param missing");
return;
} else {
web_contents = browser->tab_strip_model()->GetWebContentsAt(tab_index);
if (!web_contents) {
AutomationJSONReply(this, reply_message).SendError("no tab at tab_index");
return;
}
}
// We're doing a SAVE_AS_ONLY_HTML so the the directory path isn't
// used. Nevertheless, SavePackage requires it be valid. Sigh.
parent_directory = base::FilePath(filename).DirName().value();
if (!web_contents->SavePage(
base::FilePath(filename),
base::FilePath(parent_directory),
content::SAVE_PAGE_TYPE_AS_ONLY_HTML)) {
AutomationJSONReply(this, reply_message).SendError(
"Could not initiate SavePage");
return;
}
// The observer will delete itself when done.
new SavePackageNotificationObserver(
BrowserContext::GetDownloadManager(browser->profile()),
this, reply_message);
}
namespace {
// Translates a dictionary password to a PasswordForm struct.
autofill::PasswordForm GetPasswordFormFromDict(
const DictionaryValue& password_dict) {
// If the time is specified, change time to the specified time.
base::Time time = base::Time::Now();
int it;
double dt;
if (password_dict.GetInteger("time", &it))
time = base::Time::FromTimeT(it);
else if (password_dict.GetDouble("time", &dt))
time = base::Time::FromDoubleT(dt);
std::string signon_realm;
string16 username_value;
string16 password_value;
string16 origin_url_text;
string16 username_element;
string16 password_element;
string16 submit_element;
string16 action_target_text;
bool blacklist;
string16 old_password_element;
string16 old_password_value;
// We don't care if any of these fail - they are either optional or checked
// before this function is called.
password_dict.GetString("signon_realm", &signon_realm);
password_dict.GetString("username_value", &username_value);
password_dict.GetString("password_value", &password_value);
password_dict.GetString("origin_url", &origin_url_text);
password_dict.GetString("username_element", &username_element);
password_dict.GetString("password_element", &password_element);
password_dict.GetString("submit_element", &submit_element);
password_dict.GetString("action_target", &action_target_text);
if (!password_dict.GetBoolean("blacklist", &blacklist))
blacklist = false;
GURL origin_gurl(origin_url_text);
GURL action_target(action_target_text);
autofill::PasswordForm password_form;
password_form.signon_realm = signon_realm;
password_form.username_value = username_value;
password_form.password_value = password_value;
password_form.origin = origin_gurl;
password_form.username_element = username_element;
password_form.password_element = password_element;
password_form.submit_element = submit_element;
password_form.action = action_target;
password_form.blacklisted_by_user = blacklist;
password_form.date_created = time;
return password_form;
}
} // namespace
// See AddSavedPassword() in chrome/test/functional/pyauto.py for sample json
// input.
// Sample json output: { "password_added": true }
void TestingAutomationProvider::AddSavedPassword(
Browser* browser,
DictionaryValue* args,
IPC::Message* reply_message) {
DictionaryValue* password_dict = NULL;
if (!args->GetDictionary("password", &password_dict)) {
AutomationJSONReply(this, reply_message).SendError(
"Must specify a password dictionary.");
return;
}
// The "signon realm" is effectively the primary key and must be included.
// Check here before calling GetPasswordFormFromDict.
if (!password_dict->HasKey("signon_realm")) {
AutomationJSONReply(this, reply_message).SendError(
"Password must include a value for 'signon_realm.'");
return;
}
autofill::PasswordForm new_password =
GetPasswordFormFromDict(*password_dict);
// Use IMPLICIT_ACCESS since new passwords aren't added in incognito mode.
PasswordStore* password_store = PasswordStoreFactory::GetForProfile(
browser->profile(), Profile::IMPLICIT_ACCESS).get();
// The password store does not exist for an incognito window.
if (password_store == NULL) {
scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
return_value->SetBoolean("password_added", false);
AutomationJSONReply(this, reply_message).SendSuccess(return_value.get());
return;
}
// This observer will delete itself.
PasswordStoreLoginsChangedObserver* observer =
new PasswordStoreLoginsChangedObserver(this, reply_message,
PasswordStoreChange::ADD,
"password_added");
observer->Init();
password_store->AddLogin(new_password);
}
// See RemoveSavedPassword() in chrome/test/functional/pyauto.py for sample
// json input.
// Sample json output: {}
void TestingAutomationProvider::RemoveSavedPassword(
Browser* browser,
DictionaryValue* args,
IPC::Message* reply_message) {
DictionaryValue* password_dict = NULL;
if (!args->GetDictionary("password", &password_dict)) {
AutomationJSONReply(this, reply_message).SendError(
"Must specify a password dictionary.");
return;
}
// The "signon realm" is effectively the primary key and must be included.
// Check here before calling GetPasswordFormFromDict.
if (!password_dict->HasKey("signon_realm")) {
AutomationJSONReply(this, reply_message).SendError(
"Password must include a value for 'signon_realm.'");
return;
}
autofill::PasswordForm to_remove =
GetPasswordFormFromDict(*password_dict);
// Use EXPLICIT_ACCESS since passwords can be removed in incognito mode.
PasswordStore* password_store = PasswordStoreFactory::GetForProfile(
browser->profile(), Profile::EXPLICIT_ACCESS).get();
if (password_store == NULL) {
AutomationJSONReply(this, reply_message).SendError(
"Unable to get password store.");
return;
}
// This observer will delete itself.
PasswordStoreLoginsChangedObserver* observer =
new PasswordStoreLoginsChangedObserver(
this, reply_message, PasswordStoreChange::REMOVE, std::string());
observer->Init();
password_store->RemoveLogin(to_remove);
}
// Sample json input: { "command": "GetSavedPasswords" }
// Refer to GetSavedPasswords() in chrome/test/pyautolib/pyauto.py for sample
// json output.
void TestingAutomationProvider::GetSavedPasswords(
Browser* browser,
DictionaryValue* args,
IPC::Message* reply_message) {
// Use EXPLICIT_ACCESS since saved passwords can be retrieved in
// incognito mode.
PasswordStore* password_store = PasswordStoreFactory::GetForProfile(
browser->profile(), Profile::EXPLICIT_ACCESS).get();
if (password_store == NULL) {
AutomationJSONReply reply(this, reply_message);
reply.SendError("Unable to get password store.");
return;
}
password_store->GetAutofillableLogins(
new AutomationProviderGetPasswordsObserver(this, reply_message));
// Observer deletes itself after sending the result.
}
namespace {
// Get the WebContents from a dictionary of arguments.
WebContents* GetWebContentsFromDict(const Browser* browser,
const DictionaryValue* args,
std::string* error_message) {
int tab_index;
if (!args->GetInteger("tab_index", &tab_index)) {
*error_message = "Must include tab_index.";
return NULL;
}
WebContents* web_contents =
browser->tab_strip_model()->GetWebContentsAt(tab_index);
if (!web_contents) {
*error_message = base::StringPrintf("No tab at index %d.", tab_index);
return NULL;
}
return web_contents;
}
} // namespace
void TestingAutomationProvider::FindInPage(
Browser* browser,
DictionaryValue* args,
IPC::Message* reply_message) {
std::string error_message;
WebContents* web_contents =
GetWebContentsFromDict(browser, args, &error_message);
if (!web_contents) {
AutomationJSONReply(this, reply_message).SendError(error_message);
return;
}
string16 search_string;
bool forward;
bool match_case;
bool find_next;
if (!args->GetString("search_string", &search_string)) {
AutomationJSONReply(this, reply_message).
SendError("Must include search_string string.");
return;
}
if (!args->GetBoolean("forward", &forward)) {
AutomationJSONReply(this, reply_message).
SendError("Must include forward boolean.");
return;
}
if (!args->GetBoolean("match_case", &match_case)) {
AutomationJSONReply(this, reply_message).
SendError("Must include match_case boolean.");
return;
}
if (!args->GetBoolean("find_next", &find_next)) {
AutomationJSONReply(this, reply_message).
SendError("Must include find_next boolean.");
return;
}
SendFindRequest(web_contents,
true,
search_string,
forward,
match_case,
find_next,
reply_message);
}
void TestingAutomationProvider::OpenFindInPage(
DictionaryValue* args,
IPC::Message* reply_message) {
AutomationJSONReply reply(this, reply_message);
Browser* browser;
std::string error_msg;
if (!GetBrowserFromJSONArgs(args, &browser, &error_msg)) {
reply.SendError(error_msg);
return;
}
chrome::FindInPage(browser, false, false);
reply.SendSuccess(NULL);
}
void TestingAutomationProvider::IsFindInPageVisible(
DictionaryValue* args,
IPC::Message* reply_message) {
AutomationJSONReply reply(this, reply_message);
bool visible;
Browser* browser;
std::string error_msg;
if (!GetBrowserFromJSONArgs(args, &browser, &error_msg)) {
reply.SendError(error_msg);
return;
}
FindBarTesting* find_bar =
browser->GetFindBarController()->find_bar()->GetFindBarTesting();
find_bar->GetFindBarWindowInfo(NULL, &visible);
DictionaryValue dict;
dict.SetBoolean("is_visible", visible);
reply.SendSuccess(&dict);
}
void TestingAutomationProvider::InstallExtension(
DictionaryValue* args, IPC::Message* reply_message) {
base::FilePath::StringType path_string;
bool with_ui;
bool from_webstore = false;
Browser* browser;
content::WebContents* tab;
std::string error_msg;
if (!GetBrowserAndTabFromJSONArgs(args, &browser, &tab, &error_msg)) {
AutomationJSONReply(this, reply_message).SendError(error_msg);
return;
}
if (!args->GetString("path", &path_string)) {
AutomationJSONReply(this, reply_message).SendError(
"Missing or invalid 'path'");
return;
}
if (!args->GetBoolean("with_ui", &with_ui)) {
AutomationJSONReply(this, reply_message).SendError(
"Missing or invalid 'with_ui'");
return;
}
args->GetBoolean("from_webstore", &from_webstore);
ExtensionService* service = extensions::ExtensionSystem::Get(
browser->profile())->extension_service();
ExtensionProcessManager* manager =
extensions::ExtensionSystem::Get(browser->profile())->process_manager();
if (service && manager) {
// The observer will delete itself when done.
new ExtensionReadyNotificationObserver(
manager,
service,
this,
reply_message);
base::FilePath extension_path(path_string);
// If the given path has a 'crx' extension, assume it is a packed extension
// and install it. Otherwise load it as an unpacked extension.
if (extension_path.MatchesExtension(FILE_PATH_LITERAL(".crx"))) {
scoped_ptr<ExtensionInstallPrompt> client(
with_ui ? new ExtensionInstallPrompt(tab) : NULL);
scoped_refptr<extensions::CrxInstaller> installer(
extensions::CrxInstaller::Create(service, client.Pass()));
if (!with_ui)
installer->set_allow_silent_install(true);
installer->set_install_cause(extension_misc::INSTALL_CAUSE_AUTOMATION);
if (from_webstore)
installer->set_creation_flags(Extension::FROM_WEBSTORE);
installer->InstallCrx(extension_path);
} else {
scoped_refptr<extensions::UnpackedInstaller> installer(
extensions::UnpackedInstaller::Create(service));
installer->set_prompt_for_plugins(with_ui);
installer->Load(extension_path);
}
} else {
AutomationJSONReply(this, reply_message).SendError(
"Extensions service/process manager is not available");
}
}
namespace {
ListValue* GetHostPermissions(const Extension* ext, bool effective_perm) {
extensions::URLPatternSet pattern_set;
if (effective_perm) {
pattern_set =
extensions::PermissionsData::GetEffectiveHostPermissions(ext);
} else {
pattern_set = ext->GetActivePermissions()->explicit_hosts();
}
ListValue* permissions = new ListValue;
for (extensions::URLPatternSet::const_iterator perm = pattern_set.begin();
perm != pattern_set.end(); ++perm) {
permissions->Append(new StringValue(perm->GetAsString()));
}
return permissions;
}
ListValue* GetAPIPermissions(const Extension* ext) {
ListValue* permissions = new ListValue;
std::set<std::string> perm_list =
ext->GetActivePermissions()->GetAPIsAsStrings();
for (std::set<std::string>::const_iterator perm = perm_list.begin();
perm != perm_list.end(); ++perm) {
permissions->Append(new StringValue(perm->c_str()));
}
return permissions;
}
} // namespace
// Sample json input: { "command": "GetExtensionsInfo" }
// See GetExtensionsInfo() in chrome/test/pyautolib/pyauto.py for sample json
// output.
void TestingAutomationProvider::GetExtensionsInfo(DictionaryValue* args,
IPC::Message* reply_message) {
AutomationJSONReply reply(this, reply_message);
Browser* browser;
std::string error_msg;
if (!GetBrowserFromJSONArgs(args, &browser, &error_msg)) {
reply.SendError(error_msg);
return;
}
ExtensionService* service = extensions::ExtensionSystem::Get(
browser->profile())->extension_service();
if (!service) {
reply.SendError("No extensions service.");
return;
}
scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
ListValue* extensions_values = new ListValue;
const ExtensionSet* extensions = service->extensions();
const ExtensionSet* disabled_extensions = service->disabled_extensions();
ExtensionList all;
all.insert(all.end(),
extensions->begin(),
extensions->end());
all.insert(all.end(),
disabled_extensions->begin(),
disabled_extensions->end());
ExtensionActionManager* extension_action_manager =
ExtensionActionManager::Get(browser->profile());
for (ExtensionList::const_iterator it = all.begin();
it != all.end(); ++it) {
const Extension* extension = it->get();
std::string id = extension->id();
DictionaryValue* extension_value = new DictionaryValue;
extension_value->SetString("id", id);
extension_value->SetString("version", extension->VersionString());
extension_value->SetString("name", extension->name());
extension_value->SetString("public_key", extension->public_key());
extension_value->SetString("description", extension->description());
extension_value->SetString(
"background_url",
extensions::BackgroundInfo::GetBackgroundURL(extension).spec());
extension_value->SetString("options_url",
extensions::ManifestURL::GetOptionsPage(extension).spec());
extension_value->Set("host_permissions",
GetHostPermissions(extension, false));
extension_value->Set("effective_host_permissions",
GetHostPermissions(extension, true));
extension_value->Set("api_permissions", GetAPIPermissions(extension));
Manifest::Location location = extension->location();
extension_value->SetBoolean("is_component",
location == Manifest::COMPONENT);
extension_value->SetBoolean("is_internal",
location == Manifest::INTERNAL);
extension_value->SetBoolean("is_user_installed",
location == Manifest::INTERNAL ||
Manifest::IsUnpackedLocation(location));
extension_value->SetBoolean("is_enabled", service->IsExtensionEnabled(id));
extension_value->SetBoolean("allowed_in_incognito",
extension_util::IsIncognitoEnabled(id, service));
extension_value->SetBoolean(
"has_page_action",
extension_action_manager->GetPageAction(*extension) != NULL);
extensions_values->Append(extension_value);
}
return_value->Set("extensions", extensions_values);
reply.SendSuccess(return_value.get());
}
// See UninstallExtensionById() in chrome/test/pyautolib/pyauto.py for sample
// json input.
// Sample json output: {}
void TestingAutomationProvider::UninstallExtensionById(
DictionaryValue* args,
IPC::Message* reply_message) {
const Extension* extension;
std::string error;
Browser* browser;
if (!GetBrowserFromJSONArgs(args, &browser, &error)) {
AutomationJSONReply(this, reply_message).SendError(error);
return;
}
if (!GetExtensionFromJSONArgs(
args, "id", browser->profile(), &extension, &error)) {
AutomationJSONReply(this, reply_message).SendError(error);
return;
}
ExtensionService* service = extensions::ExtensionSystem::Get(
browser->profile())->extension_service();
if (!service) {
AutomationJSONReply(this, reply_message).SendError(
"No extensions service.");
return;
}
// Wait for a notification indicating that the extension with the given ID
// has been uninstalled. This observer will delete itself.
new ExtensionUninstallObserver(this, reply_message, extension->id());
service->UninstallExtension(extension->id(), false, NULL);
}
// See SetExtensionStateById() in chrome/test/pyautolib/pyauto.py
// for sample json input.
void TestingAutomationProvider::SetExtensionStateById(
DictionaryValue* args,
IPC::Message* reply_message) {
const Extension* extension;
std::string error;
Browser* browser;
if (!GetBrowserFromJSONArgs(args, &browser, &error)) {
AutomationJSONReply(this, reply_message).SendError(error);
return;
}
if (!GetExtensionFromJSONArgs(
args, "id", browser->profile(), &extension, &error)) {
AutomationJSONReply(this, reply_message).SendError(error);
return;
}
bool enable;
if (!args->GetBoolean("enable", &enable)) {
AutomationJSONReply(this, reply_message)
.SendError("Missing or invalid key: enable");
return;
}
bool allow_in_incognito;
if (!args->GetBoolean("allow_in_incognito", &allow_in_incognito)) {
AutomationJSONReply(this, reply_message)
.SendError("Missing or invalid key: allow_in_incognito");
return;
}
if (allow_in_incognito && !enable) {
AutomationJSONReply(this, reply_message)
.SendError("Invalid state: Disabled extension "
"cannot be allowed in incognito mode.");
return;
}
ExtensionService* service = extensions::ExtensionSystem::Get(
browser->profile())->extension_service();
ExtensionProcessManager* manager =
extensions::ExtensionSystem::Get(browser->profile())->process_manager();
if (!service) {
AutomationJSONReply(this, reply_message)
.SendError("No extensions service or process manager.");
return;
}
if (enable) {
if (!service->IsExtensionEnabled(extension->id())) {
new ExtensionReadyNotificationObserver(
manager,
service,
this,
reply_message);
service->EnableExtension(extension->id());
} else {
AutomationJSONReply(this, reply_message).SendSuccess(NULL);
}
} else {
service->DisableExtension(extension->id(),
Extension::DISABLE_USER_ACTION);
AutomationJSONReply(this, reply_message).SendSuccess(NULL);
}
extension_util::SetIsIncognitoEnabled(
extension->id(), service, allow_in_incognito);
}
// See TriggerPageActionById() in chrome/test/pyautolib/pyauto.py
// for sample json input.
void TestingAutomationProvider::TriggerPageActionById(
DictionaryValue* args,
IPC::Message* reply_message) {
std::string error;
Browser* browser;
WebContents* tab;
if (!GetBrowserAndTabFromJSONArgs(args, &browser, &tab, &error)) {
AutomationJSONReply(this, reply_message).SendError(error);
return;
}
const Extension* extension;
if (!GetEnabledExtensionFromJSONArgs(
args, "id", browser->profile(), &extension, &error)) {
AutomationJSONReply(this, reply_message).SendError(error);
return;
}
ExtensionAction* page_action =
ExtensionActionManager::Get(browser->profile())->
GetPageAction(*extension);
if (!page_action) {
AutomationJSONReply(this, reply_message).SendError(
"Extension doesn't have any page action.");
return;
}
EnsureTabSelected(browser, tab);
bool pressed = false;
LocationBarTesting* loc_bar =
browser->window()->GetLocationBar()->GetLocationBarForTesting();
size_t page_action_visible_count =
static_cast<size_t>(loc_bar->PageActionVisibleCount());
for (size_t i = 0; i < page_action_visible_count; ++i) {
if (loc_bar->GetVisiblePageAction(i) == page_action) {
loc_bar->TestPageActionPressed(i);
pressed = true;
break;
}
}
if (!pressed) {
AutomationJSONReply(this, reply_message).SendError(
"Extension's page action is not visible.");
return;
}
if (page_action->HasPopup(ExtensionTabUtil::GetTabId(tab))) {
// This observer will delete itself.
new ExtensionPopupObserver(
this, reply_message, extension->id());
} else {
AutomationJSONReply(this, reply_message).SendSuccess(NULL);
}
}
// See TriggerBrowserActionById() in chrome/test/pyautolib/pyauto.py
// for sample json input.
void TestingAutomationProvider::TriggerBrowserActionById(
DictionaryValue* args,
IPC::Message* reply_message) {
std::string error;
Browser* browser;
WebContents* tab;
if (!GetBrowserAndTabFromJSONArgs(args, &browser, &tab, &error)) {
AutomationJSONReply(this, reply_message).SendError(error);
return;
}
const Extension* extension;
if (!GetEnabledExtensionFromJSONArgs(
args, "id", browser->profile(), &extension, &error)) {
AutomationJSONReply(this, reply_message).SendError(error);
return;
}
ExtensionAction* action = ExtensionActionManager::Get(browser->profile())->
GetBrowserAction(*extension);
if (!action) {
AutomationJSONReply(this, reply_message).SendError(
"Extension doesn't have any browser action.");
return;
}
EnsureTabSelected(browser, tab);
BrowserActionTestUtil browser_actions(browser);
int num_browser_actions = browser_actions.NumberOfBrowserActions();
int action_index = -1;
#if defined(TOOLKIT_VIEWS)
for (int i = 0; i < num_browser_actions; ++i) {
if (extension->id() == browser_actions.GetExtensionId(i)) {
action_index = i;
break;
}
}
#else
// TODO(kkania): Implement the platform-specific GetExtensionId() in
// BrowserActionTestUtil.
if (num_browser_actions != 1) {
AutomationJSONReply(this, reply_message).SendError(base::StringPrintf(
"Found %d browser actions. Only one browser action must be active.",
num_browser_actions));
return;
}
// This extension has a browser action, and there's only one action, so this
// must be the first one.
action_index = 0;
#endif
if (action_index == -1) {
AutomationJSONReply(this, reply_message).SendError(
"Extension's browser action is not visible.");
return;
}
browser_actions.Press(action_index);
if (action->HasPopup(ExtensionTabUtil::GetTabId(tab))) {
// This observer will delete itself.
new ExtensionPopupObserver(
this, reply_message, extension->id());
} else {
AutomationJSONReply(this, reply_message).SendSuccess(NULL);
}
}
void TestingAutomationProvider::ActionOnSSLBlockingPage(
DictionaryValue* args,
IPC::Message* reply_message) {
WebContents* web_contents;
bool proceed;
std::string error;
if (!GetTabFromJSONArgs(args, &web_contents, &error)) {
AutomationJSONReply(this, reply_message).SendError(error);
return;
}
if (!args->GetBoolean("proceed", &proceed)) {
AutomationJSONReply(this, reply_message).SendError(
"'proceed' is missing or invalid");
return;
}
NavigationController& controller = web_contents->GetController();
NavigationEntry* entry = controller.GetActiveEntry();
if (entry->GetPageType() == content::PAGE_TYPE_INTERSTITIAL) {
InterstitialPage* ssl_blocking_page =
InterstitialPage::GetInterstitialPage(web_contents);
if (ssl_blocking_page) {
if (proceed) {
new NavigationNotificationObserver(&controller, this, reply_message, 1,
false, true);
ssl_blocking_page->Proceed();
return;
}
ssl_blocking_page->DontProceed();
AutomationJSONReply(this, reply_message).SendSuccess(NULL);
return;
}
}
AutomationJSONReply(this, reply_message).SendError(error);
}
void TestingAutomationProvider::GetSecurityState(DictionaryValue* args,
IPC::Message* reply_message) {
AutomationJSONReply reply(this, reply_message);
WebContents* web_contents;
std::string error;
if (!GetTabFromJSONArgs(args, &web_contents, &error)) {
reply.SendError(error);
return;
}
NavigationEntry* entry = web_contents->GetController().GetActiveEntry();
DictionaryValue dict;
dict.SetInteger("security_style",
static_cast<int>(entry->GetSSL().security_style));
dict.SetInteger("ssl_cert_status",
static_cast<int>(entry->GetSSL().cert_status));
dict.SetInteger("insecure_content_status",
static_cast<int>(entry->GetSSL().content_status));
reply.SendSuccess(&dict);
}
// Sample json input: { "command": "UpdateExtensionsNow" }
// Sample json output: {}
void TestingAutomationProvider::UpdateExtensionsNow(
DictionaryValue* args,
IPC::Message* reply_message) {
std::string error;
Browser* browser;
if (!GetBrowserFromJSONArgs(args, &browser, &error)) {
AutomationJSONReply(this, reply_message).SendError(error);
return;
}
ExtensionService* service = extensions::ExtensionSystem::Get(
browser->profile())->extension_service();
if (!service) {
AutomationJSONReply(this, reply_message).SendError(
"No extensions service.");
return;
}
extensions::ExtensionUpdater* updater = service->updater();
if (!updater) {
AutomationJSONReply(this, reply_message).SendError(
"No updater for extensions service.");
return;
}
ExtensionProcessManager* manager =
extensions::ExtensionSystem::Get(browser->profile())->process_manager();
if (!manager) {
AutomationJSONReply(this, reply_message).SendError(
"No extension process manager.");
return;
}
// Create a new observer that waits until the extensions have been fully
// updated (we should not send the reply until after all extensions have
// been updated). This observer will delete itself.
ExtensionsUpdatedObserver* observer = new ExtensionsUpdatedObserver(
manager, this, reply_message);
extensions::ExtensionUpdater::CheckParams params;
params.install_immediately = true;
params.callback = base::Bind(&ExtensionsUpdatedObserver::UpdateCheckFinished,
base::Unretained(observer));
updater->CheckNow(params);
}
namespace {
void SendSuccessIfAlive(
base::WeakPtr<AutomationProvider> provider,
IPC::Message* reply_message) {
if (provider.get())
AutomationJSONReply(provider.get(), reply_message).SendSuccess(NULL);
}
} // namespace
void TestingAutomationProvider::OverrideGeoposition(
base::DictionaryValue* args,
IPC::Message* reply_message) {
double latitude, longitude, altitude;
if (!args->GetDouble("latitude", &latitude) ||
!args->GetDouble("longitude", &longitude) ||
!args->GetDouble("altitude", &altitude)) {
AutomationJSONReply(this, reply_message).SendError(
"Missing or invalid geolocation parameters");
return;
}
content::Geoposition position;
position.latitude = latitude;
position.longitude = longitude;
position.altitude = altitude;
position.accuracy = 0.;
position.timestamp = base::Time::Now();
content::GeolocationProvider::OverrideLocationForTesting(
position,
base::Bind(&SendSuccessIfAlive, AsWeakPtr(), reply_message));
}
// Refer to GetAllNotifications() in chrome/test/pyautolib/pyauto.py for
// sample json input/output.
void TestingAutomationProvider::GetAllNotifications(
Browser* browser,
DictionaryValue* args,
IPC::Message* reply_message) {
new GetAllNotificationsObserver(this, reply_message);
}
// Refer to CloseNotification() in chrome/test/pyautolib/pyauto.py for
// sample json input.
// Returns empty json message.
void TestingAutomationProvider::CloseNotification(
Browser* browser,
DictionaryValue* args,
IPC::Message* reply_message) {
int index;
if (!args->GetInteger("index", &index)) {
AutomationJSONReply(this, reply_message)
.SendError("'index' missing or invalid.");
return;
}
BalloonNotificationUIManager* manager =
BalloonNotificationUIManager::GetInstanceForTesting();
BalloonCollection* collection = manager->balloon_collection();
const BalloonCollection::Balloons& balloons = collection->GetActiveBalloons();
int balloon_count = static_cast<int>(balloons.size());
if (index < 0 || index >= balloon_count) {
AutomationJSONReply(this, reply_message)
.SendError(base::StringPrintf("No notification at index %d", index));
return;
}
std::vector<const Notification*> queued_notes;
manager->GetQueuedNotificationsForTesting(&queued_notes);
if (queued_notes.empty()) {
new OnNotificationBalloonCountObserver(
this, reply_message, balloon_count - 1);
} else {
new NewNotificationBalloonObserver(this, reply_message);
}
manager->CancelById(balloons[index]->notification().notification_id());
}
// Refer to WaitForNotificationCount() in chrome/test/pyautolib/pyauto.py for
// sample json input.
// Returns empty json message.
void TestingAutomationProvider::WaitForNotificationCount(
Browser* browser,
DictionaryValue* args,
IPC::Message* reply_message) {
int count;
if (!args->GetInteger("count", &count)) {
AutomationJSONReply(this, reply_message)
.SendError("'count' missing or invalid.");
return;
}
// This will delete itself when finished.
new OnNotificationBalloonCountObserver(this, reply_message, count);
}
// Sample JSON input: { "command": "GetNTPInfo" }
// For output, refer to chrome/test/pyautolib/ntp_model.py.
void TestingAutomationProvider::GetNTPInfo(
Browser* browser,
DictionaryValue* args,
IPC::Message* reply_message) {
// This observer will delete itself.
new NTPInfoObserver(this, reply_message);
}
void TestingAutomationProvider::RemoveNTPMostVisitedThumbnail(
Browser* browser,
DictionaryValue* args,
IPC::Message* reply_message) {
AutomationJSONReply reply(this, reply_message);
std::string url;
if (!args->GetString("url", &url)) {
reply.SendError("Missing or invalid 'url' key.");
return;
}
history::TopSites* top_sites = browser->profile()->GetTopSites();
if (!top_sites) {
reply.SendError("TopSites service is not initialized.");
return;
}
top_sites->AddBlacklistedURL(GURL(url));
reply.SendSuccess(NULL);
}
void TestingAutomationProvider::RestoreAllNTPMostVisitedThumbnails(
Browser* browser,
DictionaryValue* args,
IPC::Message* reply_message) {
AutomationJSONReply reply(this, reply_message);
history::TopSites* top_sites = browser->profile()->GetTopSites();
if (!top_sites) {
reply.SendError("TopSites service is not initialized.");
return;
}
top_sites->ClearBlacklistedURLs();
reply.SendSuccess(NULL);
}
void TestingAutomationProvider::KillRendererProcess(
Browser* browser,
DictionaryValue* args,
IPC::Message* reply_message) {
int pid;
uint32 kAccessFlags = base::kProcessAccessTerminate |
base::kProcessAccessWaitForTermination |
base::kProcessAccessQueryInformation;
if (!args->GetInteger("pid", &pid)) {
AutomationJSONReply(this, reply_message)
.SendError("'pid' key missing or invalid.");
return;
}
base::ProcessHandle process;
if (!base::OpenProcessHandleWithAccess(static_cast<base::ProcessId>(pid),
kAccessFlags,
&process)) {
AutomationJSONReply(this, reply_message).SendError(base::StringPrintf(
"Failed to open process handle for pid %d", pid));
return;
}
new RendererProcessClosedObserver(this, reply_message);
base::KillProcess(process, 0, false);
base::CloseProcessHandle(process);
}
bool TestingAutomationProvider::BuildWebKeyEventFromArgs(
DictionaryValue* args,
std::string* error,
NativeWebKeyboardEvent* event) {
int type, modifiers;
bool is_system_key;
string16 unmodified_text, text;
std::string key_identifier;
if (!args->GetInteger("type", &type)) {
*error = "'type' missing or invalid.";
return false;
}
if (!args->GetBoolean("isSystemKey", &is_system_key)) {
*error = "'isSystemKey' missing or invalid.";
return false;
}
if (!args->GetString("unmodifiedText", &unmodified_text)) {
*error = "'unmodifiedText' missing or invalid.";
return false;
}
if (!args->GetString("text", &text)) {
*error = "'text' missing or invalid.";
return false;
}
if (!args->GetInteger("nativeKeyCode", &event->nativeKeyCode)) {
*error = "'nativeKeyCode' missing or invalid.";
return false;
}
if (!args->GetInteger("windowsKeyCode", &event->windowsKeyCode)) {
*error = "'windowsKeyCode' missing or invalid.";
return false;
}
if (!args->GetInteger("modifiers", &modifiers)) {
*error = "'modifiers' missing or invalid.";
return false;
}
if (args->GetString("keyIdentifier", &key_identifier)) {
base::strlcpy(event->keyIdentifier,
key_identifier.c_str(),
WebKit::WebKeyboardEvent::keyIdentifierLengthCap);
} else {
*error = "'keyIdentifier' missing or invalid.";
return false;
}
if (type == automation::kRawKeyDownType) {
event->type = WebKit::WebInputEvent::RawKeyDown;
} else if (type == automation::kKeyDownType) {
event->type = WebKit::WebInputEvent::KeyDown;
} else if (type == automation::kKeyUpType) {
event->type = WebKit::WebInputEvent::KeyUp;
} else if (type == automation::kCharType) {
event->type = WebKit::WebInputEvent::Char;
} else {
*error = "'type' refers to an unrecognized keyboard event type";
return false;
}
string16 unmodified_text_truncated = unmodified_text.substr(
0, WebKit::WebKeyboardEvent::textLengthCap - 1);
memcpy(event->unmodifiedText,
unmodified_text_truncated.c_str(),
unmodified_text_truncated.length() + 1);
string16 text_truncated = text.substr(
0, WebKit::WebKeyboardEvent::textLengthCap - 1);
memcpy(event->text, text_truncated.c_str(), text_truncated.length() + 1);
event->modifiers = 0;
if (modifiers & automation::kShiftKeyMask)
event->modifiers |= WebKit::WebInputEvent::ShiftKey;
if (modifiers & automation::kControlKeyMask)
event->modifiers |= WebKit::WebInputEvent::ControlKey;
if (modifiers & automation::kAltKeyMask)
event->modifiers |= WebKit::WebInputEvent::AltKey;
if (modifiers & automation::kMetaKeyMask)
event->modifiers |= WebKit::WebInputEvent::MetaKey;
event->isSystemKey = is_system_key;
event->timeStampSeconds = base::Time::Now().ToDoubleT();
event->skip_in_browser = true;
return true;
}
void TestingAutomationProvider::SendWebkitKeyEvent(
DictionaryValue* args,
IPC::Message* reply_message) {
if (SendErrorIfModalDialogActive(this, reply_message))
return;
NativeWebKeyboardEvent event;
// In the event of an error, BuildWebKeyEventFromArgs handles telling what
// went wrong and sending the reply message; if it fails, we just have to
// stop here.
std::string error;
if (!BuildWebKeyEventFromArgs(args, &error, &event)) {
AutomationJSONReply(this, reply_message).SendError(error);
return;
}
RenderViewHost* view;
if (!GetRenderViewFromJSONArgs(args, profile(), &view, &error)) {
AutomationJSONReply(this, reply_message).SendError(error);
return;
}
new InputEventAckNotificationObserver(this, reply_message, event.type, 1);
view->ForwardKeyboardEvent(event);
}
namespace {
// Gets the active JavaScript modal dialog, or NULL if none.
JavaScriptAppModalDialog* GetActiveJavaScriptModalDialog(
std::string* error_msg) {
AppModalDialogQueue* dialog_queue = AppModalDialogQueue::GetInstance();
if (!dialog_queue->HasActiveDialog() ||
!dialog_queue->active_dialog()->IsJavaScriptModalDialog()) {
*error_msg = "No JavaScriptModalDialog open";
return NULL;
}
return static_cast<JavaScriptAppModalDialog*>(dialog_queue->active_dialog());
}
} // namespace
void TestingAutomationProvider::GetAppModalDialogMessage(
DictionaryValue* args, IPC::Message* reply_message) {
AutomationJSONReply reply(this, reply_message);
std::string error_msg;
JavaScriptAppModalDialog* dialog = GetActiveJavaScriptModalDialog(&error_msg);
if (!dialog) {
reply.SendError(error_msg);
return;
}
DictionaryValue result_dict;
result_dict.SetString("message", UTF16ToUTF8(dialog->message_text()));
reply.SendSuccess(&result_dict);
}
void TestingAutomationProvider::AcceptOrDismissAppModalDialog(
DictionaryValue* args, IPC::Message* reply_message) {
AutomationJSONReply reply(this, reply_message);
bool accept;
if (!args->GetBoolean("accept", &accept)) {
reply.SendError("Missing or invalid 'accept'");
return;
}
std::string error_msg;
JavaScriptAppModalDialog* dialog = GetActiveJavaScriptModalDialog(&error_msg);
if (!dialog) {
reply.SendError(error_msg);
return;
}
if (accept) {
std::string prompt_text;
if (args->GetString("prompt_text", &prompt_text))
dialog->SetOverridePromptText(UTF8ToUTF16(prompt_text));
dialog->native_dialog()->AcceptAppModalDialog();
} else {
dialog->native_dialog()->CancelAppModalDialog();
}
reply.SendSuccess(NULL);
}
// Sample JSON input: { "command": "LaunchApp",
// "id": "ahfgeienlihckogmohjhadlkjgocpleb" }
// Sample JSON output: {}
void TestingAutomationProvider::LaunchApp(
Browser* browser,
DictionaryValue* args,
IPC::Message* reply_message) {
std::string id;
if (!args->GetString("id", &id)) {
AutomationJSONReply(this, reply_message).SendError(
"Must include string id.");
return;
}
ExtensionService* service = extensions::ExtensionSystem::Get(
browser->profile())->extension_service();
if (!service) {
AutomationJSONReply(this, reply_message).SendError(
"No extensions service.");
return;
}
const Extension* extension = service->GetExtensionById(
id, false /* do not include disabled extensions */);
if (!extension) {
AutomationJSONReply(this, reply_message).SendError(
base::StringPrintf(
"Extension with ID '%s' doesn't exist or is disabled.",
id.c_str()));
return;
}
WebContents* old_contents =
browser->tab_strip_model()->GetActiveWebContents();
if (!old_contents) {
AutomationJSONReply(this, reply_message).SendError(
"Cannot identify selected tab contents.");
return;
}
AppLaunchParams launch_params(profile(), extension, CURRENT_TAB);
// This observer will delete itself.
new AppLaunchObserver(&old_contents->GetController(), this, reply_message,
launch_params.container);
OpenApplication(launch_params);
}
// Sample JSON input: { "command": "SetAppLaunchType",
// "id": "ahfgeienlihckogmohjhadlkjgocpleb",
// "launch_type": "pinned" }
// Sample JSON output: {}
void TestingAutomationProvider::SetAppLaunchType(
Browser* browser,
DictionaryValue* args,
IPC::Message* reply_message) {
AutomationJSONReply reply(this, reply_message);
std::string id;
if (!args->GetString("id", &id)) {
reply.SendError("Must include string id.");
return;
}
std::string launch_type_str;
if (!args->GetString("launch_type", &launch_type_str)) {
reply.SendError("Must specify app launch type.");
return;
}
ExtensionService* service = extensions::ExtensionSystem::Get(
browser->profile())->extension_service();
if (!service) {
reply.SendError("No extensions service.");
return;
}
const Extension* extension = service->GetExtensionById(
id, true /* include disabled extensions */);
if (!extension) {
reply.SendError(base::StringPrintf(
"Extension with ID '%s' doesn't exist.", id.c_str()));
return;
}
extensions::ExtensionPrefs::LaunchType launch_type;
if (launch_type_str == "pinned") {
launch_type = extensions::ExtensionPrefs::LAUNCH_PINNED;
} else if (launch_type_str == "regular") {
launch_type = extensions::ExtensionPrefs::LAUNCH_REGULAR;
} else if (launch_type_str == "fullscreen") {
launch_type = extensions::ExtensionPrefs::LAUNCH_FULLSCREEN;
} else if (launch_type_str == "window") {
launch_type = extensions::ExtensionPrefs::LAUNCH_WINDOW;
} else {
reply.SendError(base::StringPrintf(
"Unexpected launch type '%s'.", launch_type_str.c_str()));
return;
}
service->extension_prefs()->SetLaunchType(extension->id(), launch_type);
reply.SendSuccess(NULL);
}
// Sample json input: { "command": "GetV8HeapStats",
// "tab_index": 0 }
// Refer to GetV8HeapStats() in chrome/test/pyautolib/pyauto.py for
// sample json output.
void TestingAutomationProvider::GetV8HeapStats(
Browser* browser,
DictionaryValue* args,
IPC::Message* reply_message) {
WebContents* web_contents;
int tab_index;
if (!args->GetInteger("tab_index", &tab_index)) {
AutomationJSONReply(this, reply_message).SendError(
"Missing 'tab_index' argument.");
return;
}
web_contents = browser->tab_strip_model()->GetWebContentsAt(tab_index);
if (!web_contents) {
AutomationJSONReply(this, reply_message).SendError(base::StringPrintf(
"Could not get WebContents at tab index %d", tab_index));
return;
}
RenderViewHost* render_view = web_contents->GetRenderViewHost();
// This observer will delete itself.
new V8HeapStatsObserver(
this, reply_message,
base::GetProcId(render_view->GetProcess()->GetHandle()));
render_view->Send(new ChromeViewMsg_GetV8HeapStats);
}
// Sample json input: { "command": "GetFPS",
// "tab_index": 0 }
// Refer to GetFPS() in chrome/test/pyautolib/pyauto.py for
// sample json output.
void TestingAutomationProvider::GetFPS(
Browser* browser,
DictionaryValue* args,
IPC::Message* reply_message) {
WebContents* web_contents;
int tab_index;
if (!args->GetInteger("tab_index", &tab_index)) {
AutomationJSONReply(this, reply_message).SendError(
"Missing 'tab_index' argument.");
return;
}
web_contents = browser->tab_strip_model()->GetWebContentsAt(tab_index);
if (!web_contents) {
AutomationJSONReply(this, reply_message).SendError(base::StringPrintf(
"Could not get WebContents at tab index %d", tab_index));
return;
}
RenderViewHost* render_view = web_contents->GetRenderViewHost();
int routing_id = render_view->GetRoutingID();
// This observer will delete itself.
new FPSObserver(
this, reply_message,
base::GetProcId(render_view->GetProcess()->GetHandle()),
routing_id);
render_view->Send(new ChromeViewMsg_GetFPS(routing_id));
}
void TestingAutomationProvider::IsFullscreenForBrowser(Browser* browser,
base::DictionaryValue* args,
IPC::Message* reply_message) {
DictionaryValue dict;
dict.SetBoolean("result",
browser->fullscreen_controller()->IsFullscreenForBrowser());
AutomationJSONReply(this, reply_message).SendSuccess(&dict);
}
void TestingAutomationProvider::IsFullscreenForTab(Browser* browser,
base::DictionaryValue* args,
IPC::Message* reply_message) {
DictionaryValue dict;
dict.SetBoolean("result",
browser->fullscreen_controller()->IsFullscreenForTabOrPending());
AutomationJSONReply(this, reply_message).SendSuccess(&dict);
}
void TestingAutomationProvider::IsMouseLocked(Browser* browser,
base::DictionaryValue* args,
IPC::Message* reply_message) {
DictionaryValue dict;
dict.SetBoolean("result", browser->tab_strip_model()->GetActiveWebContents()->
GetRenderViewHost()->GetView()->IsMouseLocked());
AutomationJSONReply(this, reply_message).SendSuccess(&dict);
}
void TestingAutomationProvider::IsMouseLockPermissionRequested(
Browser* browser,
base::DictionaryValue* args,
IPC::Message* reply_message) {
FullscreenExitBubbleType type =
browser->fullscreen_controller()->GetFullscreenExitBubbleType();
bool mouse_lock = false;
fullscreen_bubble::PermissionRequestedByType(type, NULL, &mouse_lock);
DictionaryValue dict;
dict.SetBoolean("result", mouse_lock);
AutomationJSONReply(this, reply_message).SendSuccess(&dict);
}
void TestingAutomationProvider::IsFullscreenPermissionRequested(
Browser* browser,
base::DictionaryValue* args,
IPC::Message* reply_message) {
FullscreenExitBubbleType type =
browser->fullscreen_controller()->GetFullscreenExitBubbleType();
bool fullscreen = false;
fullscreen_bubble::PermissionRequestedByType(type, &fullscreen, NULL);
DictionaryValue dict;
dict.SetBoolean("result", fullscreen);
AutomationJSONReply(this, reply_message).SendSuccess(&dict);
}
void TestingAutomationProvider::IsFullscreenBubbleDisplayed(Browser* browser,
base::DictionaryValue* args,
IPC::Message* reply_message) {
FullscreenExitBubbleType type =
browser->fullscreen_controller()->GetFullscreenExitBubbleType();
DictionaryValue dict;
dict.SetBoolean("result",
type != FEB_TYPE_BROWSER_FULLSCREEN_EXIT_INSTRUCTION);
AutomationJSONReply(this, reply_message).SendSuccess(&dict);
}
void TestingAutomationProvider::IsFullscreenBubbleDisplayingButtons(
Browser* browser,
base::DictionaryValue* args,
IPC::Message* reply_message) {
FullscreenExitBubbleType type =
browser->fullscreen_controller()->GetFullscreenExitBubbleType();
DictionaryValue dict;
dict.SetBoolean("result", fullscreen_bubble::ShowButtonsForType(type));
AutomationJSONReply(this, reply_message).SendSuccess(&dict);
}
void TestingAutomationProvider::AcceptCurrentFullscreenOrMouseLockRequest(
Browser* browser,
base::DictionaryValue* args,
IPC::Message* reply_message) {
browser->fullscreen_controller()->OnAcceptFullscreenPermission();
AutomationJSONReply(this, reply_message).SendSuccess(NULL);
}
void TestingAutomationProvider::DenyCurrentFullscreenOrMouseLockRequest(
Browser* browser,
base::DictionaryValue* args,
IPC::Message* reply_message) {
browser->fullscreen_controller()->OnDenyFullscreenPermission();
AutomationJSONReply(this, reply_message).SendSuccess(NULL);
}
void TestingAutomationProvider::WaitForTabToBeRestored(
DictionaryValue* args,
IPC::Message* reply_message) {
WebContents* web_contents;
std::string error;
if (!GetTabFromJSONArgs(args, &web_contents, &error)) {
AutomationJSONReply(this, reply_message).SendError(error);
return;
}
NavigationController& controller = web_contents->GetController();
new NavigationControllerRestoredObserver(this, &controller, reply_message);
}
void TestingAutomationProvider::RefreshPolicies(
base::DictionaryValue* args,
IPC::Message* reply_message) {
#if !defined(ENABLE_CONFIGURATION_POLICY)
AutomationJSONReply(this, reply_message).SendError(
"Configuration Policy disabled");
#else
// Some policies (e.g. URLBlacklist) post tasks to other message loops
// before they start enforcing updated policy values; make sure those tasks
// have finished after a policy update.
// Updates of the URLBlacklist are done on IO, after building the blacklist
// on FILE, which is initiated from IO.
base::Closure reply =
base::Bind(SendSuccessReply, AsWeakPtr(), reply_message);
g_browser_process->policy_service()->RefreshPolicies(
base::Bind(PostTask, BrowserThread::IO,
base::Bind(PostTask, BrowserThread::FILE,
base::Bind(PostTask, BrowserThread::IO,
base::Bind(PostTask, BrowserThread::UI, reply)))));
#endif
}
static int AccessArray(const volatile int arr[], const volatile int *index) {
return arr[*index];
}
void TestingAutomationProvider::SimulateAsanMemoryBug(
base::DictionaryValue* args, IPC::Message* reply_message) {
// This array is volatile not to let compiler optimize us out.
volatile int testarray[3] = {0, 0, 0};
// Send the reply while we can.
AutomationJSONReply(this, reply_message).SendSuccess(NULL);
// Cause Address Sanitizer to abort this process.
volatile int index = 5;
AccessArray(testarray, &index);
}
void TestingAutomationProvider::GetIndicesFromTab(
DictionaryValue* args,
IPC::Message* reply_message) {
AutomationJSONReply reply(this, reply_message);
int id_or_handle = 0;
bool has_id = args->HasKey("tab_id");
bool has_handle = args->HasKey("tab_handle");
if (has_id && has_handle) {
reply.SendError(
"Both 'tab_id' and 'tab_handle' were specified. Only one is allowed");
return;
} else if (!has_id && !has_handle) {
reply.SendError("Either 'tab_id' or 'tab_handle' must be specified");
return;
}
if (has_id && !args->GetInteger("tab_id", &id_or_handle)) {
reply.SendError("'tab_id' is invalid");
return;
}
if (has_handle && (!args->GetInteger("tab_handle", &id_or_handle) ||
!tab_tracker_->ContainsHandle(id_or_handle))) {
reply.SendError("'tab_handle' is invalid");
return;
}
int id = id_or_handle;
if (has_handle) {
SessionTabHelper* session_tab_helper =
SessionTabHelper::FromWebContents(
tab_tracker_->GetResource(id_or_handle)->GetWebContents());
id = session_tab_helper->session_id().id();
}
chrome::BrowserIterator it;
int browser_index = 0;
for (; !it.done(); it.Next(), ++browser_index) {
Browser* browser = *it;
for (int tab_index = 0;
tab_index < browser->tab_strip_model()->count();
++tab_index) {
WebContents* tab =
browser->tab_strip_model()->GetWebContentsAt(tab_index);
SessionTabHelper* session_tab_helper =
SessionTabHelper::FromWebContents(tab);
if (session_tab_helper->session_id().id() == id) {
DictionaryValue dict;
dict.SetInteger("windex", browser_index);
dict.SetInteger("tab_index", tab_index);
reply.SendSuccess(&dict);
return;
}
}
}
reply.SendError("Could not find tab among current browser windows");
}
void TestingAutomationProvider::NavigateToURL(
DictionaryValue* args,
IPC::Message* reply_message) {
if (SendErrorIfModalDialogActive(this, reply_message))
return;
int navigation_count;
std::string url, error;
Browser* browser;
WebContents* web_contents;
if (!GetBrowserAndTabFromJSONArgs(args, &browser, &web_contents, &error)) {
AutomationJSONReply(this, reply_message).SendError(error);
return;
}
if (!args->GetString("url", &url)) {
AutomationJSONReply(this, reply_message)
.SendError("'url' missing or invalid");
return;
}
if (!args->GetInteger("navigation_count", &navigation_count)) {
AutomationJSONReply(this, reply_message)
.SendError("'navigation_count' missing or invalid");
return;
}
if (navigation_count > 0) {
new NavigationNotificationObserver(
&web_contents->GetController(), this, reply_message,
navigation_count, false, true);
} else {
AutomationJSONReply(this, reply_message).SendSuccess(NULL);
}
OpenURLParams params(
GURL(url), content::Referrer(), CURRENT_TAB,
content::PageTransitionFromInt(
content::PAGE_TRANSITION_TYPED |
content::PAGE_TRANSITION_FROM_ADDRESS_BAR),
false);
browser->OpenURLFromTab(web_contents, params);
}
void TestingAutomationProvider::GetActiveTabIndexJSON(
DictionaryValue* args,
IPC::Message* reply_message) {
AutomationJSONReply reply(this, reply_message);
Browser* browser;
std::string error_msg;
if (!GetBrowserFromJSONArgs(args, &browser, &error_msg)) {
reply.SendError(error_msg);
return;
}
int tab_index = browser->tab_strip_model()->active_index();
scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
return_value->SetInteger("tab_index", tab_index);
reply.SendSuccess(return_value.get());
}
void TestingAutomationProvider::AppendTabJSON(DictionaryValue* args,
IPC::Message* reply_message) {
TabAppendedNotificationObserver* observer = NULL;
int append_tab_response = -1;
Browser* browser;
std::string error_msg, url;
if (!GetBrowserFromJSONArgs(args, &browser, &error_msg)) {
AutomationJSONReply(this, reply_message).SendError(error_msg);
return;
}
if (!args->GetString("url", &url)) {
AutomationJSONReply(this, reply_message)
.SendError("'url' missing or invalid");
return;
}
observer = new TabAppendedNotificationObserver(browser, this, reply_message,
true);
WebContents* contents =
chrome::AddSelectedTabWithURL(browser, GURL(url),
content::PAGE_TRANSITION_TYPED);
if (contents) {
append_tab_response = GetIndexForNavigationController(
&contents->GetController(), browser);
}
if (!contents || append_tab_response < 0) {
if (observer) {
observer->ReleaseReply();
delete observer;
}
AutomationJSONReply(this, reply_message).SendError("Failed to append tab.");
}
}
void TestingAutomationProvider::WaitUntilNavigationCompletes(
DictionaryValue* args,
IPC::Message* reply_message) {
if (SendErrorIfModalDialogActive(this, reply_message))
return;
std::string error;
Browser* browser;
WebContents* web_contents;
if (!GetBrowserAndTabFromJSONArgs(args, &browser, &web_contents, &error)) {
AutomationJSONReply(this, reply_message).SendError(error);
return;
}
NavigationNotificationObserver* observer =
new NavigationNotificationObserver(&web_contents->GetController(), this,
reply_message, 1, true, true);
if (!web_contents->IsLoading()) {
observer->ConditionMet(AUTOMATION_MSG_NAVIGATION_SUCCESS);
return;
}
}
void TestingAutomationProvider::ExecuteJavascriptJSON(
DictionaryValue* args,
IPC::Message* reply_message) {
if (SendErrorIfModalDialogActive(this, reply_message))
return;
string16 frame_xpath, javascript;
std::string error;
RenderViewHost* render_view;
if (!GetRenderViewFromJSONArgs(args, profile(), &render_view, &error)) {
AutomationJSONReply(this, reply_message).SendError(error);
return;
}
if (!args->GetString("frame_xpath", &frame_xpath)) {
AutomationJSONReply(this, reply_message)
.SendError("'frame_xpath' missing or invalid");
return;
}
if (!args->GetString("javascript", &javascript)) {
AutomationJSONReply(this, reply_message)
.SendError("'javascript' missing or invalid");
return;
}
new DomOperationMessageSender(this, reply_message, true);
ExecuteJavascriptInRenderViewFrame(frame_xpath, javascript, reply_message,
render_view);
}
void TestingAutomationProvider::ExecuteJavascriptInRenderView(
DictionaryValue* args,
IPC::Message* reply_message) {
string16 frame_xpath, javascript, extension_id, url_text;
int render_process_id, render_view_id;
if (!args->GetString("frame_xpath", &frame_xpath)) {
AutomationJSONReply(this, reply_message)
.SendError("'frame_xpath' missing or invalid");
return;
}
if (!args->GetString("javascript", &javascript)) {
AutomationJSONReply(this, reply_message)
.SendError("'javascript' missing or invalid");
return;
}
if (!args->GetInteger("view.render_process_id", &render_process_id)) {
AutomationJSONReply(this, reply_message)
.SendError("'view.render_process_id' missing or invalid");
return;
}
if (!args->GetInteger("view.render_view_id", &render_view_id)) {
AutomationJSONReply(this, reply_message)
.SendError("'view.render_view_id' missing or invalid");
return;
}
RenderViewHost* rvh = RenderViewHost::FromID(render_process_id,
render_view_id);
if (!rvh) {
AutomationJSONReply(this, reply_message).SendError(
"A RenderViewHost object was not found with the given view ID.");
return;
}
new DomOperationMessageSender(this, reply_message, true);
ExecuteJavascriptInRenderViewFrame(frame_xpath, javascript, reply_message,
rvh);
}
void TestingAutomationProvider::AddDomEventObserver(
DictionaryValue* args,
IPC::Message* reply_message) {
if (SendErrorIfModalDialogActive(this, reply_message))
return;
AutomationJSONReply reply(this, reply_message);
std::string event_name;
int automation_id;
bool recurring;
if (!args->GetString("event_name", &event_name)) {
reply.SendError("'event_name' missing or invalid");
return;
}
if (!args->GetInteger("automation_id", &automation_id)) {
reply.SendError("'automation_id' missing or invalid");
return;
}
if (!args->GetBoolean("recurring", &recurring)) {
reply.SendError("'recurring' missing or invalid");
return;
}
if (!automation_event_queue_.get())
automation_event_queue_.reset(new AutomationEventQueue);
int observer_id = automation_event_queue_->AddObserver(
new DomEventObserver(automation_event_queue_.get(), event_name,
automation_id, recurring));
scoped_ptr<DictionaryValue> return_value(new DictionaryValue);
return_value->SetInteger("observer_id", observer_id);
reply.SendSuccess(return_value.get());
}
void TestingAutomationProvider::RemoveEventObserver(
DictionaryValue* args,
IPC::Message* reply_message) {
AutomationJSONReply reply(this, reply_message);
int observer_id;
if (!args->GetInteger("observer_id", &observer_id) ||
!automation_event_queue_.get()) {
reply.SendError("'observer_id' missing or invalid");
return;
}
if (automation_event_queue_->RemoveObserver(observer_id)) {
reply.SendSuccess(NULL);
return;
}
reply.SendError("Invalid observer id.");
}
void TestingAutomationProvider::ClearEventQueue(
DictionaryValue* args,
IPC::Message* reply_message) {
automation_event_queue_.reset();
AutomationJSONReply(this, reply_message).SendSuccess(NULL);
}
void TestingAutomationProvider::GetNextEvent(
DictionaryValue* args,
IPC::Message* reply_message) {
scoped_ptr<AutomationJSONReply> reply(
new AutomationJSONReply(this, reply_message));
int observer_id;
bool blocking;
if (!args->GetInteger("observer_id", &observer_id)) {
reply->SendError("'observer_id' missing or invalid");
return;
}
if (!args->GetBoolean("blocking", &blocking)) {
reply->SendError("'blocking' missing or invalid");
return;
}
if (!automation_event_queue_.get()) {
reply->SendError(
"No observers are attached to the queue. Did you create any?");
return;
}
// The reply will be freed once a matching event is added to the queue.
automation_event_queue_->GetNextEvent(reply.release(), observer_id, blocking);
}
void TestingAutomationProvider::GoForward(
DictionaryValue* args,
IPC::Message* reply_message) {
if (SendErrorIfModalDialogActive(this, reply_message))
return;
WebContents* web_contents;
std::string error;
if (!GetTabFromJSONArgs(args, &web_contents, &error)) {
AutomationJSONReply(this, reply_message).SendError(error);
return;
}
NavigationController& controller = web_contents->GetController();
if (!controller.CanGoForward()) {
DictionaryValue dict;
dict.SetBoolean("did_go_forward", false);
AutomationJSONReply(this, reply_message).SendSuccess(&dict);
return;
}
new NavigationNotificationObserver(&controller, this, reply_message,
1, false, true);
controller.GoForward();
}
void TestingAutomationProvider::ExecuteBrowserCommandAsyncJSON(
DictionaryValue* args,
IPC::Message* reply_message) {
AutomationJSONReply reply(this, reply_message);
int command;
Browser* browser;
std::string error;
if (!GetBrowserFromJSONArgs(args, &browser, &error)) {
reply.SendError(error);
return;
}
if (!args->GetInteger("accelerator", &command)) {
reply.SendError("'accelerator' missing or invalid.");
return;
}
if (!chrome::SupportsCommand(browser, command)) {
reply.SendError(base::StringPrintf("Browser does not support command=%d.",
command));
return;
}
if (!chrome::IsCommandEnabled(browser, command)) {
reply.SendError(base::StringPrintf(
"Browser command=%d not enabled.", command));
return;
}
chrome::ExecuteCommand(browser, command);
reply.SendSuccess(NULL);
}
void TestingAutomationProvider::ExecuteBrowserCommandJSON(
DictionaryValue* args,
IPC::Message* reply_message) {
int command;
Browser* browser;
std::string error;
if (!GetBrowserFromJSONArgs(args, &browser, &error)) {
AutomationJSONReply(this, reply_message).SendError(error);
return;
}
if (!args->GetInteger("accelerator", &command)) {
AutomationJSONReply(this, reply_message).SendError(
"'accelerator' missing or invalid.");
return;
}
if (!chrome::SupportsCommand(browser, command)) {
AutomationJSONReply(this, reply_message).SendError(
base::StringPrintf("Browser does not support command=%d.", command));
return;
}
if (!chrome::IsCommandEnabled(browser, command)) {
AutomationJSONReply(this, reply_message).SendError(
base::StringPrintf("Browser command=%d not enabled.", command));
return;
}
// First check if we can handle the command without using an observer.
for (size_t i = 0; i < arraysize(kSynchronousCommands); i++) {
if (command == kSynchronousCommands[i]) {
chrome::ExecuteCommand(browser, command);
AutomationJSONReply(this, reply_message).SendSuccess(NULL);
return;
}
}
// Use an observer if we have one, otherwise fail.
if (ExecuteBrowserCommandObserver::CreateAndRegisterObserver(
this, browser, command, reply_message, true)) {
chrome::ExecuteCommand(browser, command);
return;
}
AutomationJSONReply(this, reply_message).SendError(base::StringPrintf(
"Unable to register observer for browser command=%d.", command));
}
void TestingAutomationProvider::IsMenuCommandEnabledJSON(
DictionaryValue* args,
IPC::Message* reply_message) {
int command;
Browser* browser;
std::string error;
if (!GetBrowserFromJSONArgs(args, &browser, &error)) {
AutomationJSONReply(this, reply_message).SendError(error);
return;
}
if (!args->GetInteger("accelerator", &command)) {
AutomationJSONReply(this, reply_message).SendError(
"'accelerator' missing or invalid.");
return;
}
DictionaryValue dict;
dict.SetBoolean("enabled", chrome::IsCommandEnabled(browser, command));
AutomationJSONReply(this, reply_message).SendSuccess(&dict);
}
void TestingAutomationProvider::GetTabInfo(
DictionaryValue* args,
IPC::Message* reply_message) {
AutomationJSONReply reply(this, reply_message);
Browser* browser;
WebContents* tab;
std::string error;
if (GetBrowserAndTabFromJSONArgs(args, &browser, &tab, &error)) {
NavigationEntry* entry = tab->GetController().GetActiveEntry();
if (!entry) {
reply.SendError("Unable to get active navigation entry");
return;
}
DictionaryValue dict;
dict.SetString("title", entry->GetTitleForDisplay(std::string()));
dict.SetString("url", entry->GetVirtualURL().spec());
reply.SendSuccess(&dict);
} else {
reply.SendError(error);
}
}
void TestingAutomationProvider::GetTabCountJSON(
DictionaryValue* args,
IPC::Message* reply_message) {
AutomationJSONReply reply(this, reply_message);
Browser* browser;
std::string error;
if (!GetBrowserFromJSONArgs(args, &browser, &error)) {
reply.SendError(error);
return;
}
DictionaryValue dict;
dict.SetInteger("tab_count", browser->tab_strip_model()->count());
reply.SendSuccess(&dict);
}
void TestingAutomationProvider::GoBack(
DictionaryValue* args,
IPC::Message* reply_message) {
if (SendErrorIfModalDialogActive(this, reply_message))
return;
WebContents* web_contents;
std::string error;
if (!GetTabFromJSONArgs(args, &web_contents, &error)) {
AutomationJSONReply(this, reply_message).SendError(error);
return;
}
NavigationController& controller = web_contents->GetController();
if (!controller.CanGoBack()) {
DictionaryValue dict;
dict.SetBoolean("did_go_back", false);
AutomationJSONReply(this, reply_message).SendSuccess(&dict);
return;
}
new NavigationNotificationObserver(&controller, this, reply_message,
1, false, true);
controller.GoBack();
}
void TestingAutomationProvider::ReloadJSON(
DictionaryValue* args,
IPC::Message* reply_message) {
if (SendErrorIfModalDialogActive(this, reply_message))
return;
WebContents* web_contents;
std::string error;
if (!GetTabFromJSONArgs(args, &web_contents, &error)) {
AutomationJSONReply(this, reply_message).SendError(error);
return;
}
NavigationController& controller = web_contents->GetController();
new NavigationNotificationObserver(&controller, this, reply_message,
1, false, true);
controller.Reload(false);
}
void TestingAutomationProvider::GetCookiesJSON(
DictionaryValue* args, IPC::Message* reply_message) {
automation_util::GetCookiesJSON(this, args, reply_message);
}
void TestingAutomationProvider::DeleteCookieJSON(
DictionaryValue* args, IPC::Message* reply_message) {
automation_util::DeleteCookieJSON(this, args, reply_message);
}
void TestingAutomationProvider::SetCookieJSON(
DictionaryValue* args, IPC::Message* reply_message) {
automation_util::SetCookieJSON(this, args, reply_message);
}
void TestingAutomationProvider::GetCookiesInBrowserContext(
DictionaryValue* args,
IPC::Message* reply_message) {
AutomationJSONReply reply(this, reply_message);
WebContents* web_contents;
std::string value, url_string;
int windex, value_size;
if (!args->GetInteger("windex", &windex)) {
reply.SendError("'windex' missing or invalid.");
return;
}
web_contents = automation_util::GetWebContentsAt(windex, 0);
if (!web_contents) {
reply.SendError("'windex' does not refer to a browser window.");
return;
}
if (!args->GetString("url", &url_string)) {
reply.SendError("'url' missing or invalid.");
return;
}
GURL url(url_string);
if (!url.is_valid()) {
reply.SendError("Invalid url.");
return;
}
automation_util::GetCookies(url, web_contents, &value_size, &value);
if (value_size == -1) {
reply.SendError(
base::StringPrintf("Unable to retrieve cookies for url=%s.",
url_string.c_str()));
return;
}
DictionaryValue dict;
dict.SetString("cookies", value);
reply.SendSuccess(&dict);
}
void TestingAutomationProvider::DeleteCookieInBrowserContext(
DictionaryValue* args,
IPC::Message* reply_message) {
AutomationJSONReply reply(this, reply_message);
WebContents* web_contents;
std::string cookie_name, url_string;
int windex;
bool success = false;
if (!args->GetInteger("windex", &windex)) {
reply.SendError("'windex' missing or invalid.");
return;
}
web_contents = automation_util::GetWebContentsAt(windex, 0);
if (!web_contents) {
reply.SendError("'windex' does not refer to a browser window.");
return;
}
if (!args->GetString("cookie_name", &cookie_name)) {
reply.SendError("'cookie_name' missing or invalid.");
return;
}
if (!args->GetString("url", &url_string)) {
reply.SendError("'url' missing or invalid.");
return;
}
GURL url(url_string);
if (!url.is_valid()) {
reply.SendError("Invalid url.");
return;
}
automation_util::DeleteCookie(url, cookie_name, web_contents, &success);
if (!success) {
reply.SendError(
base::StringPrintf("Failed to delete cookie with name=%s for url=%s.",
cookie_name.c_str(), url_string.c_str()));
return;
}
reply.SendSuccess(NULL);
}
void TestingAutomationProvider::SetCookieInBrowserContext(
DictionaryValue* args,
IPC::Message* reply_message) {
AutomationJSONReply reply(this, reply_message);
WebContents* web_contents;
std::string value, url_string;
int windex, response_value = -1;
if (!args->GetInteger("windex", &windex)) {
reply.SendError("'windex' missing or invalid.");
return;
}
web_contents = automation_util::GetWebContentsAt(windex, 0);
if (!web_contents) {
reply.SendError("'windex' does not refer to a browser window.");
return;
}
if (!args->GetString("value", &value)) {
reply.SendError("'value' missing or invalid.");
return;
}
if (!args->GetString("url", &url_string)) {
reply.SendError("'url' missing or invalid.");
return;
}
GURL url(url_string);
if (!url.is_valid()) {
reply.SendError("Invalid url.");
return;
}
automation_util::SetCookie(url, value, web_contents, &response_value);
if (response_value != 1) {
reply.SendError(base::StringPrintf(
"Unable set cookie for url=%s.", url_string.c_str()));
return;
}
reply.SendSuccess(NULL);
}
void TestingAutomationProvider::GetTabIds(
DictionaryValue* args, IPC::Message* reply_message) {
ListValue* id_list = new ListValue();
for (chrome::BrowserIterator it; !it.done(); it.Next()) {
Browser* browser = *it;
for (int i = 0; i < browser->tab_strip_model()->count(); ++i) {
int id = SessionTabHelper::FromWebContents(
browser->tab_strip_model()->GetWebContentsAt(i))->session_id().id();
id_list->Append(Value::CreateIntegerValue(id));
}
}
DictionaryValue dict;
dict.Set("ids", id_list);
AutomationJSONReply(this, reply_message).SendSuccess(&dict);
}
void TestingAutomationProvider::IsTabIdValid(
DictionaryValue* args, IPC::Message* reply_message) {
AutomationJSONReply reply(this, reply_message);
int id;
if (!args->GetInteger("id", &id)) {
reply.SendError("'id' missing or invalid");
return;
}
bool is_valid = false;
for (chrome::BrowserIterator it; !it.done(); it.Next()) {
Browser* browser = *it;
for (int i = 0; i < browser->tab_strip_model()->count(); ++i) {
WebContents* tab = browser->tab_strip_model()->GetWebContentsAt(i);
SessionTabHelper* session_tab_helper =
SessionTabHelper::FromWebContents(tab);
if (session_tab_helper->session_id().id() == id) {
is_valid = true;
break;
}
}
}
DictionaryValue dict;
dict.SetBoolean("is_valid", is_valid);
reply.SendSuccess(&dict);
}
void TestingAutomationProvider::CloseTabJSON(
DictionaryValue* args, IPC::Message* reply_message) {
Browser* browser;
WebContents* tab;
std::string error;
bool wait_until_closed = false; // ChromeDriver does not use this.
args->GetBoolean("wait_until_closed", &wait_until_closed);
// Close tabs synchronously.
if (GetBrowserAndTabFromJSONArgs(args, &browser, &tab, &error)) {
if (wait_until_closed) {
new TabClosedNotificationObserver(this, wait_until_closed, reply_message,
true);
}
chrome::CloseWebContents(browser, tab, false);
if (!wait_until_closed)
AutomationJSONReply(this, reply_message).SendSuccess(NULL);
return;
}
// Close other types of views asynchronously.
RenderViewHost* view;
if (!GetRenderViewFromJSONArgs(args, profile(), &view, &error)) {
AutomationJSONReply(this, reply_message).SendError(error);
return;
}
view->ClosePage();
AutomationJSONReply(this, reply_message).SendSuccess(NULL);
}
void TestingAutomationProvider::SetViewBounds(
base::DictionaryValue* args,
IPC::Message* reply_message) {
AutomationJSONReply reply(this, reply_message);
int x, y, width, height;
if (!args->GetInteger("bounds.x", &x) ||
!args->GetInteger("bounds.y", &y) ||
!args->GetInteger("bounds.width", &width) ||
!args->GetInteger("bounds.height", &height)) {
reply.SendError("Missing or invalid 'bounds'");
return;
}
Browser* browser;
std::string error;
if (!GetBrowserFromJSONArgs(args, &browser, &error)) {
reply.SendError(error);
return;
}
BrowserWindow* browser_window = browser->window();
if (browser_window->IsMaximized()) {
browser_window->Restore();
}
browser_window->SetBounds(gfx::Rect(x, y, width, height));
reply.SendSuccess(NULL);
}
void TestingAutomationProvider::MaximizeView(
base::DictionaryValue* args,
IPC::Message* reply_message) {
Browser* browser;
std::string error;
if (!GetBrowserFromJSONArgs(args, &browser, &error)) {
AutomationJSONReply(this, reply_message).SendError(error);
return;
}
#if defined(OS_LINUX)
// Maximization on Linux is asynchronous, so create an observer object to be
// notified upon maximization completion.
new WindowMaximizedObserver(this, reply_message);
#endif // defined(OS_LINUX)
browser->window()->Maximize();
#if !defined(OS_LINUX)
// Send success reply right away for OS's with synchronous maximize command.
AutomationJSONReply(this, reply_message).SendSuccess(NULL);
#endif // !defined(OS_LINUX)
}
void TestingAutomationProvider::ActivateTabJSON(
DictionaryValue* args,
IPC::Message* reply_message) {
if (SendErrorIfModalDialogActive(this, reply_message))
return;
AutomationJSONReply reply(this, reply_message);
Browser* browser;
WebContents* web_contents;
std::string error;
if (!GetBrowserAndTabFromJSONArgs(args, &browser, &web_contents, &error)) {
reply.SendError(error);
return;
}
TabStripModel* tab_strip = browser->tab_strip_model();
tab_strip->ActivateTabAt(tab_strip->GetIndexOfWebContents(web_contents),
true);
reply.SendSuccess(NULL);
}
void TestingAutomationProvider::IsPageActionVisible(
base::DictionaryValue* args,
IPC::Message* reply_message) {
AutomationJSONReply reply(this, reply_message);
WebContents* tab;
std::string error;
if (!GetTabFromJSONArgs(args, &tab, &error)) {
reply.SendError(error);
return;
}
Browser* browser = automation_util::GetBrowserForTab(tab);
if (!browser) {
reply.SendError("Tab does not belong to an open browser");
return;
}
const Extension* extension;
if (!GetEnabledExtensionFromJSONArgs(
args, "extension_id", browser->profile(), &extension, &error)) {
reply.SendError(error);
return;
}
ExtensionAction* page_action =
ExtensionActionManager::Get(browser->profile())->
GetPageAction(*extension);
if (!page_action) {
reply.SendError("Extension doesn't have any page action");
return;
}
EnsureTabSelected(browser, tab);
bool is_visible = false;
LocationBarTesting* loc_bar =
browser->window()->GetLocationBar()->GetLocationBarForTesting();
size_t page_action_visible_count =
static_cast<size_t>(loc_bar->PageActionVisibleCount());
for (size_t i = 0; i < page_action_visible_count; ++i) {
if (loc_bar->GetVisiblePageAction(i) == page_action) {
is_visible = true;
break;
}
}
DictionaryValue dict;
dict.SetBoolean("is_visible", is_visible);
reply.SendSuccess(&dict);
}
void TestingAutomationProvider::CreateNewAutomationProvider(
DictionaryValue* args,
IPC::Message* reply_message) {
AutomationJSONReply reply(this, reply_message);
std::string channel_id;
if (!args->GetString("channel_id", &channel_id)) {
reply.SendError("'channel_id' missing or invalid");
return;
}
AutomationProvider* provider = new TestingAutomationProvider(profile_);
provider->DisableInitialLoadObservers();
// TODO(kkania): Remove this when crbug.com/91311 is fixed.
// Named server channels should ideally be created and closed on the file
// thread, within the IPC channel code.
base::ThreadRestrictions::ScopedAllowIO allow_io;
if (!provider->InitializeChannel(
automation::kNamedInterfacePrefix + channel_id)) {
reply.SendError("Failed to initialize channel: " + channel_id);
return;
}
DCHECK(g_browser_process);
g_browser_process->GetAutomationProviderList()->AddProvider(provider);
reply.SendSuccess(NULL);
}
void TestingAutomationProvider::WaitForTabCountToBecome(
int browser_handle,
int target_tab_count,
IPC::Message* reply_message) {
if (!browser_tracker_->ContainsHandle(browser_handle)) {
AutomationMsg_WaitForTabCountToBecome::WriteReplyParams(reply_message,
false);
Send(reply_message);
return;
}
Browser* browser = browser_tracker_->GetResource(browser_handle);
// The observer will delete itself.
new TabCountChangeObserver(this, browser, reply_message, target_tab_count);
}
void TestingAutomationProvider::WaitForInfoBarCount(
int tab_handle,
size_t target_count,
IPC::Message* reply_message) {
if (!tab_tracker_->ContainsHandle(tab_handle)) {
AutomationMsg_WaitForInfoBarCount::WriteReplyParams(reply_message_, false);
Send(reply_message_);
return;
}
NavigationController* controller = tab_tracker_->GetResource(tab_handle);
if (!controller) {
AutomationMsg_WaitForInfoBarCount::WriteReplyParams(reply_message_, false);
Send(reply_message_);
return;
}
// The delegate will delete itself.
new InfoBarCountObserver(this, reply_message,
controller->GetWebContents(), target_count);
}
void TestingAutomationProvider::WaitForProcessLauncherThreadToGoIdle(
IPC::Message* reply_message) {
new WaitForProcessLauncherThreadToGoIdleObserver(this, reply_message);
}
void TestingAutomationProvider::OnRemoveProvider() {
if (g_browser_process)
g_browser_process->GetAutomationProviderList()->RemoveProvider(this);
}
void TestingAutomationProvider::EnsureTabSelected(Browser* browser,
WebContents* tab) {
TabStripModel* tab_strip = browser->tab_strip_model();
if (tab_strip->GetActiveWebContents() != tab)
tab_strip->ActivateTabAt(tab_strip->GetIndexOfWebContents(tab), true);
}