blob: 1217c1a60f8c2c1a530b103ae202eb3350eff476 [file] [log] [blame]
// Copyright (c) 2006-2009 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/automation_provider.h"
#include "app/l10n_util.h"
#include "app/message_box_flags.h"
#include "base/file_version_info.h"
#include "base/json_reader.h"
#include "base/message_loop.h"
#include "base/path_service.h"
#include "base/stl_util-inl.h"
#include "base/string_util.h"
#include "base/thread.h"
#include "base/values.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/browser/app_modal_dialog.h"
#include "chrome/browser/app_modal_dialog_queue.h"
#include "chrome/browser/automation/automation_extension_function.h"
#include "chrome/browser/automation/automation_provider_list.h"
#include "chrome/browser/automation/extension_automation_constants.h"
#include "chrome/browser/automation/extension_port_container.h"
#include "chrome/browser/automation/url_request_failed_dns_job.h"
#include "chrome/browser/automation/url_request_mock_http_job.h"
#include "chrome/browser/automation/url_request_slow_download_job.h"
#include "chrome/browser/blocked_popup_container.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_window.h"
#include "chrome/browser/dom_operation_notification_details.h"
#include "chrome/browser/debugger/devtools_manager.h"
#include "chrome/browser/download/download_manager.h"
#include "chrome/browser/download/download_shelf.h"
#include "chrome/browser/extensions/extension_message_service.h"
#include "chrome/browser/find_bar.h"
#include "chrome/browser/find_bar_controller.h"
#include "chrome/browser/find_notification_details.h"
#include "chrome/browser/location_bar.h"
#include "chrome/browser/profile_manager.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/ssl/ssl_manager.h"
#include "chrome/browser/ssl/ssl_blocking_page.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/tab_contents_view.h"
#include "chrome/common/automation_constants.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/json_value_serializer.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/platform_util.h"
#include "chrome/common/pref_service.h"
#include "chrome/test/automation/automation_messages.h"
#include "net/base/cookie_monster.h"
#include "net/proxy/proxy_service.h"
#include "net/proxy/proxy_config_service_fixed.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_filter.h"
#if defined(OS_WIN)
// TODO(port): Port these headers.
#include "chrome/browser/automation/ui_controls.h"
#include "chrome/browser/character_encoding.h"
#include "chrome/browser/download/save_package.h"
#include "chrome/browser/external_tab_container.h"
#include "chrome/browser/printing/print_job.h"
#endif // defined(OS_WIN)
#if defined(OS_WIN) || defined(OS_LINUX)
// TODO(port): Port these to the mac.
#include "chrome/browser/login_prompt.h"
#endif
#if defined(OS_WIN)
#include "chrome/browser/views/bookmark_bar_view.h"
#include "views/widget/root_view.h"
#include "views/widget/widget_win.h"
#include "views/window/window.h"
#endif
using base::Time;
class InitialLoadObserver : public NotificationObserver {
public:
InitialLoadObserver(size_t tab_count, AutomationProvider* automation)
: automation_(automation),
outstanding_tab_count_(tab_count) {
if (outstanding_tab_count_ > 0) {
registrar_.Add(this, NotificationType::LOAD_START,
NotificationService::AllSources());
registrar_.Add(this, NotificationType::LOAD_STOP,
NotificationService::AllSources());
}
}
~InitialLoadObserver() {
}
void ConditionMet() {
registrar_.RemoveAll();
automation_->Send(new AutomationMsg_InitialLoadsComplete(0));
}
virtual void Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
if (type == NotificationType::LOAD_START) {
if (outstanding_tab_count_ > loading_tabs_.size())
loading_tabs_.insert(source.map_key());
} else if (type == NotificationType::LOAD_STOP) {
if (outstanding_tab_count_ > finished_tabs_.size()) {
if (loading_tabs_.find(source.map_key()) != loading_tabs_.end())
finished_tabs_.insert(source.map_key());
if (outstanding_tab_count_ == finished_tabs_.size())
ConditionMet();
}
} else {
NOTREACHED();
}
}
private:
typedef std::set<uintptr_t> TabSet;
NotificationRegistrar registrar_;
AutomationProvider* automation_;
size_t outstanding_tab_count_;
TabSet loading_tabs_;
TabSet finished_tabs_;
};
// Watches for NewTabUI page loads for performance timing purposes.
class NewTabUILoadObserver : public NotificationObserver {
public:
explicit NewTabUILoadObserver(AutomationProvider* automation)
: automation_(automation) {
registrar_.Add(this, NotificationType::INITIAL_NEW_TAB_UI_LOAD,
NotificationService::AllSources());
}
~NewTabUILoadObserver() {
}
virtual void Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
if (type == NotificationType::INITIAL_NEW_TAB_UI_LOAD) {
Details<int> load_time(details);
automation_->Send(
new AutomationMsg_InitialNewTabUILoadComplete(0, *load_time.ptr()));
} else {
NOTREACHED();
}
}
private:
NotificationRegistrar registrar_;
AutomationProvider* automation_;
};
class NavigationControllerRestoredObserver : public NotificationObserver {
public:
NavigationControllerRestoredObserver(AutomationProvider* automation,
NavigationController* controller,
IPC::Message* reply_message)
: automation_(automation),
controller_(controller),
reply_message_(reply_message) {
if (FinishedRestoring()) {
SendDone();
} else {
registrar_.Add(this, NotificationType::LOAD_STOP,
NotificationService::AllSources());
}
}
~NavigationControllerRestoredObserver() {
}
virtual void Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
if (FinishedRestoring()) {
SendDone();
registrar_.RemoveAll();
}
}
private:
bool FinishedRestoring() {
return (!controller_->needs_reload() && !controller_->pending_entry() &&
!controller_->tab_contents()->is_loading());
}
void SendDone() {
DCHECK(reply_message_ != NULL);
automation_->Send(reply_message_);
}
NotificationRegistrar registrar_;
AutomationProvider* automation_;
NavigationController* controller_;
IPC::Message* reply_message_;
DISALLOW_COPY_AND_ASSIGN(NavigationControllerRestoredObserver);
};
template<class NavigationCodeType>
class NavigationNotificationObserver : public NotificationObserver {
public:
NavigationNotificationObserver(NavigationController* controller,
AutomationProvider* automation,
IPC::Message* reply_message,
NavigationCodeType success_code,
NavigationCodeType auth_needed_code,
NavigationCodeType failed_code)
: automation_(automation),
reply_message_(reply_message),
controller_(controller),
navigation_started_(false),
success_code_(success_code),
auth_needed_code_(auth_needed_code),
failed_code_(failed_code) {
Source<NavigationController> source(controller_);
registrar_.Add(this, NotificationType::NAV_ENTRY_COMMITTED, source);
registrar_.Add(this, NotificationType::LOAD_START, source);
registrar_.Add(this, NotificationType::LOAD_STOP, source);
registrar_.Add(this, NotificationType::AUTH_NEEDED, source);
registrar_.Add(this, NotificationType::AUTH_SUPPLIED, source);
}
~NavigationNotificationObserver() {
if (reply_message_) {
// This means we did not receive a notification for this navigation.
// Send over a failed navigation status back to the caller to ensure that
// the caller does not hang waiting for the response.
IPC::ParamTraits<NavigationCodeType>::Write(reply_message_,
failed_code_);
automation_->Send(reply_message_);
reply_message_ = NULL;
}
automation_->RemoveNavigationStatusListener(this);
}
void ConditionMet(NavigationCodeType navigation_result) {
DCHECK(reply_message_ != NULL);
IPC::ParamTraits<NavigationCodeType>::Write(reply_message_,
navigation_result);
automation_->Send(reply_message_);
reply_message_ = NULL;
delete this;
}
virtual void Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
// We listen for 2 events to determine when the navigation started because:
// - when this is used by the WaitForNavigation method, we might be invoked
// afer the load has started (but not after the entry was committed, as
// WaitForNavigation compares times of the last navigation).
// - when this is used with a page requiring authentication, we will not get
// a NotificationType::NAV_ENTRY_COMMITTED until after we authenticate, so
// we need the NotificationType::LOAD_START.
if (type == NotificationType::NAV_ENTRY_COMMITTED ||
type == NotificationType::LOAD_START) {
navigation_started_ = true;
} else if (type == NotificationType::LOAD_STOP) {
if (navigation_started_) {
navigation_started_ = false;
ConditionMet(success_code_);
}
} else if (type == NotificationType::AUTH_SUPPLIED) {
// The LoginHandler for this tab is no longer valid.
automation_->RemoveLoginHandler(controller_);
// Treat this as if navigation started again, since load start/stop don't
// occur while authentication is ongoing.
navigation_started_ = true;
} else if (type == NotificationType::AUTH_NEEDED) {
#if defined(OS_WIN)
if (navigation_started_) {
// Remember the login handler that wants authentication.
LoginHandler* handler =
Details<LoginNotificationDetails>(details)->handler();
automation_->AddLoginHandler(controller_, handler);
// Respond that authentication is needed.
navigation_started_ = false;
ConditionMet(auth_needed_code_);
} else {
NOTREACHED();
}
#else
// TODO(port): Enable when we have LoginNotificationDetails etc.
NOTIMPLEMENTED();
#endif
} else {
NOTREACHED();
}
}
private:
NotificationRegistrar registrar_;
AutomationProvider* automation_;
IPC::Message* reply_message_;
NavigationController* controller_;
bool navigation_started_;
NavigationCodeType success_code_;
NavigationCodeType auth_needed_code_;
NavigationCodeType failed_code_;
};
class TabStripNotificationObserver : public NotificationObserver {
public:
TabStripNotificationObserver(NotificationType notification,
AutomationProvider* automation)
: automation_(automation),
notification_(notification) {
registrar_.Add(this, notification_, NotificationService::AllSources());
}
virtual ~TabStripNotificationObserver() {
}
virtual void Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
if (type == notification_) {
ObserveTab(Source<NavigationController>(source).ptr());
// If verified, no need to observe anymore
automation_->RemoveTabStripObserver(this);
delete this;
} else {
NOTREACHED();
}
}
virtual void ObserveTab(NavigationController* controller) = 0;
protected:
NotificationRegistrar registrar_;
AutomationProvider* automation_;
NotificationType notification_;
};
class TabAppendedNotificationObserver : public TabStripNotificationObserver {
public:
TabAppendedNotificationObserver(Browser* parent,
AutomationProvider* automation,
IPC::Message* reply_message)
: TabStripNotificationObserver(NotificationType::TAB_PARENTED,
automation),
parent_(parent),
reply_message_(reply_message) {
}
virtual void ObserveTab(NavigationController* controller) {
if (automation_->GetIndexForNavigationController(controller, parent_) ==
TabStripModel::kNoTab) {
// This tab notification doesn't belong to the parent_.
return;
}
// Give the same response even if auth is needed, since it doesn't matter.
automation_->AddNavigationStatusListener<int>(
controller, reply_message_, AUTOMATION_MSG_NAVIGATION_SUCCESS,
AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED, AUTOMATION_MSG_NAVIGATION_ERROR);
}
protected:
Browser* parent_;
IPC::Message* reply_message_;
};
class TabClosedNotificationObserver : public TabStripNotificationObserver {
public:
TabClosedNotificationObserver(AutomationProvider* automation,
bool wait_until_closed,
IPC::Message* reply_message)
: TabStripNotificationObserver(wait_until_closed ?
NotificationType::TAB_CLOSED : NotificationType::TAB_CLOSING,
automation),
reply_message_(reply_message),
for_browser_command_(false) {
}
virtual void ObserveTab(NavigationController* controller) {
if (for_browser_command_) {
AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message_,
true);
} else {
AutomationMsg_CloseTab::WriteReplyParams(reply_message_, true);
}
automation_->Send(reply_message_);
}
void set_for_browser_command(bool for_browser_command) {
for_browser_command_ = for_browser_command;
}
protected:
IPC::Message* reply_message_;
bool for_browser_command_;
};
class BrowserOpenedNotificationObserver : public NotificationObserver {
public:
BrowserOpenedNotificationObserver(AutomationProvider* automation,
IPC::Message* reply_message)
: automation_(automation),
reply_message_(reply_message),
for_browser_command_(false) {
registrar_.Add(this, NotificationType::BROWSER_OPENED,
NotificationService::AllSources());
}
~BrowserOpenedNotificationObserver() {
}
virtual void Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
if (type == NotificationType::BROWSER_OPENED) {
if (for_browser_command_) {
AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message_,
true);
}
automation_->Send(reply_message_);
delete this;
} else {
NOTREACHED();
}
}
void set_for_browser_command(bool for_browser_command) {
for_browser_command_ = for_browser_command;
}
private:
NotificationRegistrar registrar_;
AutomationProvider* automation_;
IPC::Message* reply_message_;
bool for_browser_command_;
};
class BrowserClosedNotificationObserver : public NotificationObserver {
public:
BrowserClosedNotificationObserver(Browser* browser,
AutomationProvider* automation,
IPC::Message* reply_message)
: automation_(automation),
reply_message_(reply_message),
for_browser_command_(false) {
registrar_.Add(this, NotificationType::BROWSER_CLOSED,
Source<Browser>(browser));
}
virtual void Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
DCHECK(type == NotificationType::BROWSER_CLOSED);
Details<bool> close_app(details);
DCHECK(reply_message_ != NULL);
if (for_browser_command_) {
AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message_,
true);
} else {
AutomationMsg_CloseBrowser::WriteReplyParams(reply_message_, true,
*(close_app.ptr()));
}
automation_->Send(reply_message_);
reply_message_ = NULL;
delete this;
}
void set_for_browser_command(bool for_browser_command) {
for_browser_command_ = for_browser_command;
}
private:
NotificationRegistrar registrar_;
AutomationProvider* automation_;
IPC::Message* reply_message_;
bool for_browser_command_;
};
namespace {
// Define mapping from command to notification
struct CommandNotification {
int command;
NotificationType::Type notification_type;
};
const struct CommandNotification command_notifications[] = {
{IDC_DUPLICATE_TAB, NotificationType::TAB_PARENTED},
{IDC_NEW_TAB, NotificationType::TAB_PARENTED},
// Returns as soon as the restored tab is created. To further wait until
// the content page is loaded, use WaitForTabToBeRestored.
{IDC_RESTORE_TAB, NotificationType::TAB_PARENTED}
};
} // namespace
class ExecuteBrowserCommandObserver : public NotificationObserver {
public:
~ExecuteBrowserCommandObserver() {
}
static bool CreateAndRegisterObserver(AutomationProvider* automation,
Browser* browser,
int command,
IPC::Message* reply_message) {
bool result = true;
switch (command) {
case IDC_NEW_WINDOW:
case IDC_NEW_INCOGNITO_WINDOW: {
BrowserOpenedNotificationObserver* observer =
new BrowserOpenedNotificationObserver(automation, reply_message);
observer->set_for_browser_command(true);
break;
}
case IDC_CLOSE_WINDOW: {
BrowserClosedNotificationObserver* observer =
new BrowserClosedNotificationObserver(browser, automation,
reply_message);
observer->set_for_browser_command(true);
break;
}
case IDC_CLOSE_TAB: {
TabClosedNotificationObserver* observer =
new TabClosedNotificationObserver(automation, true, reply_message);
observer->set_for_browser_command(true);
break;
}
case IDC_BACK:
case IDC_FORWARD:
case IDC_RELOAD: {
automation->
AddNavigationStatusListener<AutomationMsg_NavigationResponseValues>(
&browser->GetSelectedTabContents()->controller(),
reply_message,
AUTOMATION_MSG_NAVIGATION_SUCCESS,
AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED,
AUTOMATION_MSG_NAVIGATION_ERROR);
break;
}
default: {
ExecuteBrowserCommandObserver* observer =
new ExecuteBrowserCommandObserver(automation, reply_message);
if (!observer->Register(command)) {
delete observer;
result = false;
}
break;
}
}
return result;
}
virtual void Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
if (type == notification_type_) {
AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message_,
true);
automation_->Send(reply_message_);
delete this;
} else {
NOTREACHED();
}
}
private:
ExecuteBrowserCommandObserver(AutomationProvider* automation,
IPC::Message* reply_message)
: automation_(automation),
reply_message_(reply_message) {
}
bool Register(int command) {
if (!GetNotificationType(command, &notification_type_))
return false;
registrar_.Add(this, notification_type_, NotificationService::AllSources());
return true;
}
bool GetNotificationType(int command, NotificationType::Type* type) {
if (!type)
return false;
bool found = false;
for (unsigned int i = 0; i < arraysize(command_notifications); i++) {
if (command_notifications[i].command == command) {
*type = command_notifications[i].notification_type;
found = true;
break;
}
}
return found;
}
NotificationRegistrar registrar_;
AutomationProvider* automation_;
NotificationType::Type notification_type_;
IPC::Message* reply_message_;
};
class FindInPageNotificationObserver : public NotificationObserver {
public:
FindInPageNotificationObserver(AutomationProvider* automation,
TabContents* parent_tab,
IPC::Message* reply_message)
: automation_(automation),
active_match_ordinal_(-1),
reply_message_(reply_message) {
registrar_.Add(this, NotificationType::FIND_RESULT_AVAILABLE,
Source<TabContents>(parent_tab));
}
~FindInPageNotificationObserver() {
}
virtual void Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
if (type == NotificationType::FIND_RESULT_AVAILABLE) {
Details<FindNotificationDetails> find_details(details);
if (find_details->request_id() == kFindInPageRequestId) {
// We get multiple responses and one of those will contain the ordinal.
// This message comes to us before the final update is sent.
if (find_details->active_match_ordinal() > -1)
active_match_ordinal_ = find_details->active_match_ordinal();
if (find_details->final_update()) {
DCHECK(reply_message_ != NULL);
AutomationMsg_FindInPage::WriteReplyParams(reply_message_,
active_match_ordinal_, find_details->number_of_matches());
automation_->Send(reply_message_);
reply_message_ = NULL;
} else {
DLOG(INFO) << "Ignoring, since we only care about the final message";
}
}
} else {
NOTREACHED();
}
}
// The Find mechanism is over asynchronous IPC, so a search is kicked off and
// we wait for notification to find out what the results are. As the user is
// typing, new search requests can be issued and the Request ID helps us make
// sense of whether this is the current request or an old one. The unit tests,
// however, which uses this constant issues only one search at a time, so we
// don't need a rolling id to identify each search. But, we still need to
// specify one, so we just use a fixed one - its value does not matter.
static const int kFindInPageRequestId;
private:
NotificationRegistrar registrar_;
AutomationProvider* automation_;
// We will at some point (before final update) be notified of the ordinal and
// we need to preserve it so we can send it later.
int active_match_ordinal_;
IPC::Message* reply_message_;
};
const int FindInPageNotificationObserver::kFindInPageRequestId = -1;
class DomOperationNotificationObserver : public NotificationObserver {
public:
explicit DomOperationNotificationObserver(AutomationProvider* automation)
: automation_(automation) {
registrar_.Add(this, NotificationType::DOM_OPERATION_RESPONSE,
NotificationService::AllSources());
}
~DomOperationNotificationObserver() {
}
virtual void Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
if (NotificationType::DOM_OPERATION_RESPONSE == type) {
Details<DomOperationNotificationDetails> dom_op_details(details);
IPC::Message* reply_message = automation_->reply_message_release();
DCHECK(reply_message != NULL);
AutomationMsg_DomOperation::WriteReplyParams(reply_message,
dom_op_details->json());
automation_->Send(reply_message);
}
}
private:
NotificationRegistrar registrar_;
AutomationProvider* automation_;
};
#if defined(OS_WIN)
// TODO(port): Enable when printing is ported.
class DocumentPrintedNotificationObserver : public NotificationObserver {
public:
DocumentPrintedNotificationObserver(AutomationProvider* automation,
IPC::Message* reply_message)
: automation_(automation),
success_(false),
reply_message_(reply_message) {
registrar_.Add(this, NotificationType::PRINT_JOB_EVENT,
NotificationService::AllSources());
}
~DocumentPrintedNotificationObserver() {
DCHECK(reply_message_ != NULL);
AutomationMsg_PrintNow::WriteReplyParams(reply_message_, success_);
automation_->Send(reply_message_);
automation_->RemoveNavigationStatusListener(this);
}
virtual void Observe(NotificationType type, const NotificationSource& source,
const NotificationDetails& details) {
using namespace printing;
DCHECK(type == NotificationType::PRINT_JOB_EVENT);
switch (Details<JobEventDetails>(details)->type()) {
case JobEventDetails::JOB_DONE: {
// Succeeded.
success_ = true;
delete this;
break;
}
case JobEventDetails::USER_INIT_CANCELED:
case JobEventDetails::FAILED: {
// Failed.
delete this;
break;
}
case JobEventDetails::NEW_DOC:
case JobEventDetails::USER_INIT_DONE:
case JobEventDetails::DEFAULT_INIT_DONE:
case JobEventDetails::NEW_PAGE:
case JobEventDetails::PAGE_DONE:
case JobEventDetails::DOC_DONE:
case JobEventDetails::ALL_PAGES_REQUESTED: {
// Don't care.
break;
}
default: {
NOTREACHED();
break;
}
}
}
private:
NotificationRegistrar registrar_;
scoped_refptr<AutomationProvider> automation_;
bool success_;
IPC::Message* reply_message_;
};
#endif // defined(OS_WIN)
class AutomationInterstitialPage : public InterstitialPage {
public:
AutomationInterstitialPage(TabContents* tab,
const GURL& url,
const std::string& contents)
: InterstitialPage(tab, true, url),
contents_(contents) {
}
virtual std::string GetHTMLContents() { return contents_; }
private:
std::string contents_;
DISALLOW_COPY_AND_ASSIGN(AutomationInterstitialPage);
};
AutomationProvider::AutomationProvider(Profile* profile)
: redirect_query_(0),
profile_(profile),
reply_message_(NULL) {
browser_tracker_.reset(new AutomationBrowserTracker(this));
tab_tracker_.reset(new AutomationTabTracker(this));
window_tracker_.reset(new AutomationWindowTracker(this));
autocomplete_edit_tracker_.reset(
new AutomationAutocompleteEditTracker(this));
new_tab_ui_load_observer_.reset(new NewTabUILoadObserver(this));
dom_operation_observer_.reset(new DomOperationNotificationObserver(this));
}
AutomationProvider::~AutomationProvider() {
STLDeleteContainerPairSecondPointers(port_containers_.begin(),
port_containers_.end());
port_containers_.clear();
// Make sure that any outstanding NotificationObservers also get destroyed.
ObserverList<NotificationObserver>::Iterator it(notification_observer_list_);
NotificationObserver* observer;
while ((observer = it.GetNext()) != NULL)
delete observer;
}
void AutomationProvider::ConnectToChannel(const std::string& channel_id) {
channel_.reset(
new IPC::SyncChannel(channel_id, IPC::Channel::MODE_CLIENT, this, NULL,
g_browser_process->io_thread()->message_loop(),
true, g_browser_process->shutdown_event()));
scoped_ptr<FileVersionInfo> file_version_info(
FileVersionInfo::CreateFileVersionInfoForCurrentModule());
std::string version_string;
if (file_version_info != NULL) {
version_string = WideToASCII(file_version_info->file_version());
}
// Send a hello message with our current automation protocol version.
channel_->Send(new AutomationMsg_Hello(0, version_string.c_str()));
}
void AutomationProvider::SetExpectedTabCount(size_t expected_tabs) {
if (expected_tabs == 0) {
Send(new AutomationMsg_InitialLoadsComplete(0));
} else {
initial_load_observer_.reset(new InitialLoadObserver(expected_tabs, this));
}
}
template<class NavigationCodeType>
NotificationObserver* AutomationProvider::AddNavigationStatusListener(
NavigationController* tab, IPC::Message* reply_message,
NavigationCodeType success_code,
NavigationCodeType auth_needed_code,
NavigationCodeType failed_code) {
NotificationObserver* observer =
new NavigationNotificationObserver<NavigationCodeType>(
tab, this, reply_message, success_code, auth_needed_code,
failed_code);
notification_observer_list_.AddObserver(observer);
return observer;
}
void AutomationProvider::RemoveNavigationStatusListener(
NotificationObserver* obs) {
notification_observer_list_.RemoveObserver(obs);
}
NotificationObserver* AutomationProvider::AddTabStripObserver(
Browser* parent,
IPC::Message* reply_message) {
NotificationObserver* observer =
new TabAppendedNotificationObserver(parent, this, reply_message);
notification_observer_list_.AddObserver(observer);
return observer;
}
void AutomationProvider::RemoveTabStripObserver(NotificationObserver* obs) {
notification_observer_list_.RemoveObserver(obs);
}
void AutomationProvider::AddLoginHandler(NavigationController* tab,
LoginHandler* handler) {
login_handler_map_[tab] = handler;
}
void AutomationProvider::RemoveLoginHandler(NavigationController* tab) {
DCHECK(login_handler_map_[tab]);
login_handler_map_.erase(tab);
}
void AutomationProvider::AddPortContainer(ExtensionPortContainer* port) {
int port_id = port->port_id();
DCHECK_NE(-1, port_id);
DCHECK(port_containers_.find(port_id) == port_containers_.end());
port_containers_[port_id] = port;
}
void AutomationProvider::RemovePortContainer(ExtensionPortContainer* port) {
int port_id = port->port_id();
DCHECK_NE(-1, port_id);
PortContainerMap::iterator it = port_containers_.find(port_id);
DCHECK(it != port_containers_.end());
if (it != port_containers_.end()) {
delete it->second;
port_containers_.erase(it);
}
}
ExtensionPortContainer* AutomationProvider::GetPortContainer(
int port_id) const {
PortContainerMap::const_iterator it = port_containers_.find(port_id);
if (it == port_containers_.end())
return NULL;
return it->second;
}
int AutomationProvider::GetIndexForNavigationController(
const NavigationController* controller, const Browser* parent) const {
DCHECK(parent);
return parent->GetIndexOfController(controller);
}
void AutomationProvider::OnMessageReceived(const IPC::Message& message) {
IPC_BEGIN_MESSAGE_MAP(AutomationProvider, message)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_CloseBrowser, CloseBrowser)
IPC_MESSAGE_HANDLER(AutomationMsg_CloseBrowserRequestAsync,
CloseBrowserAsync)
IPC_MESSAGE_HANDLER(AutomationMsg_ActivateTab, ActivateTab)
IPC_MESSAGE_HANDLER(AutomationMsg_ActiveTabIndex, GetActiveTabIndex)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_AppendTab, AppendTab)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_CloseTab, CloseTab)
IPC_MESSAGE_HANDLER(AutomationMsg_GetCookies, GetCookies)
IPC_MESSAGE_HANDLER(AutomationMsg_SetCookie, SetCookie)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_NavigateToURL, NavigateToURL)
IPC_MESSAGE_HANDLER(AutomationMsg_NavigationAsync, NavigationAsync)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_GoBack, GoBack)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_GoForward, GoForward)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_Reload, Reload)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_SetAuth, SetAuth)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_CancelAuth, CancelAuth)
IPC_MESSAGE_HANDLER(AutomationMsg_NeedsAuth, NeedsAuth)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_RedirectsFrom,
GetRedirectsFrom)
IPC_MESSAGE_HANDLER(AutomationMsg_BrowserWindowCount, GetBrowserWindowCount)
IPC_MESSAGE_HANDLER(AutomationMsg_NormalBrowserWindowCount,
GetNormalBrowserWindowCount)
IPC_MESSAGE_HANDLER(AutomationMsg_BrowserWindow, GetBrowserWindow)
IPC_MESSAGE_HANDLER(AutomationMsg_GetBrowserLocale, GetBrowserLocale)
IPC_MESSAGE_HANDLER(AutomationMsg_LastActiveBrowserWindow,
GetLastActiveBrowserWindow)
IPC_MESSAGE_HANDLER(AutomationMsg_ActiveWindow, GetActiveWindow)
IPC_MESSAGE_HANDLER(AutomationMsg_FindNormalBrowserWindow,
FindNormalBrowserWindow)
IPC_MESSAGE_HANDLER(AutomationMsg_IsWindowActive, IsWindowActive)
IPC_MESSAGE_HANDLER(AutomationMsg_ActivateWindow, ActivateWindow)
#if defined(OS_WIN)
IPC_MESSAGE_HANDLER(AutomationMsg_WindowHWND, GetWindowHWND)
#endif // defined(OS_WIN)
IPC_MESSAGE_HANDLER(AutomationMsg_WindowExecuteCommandAsync,
ExecuteBrowserCommandAsync)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WindowExecuteCommand,
ExecuteBrowserCommand)
IPC_MESSAGE_HANDLER(AutomationMsg_WindowViewBounds, WindowGetViewBounds)
IPC_MESSAGE_HANDLER(AutomationMsg_SetWindowBounds, SetWindowBounds)
IPC_MESSAGE_HANDLER(AutomationMsg_SetWindowVisible, SetWindowVisible)
#if defined(OS_WIN)
IPC_MESSAGE_HANDLER(AutomationMsg_WindowClick, WindowSimulateClick)
IPC_MESSAGE_HANDLER(AutomationMsg_WindowKeyPress, WindowSimulateKeyPress)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WindowDrag,
WindowSimulateDrag)
#endif // defined(OS_WIN)
IPC_MESSAGE_HANDLER(AutomationMsg_TabCount, GetTabCount)
IPC_MESSAGE_HANDLER(AutomationMsg_Tab, GetTab)
#if defined(OS_WIN)
IPC_MESSAGE_HANDLER(AutomationMsg_TabHWND, GetTabHWND)
#endif // defined(OS_WIN)
IPC_MESSAGE_HANDLER(AutomationMsg_TabProcessID, GetTabProcessID)
IPC_MESSAGE_HANDLER(AutomationMsg_TabTitle, GetTabTitle)
IPC_MESSAGE_HANDLER(AutomationMsg_TabIndex, GetTabIndex)
IPC_MESSAGE_HANDLER(AutomationMsg_TabURL, GetTabURL)
IPC_MESSAGE_HANDLER(AutomationMsg_ShelfVisibility, GetShelfVisibility)
IPC_MESSAGE_HANDLER(AutomationMsg_HandleUnused, HandleUnused)
IPC_MESSAGE_HANDLER(AutomationMsg_ApplyAccelerator, ApplyAccelerator)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_DomOperation,
ExecuteJavascript)
IPC_MESSAGE_HANDLER(AutomationMsg_ConstrainedWindowCount,
GetConstrainedWindowCount)
IPC_MESSAGE_HANDLER(AutomationMsg_FindInPage, HandleFindInPageRequest)
IPC_MESSAGE_HANDLER(AutomationMsg_GetFocusedViewID, GetFocusedViewID)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_InspectElement,
HandleInspectElementRequest)
IPC_MESSAGE_HANDLER(AutomationMsg_SetFilteredInet, SetFilteredInet)
IPC_MESSAGE_HANDLER(AutomationMsg_DownloadDirectory, GetDownloadDirectory)
IPC_MESSAGE_HANDLER(AutomationMsg_SetProxyConfig, SetProxyConfig);
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_OpenNewBrowserWindow,
OpenNewBrowserWindow)
IPC_MESSAGE_HANDLER(AutomationMsg_WindowForBrowser, GetWindowForBrowser)
IPC_MESSAGE_HANDLER(AutomationMsg_AutocompleteEditForBrowser,
GetAutocompleteEditForBrowser)
IPC_MESSAGE_HANDLER(AutomationMsg_BrowserForWindow, GetBrowserForWindow)
#if defined(OS_WIN)
IPC_MESSAGE_HANDLER(AutomationMsg_CreateExternalTab, CreateExternalTab)
#endif
IPC_MESSAGE_HANDLER(AutomationMsg_NavigateInExternalTab,
NavigateInExternalTab)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_ShowInterstitialPage,
ShowInterstitialPage)
IPC_MESSAGE_HANDLER(AutomationMsg_HideInterstitialPage,
HideInterstitialPage)
#if defined(OS_WIN)
IPC_MESSAGE_HANDLER(AutomationMsg_SetAcceleratorsForTab,
SetAcceleratorsForTab)
IPC_MESSAGE_HANDLER(AutomationMsg_ProcessUnhandledAccelerator,
ProcessUnhandledAccelerator)
#endif
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WaitForTabToBeRestored,
WaitForTabToBeRestored)
IPC_MESSAGE_HANDLER(AutomationMsg_SetInitialFocus, SetInitialFocus)
#if defined(OS_WIN)
IPC_MESSAGE_HANDLER(AutomationMsg_TabReposition, OnTabReposition)
IPC_MESSAGE_HANDLER(AutomationMsg_ForwardContextMenuCommandToChrome,
OnForwardContextMenuCommandToChrome)
#endif
IPC_MESSAGE_HANDLER(AutomationMsg_GetSecurityState, GetSecurityState)
IPC_MESSAGE_HANDLER(AutomationMsg_GetPageType, GetPageType)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_ActionOnSSLBlockingPage,
ActionOnSSLBlockingPage)
IPC_MESSAGE_HANDLER(AutomationMsg_BringBrowserToFront, BringBrowserToFront)
IPC_MESSAGE_HANDLER(AutomationMsg_IsPageMenuCommandEnabled,
IsPageMenuCommandEnabled)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_PrintNow, PrintNow)
IPC_MESSAGE_HANDLER(AutomationMsg_SavePage, SavePage)
IPC_MESSAGE_HANDLER(AutomationMsg_AutocompleteEditGetText,
GetAutocompleteEditText)
IPC_MESSAGE_HANDLER(AutomationMsg_AutocompleteEditSetText,
SetAutocompleteEditText)
IPC_MESSAGE_HANDLER(AutomationMsg_AutocompleteEditIsQueryInProgress,
AutocompleteEditIsQueryInProgress)
IPC_MESSAGE_HANDLER(AutomationMsg_AutocompleteEditGetMatches,
AutocompleteEditGetMatches)
IPC_MESSAGE_HANDLER(AutomationMsg_OpenFindInPage,
HandleOpenFindInPageRequest)
IPC_MESSAGE_HANDLER(AutomationMsg_HandleMessageFromExternalHost,
OnMessageFromExternalHost)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_Find, HandleFindRequest)
IPC_MESSAGE_HANDLER(AutomationMsg_FindWindowVisibility,
GetFindWindowVisibility)
IPC_MESSAGE_HANDLER(AutomationMsg_FindWindowLocation,
HandleFindWindowLocationRequest)
IPC_MESSAGE_HANDLER(AutomationMsg_BookmarkBarVisibility,
GetBookmarkBarVisibility)
IPC_MESSAGE_HANDLER(AutomationMsg_GetSSLInfoBarCount, GetSSLInfoBarCount)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_ClickSSLInfoBarLink,
ClickSSLInfoBarLink)
IPC_MESSAGE_HANDLER(AutomationMsg_GetLastNavigationTime,
GetLastNavigationTime)
IPC_MESSAGE_HANDLER_DELAY_REPLY(AutomationMsg_WaitForNavigation,
WaitForNavigation)
IPC_MESSAGE_HANDLER(AutomationMsg_SetIntPreference, SetIntPreference)
IPC_MESSAGE_HANDLER(AutomationMsg_ShowingAppModalDialog,
GetShowingAppModalDialog)
IPC_MESSAGE_HANDLER(AutomationMsg_ClickAppModalDialogButton,
ClickAppModalDialogButton)
IPC_MESSAGE_HANDLER(AutomationMsg_SetStringPreference, SetStringPreference)
IPC_MESSAGE_HANDLER(AutomationMsg_GetBooleanPreference,
GetBooleanPreference)
IPC_MESSAGE_HANDLER(AutomationMsg_SetBooleanPreference,
SetBooleanPreference)
IPC_MESSAGE_HANDLER(AutomationMsg_GetPageCurrentEncoding,
GetPageCurrentEncoding)
IPC_MESSAGE_HANDLER(AutomationMsg_OverrideEncoding, OverrideEncoding)
IPC_MESSAGE_HANDLER(AutomationMsg_SavePackageShouldPromptUser,
SavePackageShouldPromptUser)
IPC_MESSAGE_HANDLER(AutomationMsg_WindowTitle, GetWindowTitle)
IPC_MESSAGE_HANDLER(AutomationMsg_SetEnableExtensionAutomation,
SetEnableExtensionAutomation)
IPC_MESSAGE_HANDLER(AutomationMsg_SetShelfVisibility, SetShelfVisibility)
IPC_MESSAGE_HANDLER(AutomationMsg_BlockedPopupCount, GetBlockedPopupCount)
IPC_END_MESSAGE_MAP()
}
void AutomationProvider::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_count()) {
browser->SelectTabContentsAt(at_index, true);
*status = 0;
}
}
}
void AutomationProvider::AppendTab(int handle, const GURL& url,
IPC::Message* reply_message) {
int append_tab_response = -1; // -1 is the error code
NotificationObserver* observer = NULL;
if (browser_tracker_->ContainsHandle(handle)) {
Browser* browser = browser_tracker_->GetResource(handle);
observer = AddTabStripObserver(browser, reply_message);
TabContents* tab_contents = browser->AddTabWithURL(url, GURL(),
PageTransition::TYPED,
true, -1, false, NULL);
if (tab_contents) {
append_tab_response =
GetIndexForNavigationController(&tab_contents->controller(), browser);
}
}
if (append_tab_response < 0) {
// The append tab failed. Remove the TabStripObserver
if (observer) {
RemoveTabStripObserver(observer);
delete observer;
}
AutomationMsg_AppendTab::WriteReplyParams(reply_message,
append_tab_response);
Send(reply_message);
}
}
void AutomationProvider::NavigateToURL(int handle, const GURL& url,
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) {
AddNavigationStatusListener<AutomationMsg_NavigationResponseValues>(
tab, reply_message, AUTOMATION_MSG_NAVIGATION_SUCCESS,
AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED,
AUTOMATION_MSG_NAVIGATION_ERROR);
// TODO(darin): avoid conversion to GURL
browser->OpenURL(url, GURL(), CURRENT_TAB, PageTransition::TYPED);
return;
}
}
AutomationMsg_NavigateToURL::WriteReplyParams(
reply_message, AUTOMATION_MSG_NAVIGATION_ERROR);
Send(reply_message);
}
void AutomationProvider::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.
browser->OpenURL(url, GURL(), CURRENT_TAB, PageTransition::TYPED);
*status = true;
}
}
}
void AutomationProvider::GoBack(int handle, IPC::Message* reply_message) {
if (tab_tracker_->ContainsHandle(handle)) {
NavigationController* tab = tab_tracker_->GetResource(handle);
Browser* browser = FindAndActivateTab(tab);
if (browser && browser->command_updater()->IsCommandEnabled(IDC_BACK)) {
AddNavigationStatusListener<AutomationMsg_NavigationResponseValues>(
tab, reply_message, AUTOMATION_MSG_NAVIGATION_SUCCESS,
AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED,
AUTOMATION_MSG_NAVIGATION_ERROR);
browser->GoBack(CURRENT_TAB);
return;
}
}
AutomationMsg_GoBack::WriteReplyParams(
reply_message, AUTOMATION_MSG_NAVIGATION_ERROR);
Send(reply_message);
}
void AutomationProvider::GoForward(int handle, IPC::Message* reply_message) {
if (tab_tracker_->ContainsHandle(handle)) {
NavigationController* tab = tab_tracker_->GetResource(handle);
Browser* browser = FindAndActivateTab(tab);
if (browser && browser->command_updater()->IsCommandEnabled(IDC_FORWARD)) {
AddNavigationStatusListener<AutomationMsg_NavigationResponseValues>(
tab, reply_message, AUTOMATION_MSG_NAVIGATION_SUCCESS,
AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED,
AUTOMATION_MSG_NAVIGATION_ERROR);
browser->GoForward(CURRENT_TAB);
return;
}
}
AutomationMsg_GoForward::WriteReplyParams(
reply_message, AUTOMATION_MSG_NAVIGATION_ERROR);
Send(reply_message);
}
void AutomationProvider::Reload(int handle, IPC::Message* reply_message) {
if (tab_tracker_->ContainsHandle(handle)) {
NavigationController* tab = tab_tracker_->GetResource(handle);
Browser* browser = FindAndActivateTab(tab);
if (browser && browser->command_updater()->IsCommandEnabled(IDC_RELOAD)) {
AddNavigationStatusListener<AutomationMsg_NavigationResponseValues>(
tab, reply_message, AUTOMATION_MSG_NAVIGATION_SUCCESS,
AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED,
AUTOMATION_MSG_NAVIGATION_ERROR);
browser->Reload();
return;
}
}
AutomationMsg_Reload::WriteReplyParams(
reply_message, AUTOMATION_MSG_NAVIGATION_ERROR);
Send(reply_message);
}
void AutomationProvider::SetAuth(int tab_handle,
const std::wstring& username,
const std::wstring& password,
IPC::Message* reply_message) {
int status = -1;
if (tab_tracker_->ContainsHandle(tab_handle)) {
NavigationController* tab = tab_tracker_->GetResource(tab_handle);
LoginHandlerMap::iterator iter = login_handler_map_.find(tab);
if (iter != login_handler_map_.end()) {
// If auth is needed again after this, assume login has failed. This is
// not strictly correct, because a navigation can require both proxy and
// server auth, but it should be OK for now.
LoginHandler* handler = iter->second;
AddNavigationStatusListener<int>(tab, reply_message, 0, -1, -1);
handler->SetAuth(username, password);
status = 0;
}
}
if (status < 0) {
AutomationMsg_SetAuth::WriteReplyParams(reply_message, status);
Send(reply_message);
}
}
void AutomationProvider::CancelAuth(int tab_handle,
IPC::Message* reply_message) {
int status = -1;
if (tab_tracker_->ContainsHandle(tab_handle)) {
NavigationController* tab = tab_tracker_->GetResource(tab_handle);
LoginHandlerMap::iterator iter = login_handler_map_.find(tab);
if (iter != login_handler_map_.end()) {
// If auth is needed again after this, something is screwy.
LoginHandler* handler = iter->second;
AddNavigationStatusListener<int>(tab, reply_message, 0, -1, -1);
handler->CancelAuth();
status = 0;
}
}
if (status < 0) {
AutomationMsg_CancelAuth::WriteReplyParams(reply_message, status);
Send(reply_message);
}
}
void AutomationProvider::NeedsAuth(int tab_handle, bool* needs_auth) {
*needs_auth = false;
if (tab_tracker_->ContainsHandle(tab_handle)) {
NavigationController* tab = tab_tracker_->GetResource(tab_handle);
LoginHandlerMap::iterator iter = login_handler_map_.find(tab);
if (iter != login_handler_map_.end()) {
// The LoginHandler will be in our map IFF the tab needs auth.
*needs_auth = true;
}
}
}
void AutomationProvider::GetRedirectsFrom(int tab_handle,
const GURL& source_url,
IPC::Message* reply_message) {
DCHECK(!redirect_query_) << "Can only handle one redirect query at once.";
if (tab_tracker_->ContainsHandle(tab_handle)) {
NavigationController* tab = tab_tracker_->GetResource(tab_handle);
HistoryService* history_service =
tab->profile()->GetHistoryService(Profile::EXPLICIT_ACCESS);
DCHECK(history_service) << "Tab " << tab_handle << "'s profile " <<
"has no history service";
if (history_service) {
DCHECK(reply_message_ == NULL);
reply_message_ = reply_message;
// Schedule a history query for redirects. The response will be sent
// asynchronously from the callback the history system uses to notify us
// that it's done: OnRedirectQueryComplete.
redirect_query_ = history_service->QueryRedirectsFrom(
source_url, &consumer_,
NewCallback(this, &AutomationProvider::OnRedirectQueryComplete));
return; // Response will be sent when query completes.
}
}
// Send failure response.
std::vector<GURL> empty;
AutomationMsg_RedirectsFrom::WriteReplyParams(reply_message, false, empty);
Send(reply_message);
}
void AutomationProvider::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->selected_index();
}
}
void AutomationProvider::GetBrowserLocale(string16* locale) {
DCHECK(g_browser_process);
*locale = ASCIIToUTF16(g_browser_process->GetApplicationLocale());
}
void AutomationProvider::GetBrowserWindowCount(int* window_count) {
*window_count = static_cast<int>(BrowserList::size());
}
void AutomationProvider::GetNormalBrowserWindowCount(int* window_count) {
*window_count = static_cast<int>(
BrowserList::GetBrowserCountForType(profile_, Browser::TYPE_NORMAL));
}
void AutomationProvider::GetShowingAppModalDialog(bool* showing_dialog,
int* dialog_button) {
AppModalDialog* dialog_delegate =
Singleton<AppModalDialogQueue>()->active_dialog();
*showing_dialog = (dialog_delegate != NULL);
if (*showing_dialog)
*dialog_button = dialog_delegate->GetDialogButtons();
else
*dialog_button = MessageBoxFlags::DIALOGBUTTON_NONE;
}
void AutomationProvider::ClickAppModalDialogButton(int button, bool* success) {
*success = false;
AppModalDialog* dialog_delegate =
Singleton<AppModalDialogQueue>()->active_dialog();
if (dialog_delegate &&
(dialog_delegate->GetDialogButtons() & button) == button) {
if ((button & MessageBoxFlags::DIALOGBUTTON_OK) ==
MessageBoxFlags::DIALOGBUTTON_OK) {
dialog_delegate->AcceptWindow();
*success = true;
}
if ((button & MessageBoxFlags::DIALOGBUTTON_CANCEL) ==
MessageBoxFlags::DIALOGBUTTON_CANCEL) {
DCHECK(!*success) << "invalid param, OK and CANCEL specified";
dialog_delegate->CancelWindow();
*success = true;
}
}
}
void AutomationProvider::GetBrowserWindow(int index, int* handle) {
*handle = 0;
if (index >= 0) {
BrowserList::const_iterator iter = BrowserList::begin();
for (; (iter != BrowserList::end()) && (index > 0); ++iter, --index);
if (iter != BrowserList::end()) {
*handle = browser_tracker_->Add(*iter);
}
}
}
void AutomationProvider::FindNormalBrowserWindow(int* handle) {
*handle = 0;
Browser* browser = BrowserList::FindBrowserWithType(profile_,
Browser::TYPE_NORMAL);
if (browser)
*handle = browser_tracker_->Add(browser);
}
void AutomationProvider::GetLastActiveBrowserWindow(int* handle) {
*handle = 0;
Browser* browser = BrowserList::GetLastActive();
if (browser)
*handle = browser_tracker_->Add(browser);
}
#if defined(OS_WIN)
// TODO(port): Remove windowsisms.
BOOL CALLBACK EnumThreadWndProc(HWND hwnd, LPARAM l_param) {
if (hwnd == reinterpret_cast<HWND>(l_param)) {
return FALSE;
}
return TRUE;
}
void AutomationProvider::GetActiveWindow(int* handle) {
HWND window = GetForegroundWindow();
// Let's make sure this window belongs to our process.
if (EnumThreadWindows(::GetCurrentThreadId(),
EnumThreadWndProc,
reinterpret_cast<LPARAM>(window))) {
// We enumerated all the windows and did not find the foreground window,
// it is not our window, ignore it.
*handle = 0;
return;
}
*handle = window_tracker_->Add(window);
}
void AutomationProvider::GetWindowHWND(int handle, HWND* win32_handle) {
*win32_handle = window_tracker_->GetResource(handle);
}
#endif // defined(OS_WIN)
void AutomationProvider::ExecuteBrowserCommandAsync(int handle, int command,
bool* success) {
*success = false;
if (browser_tracker_->ContainsHandle(handle)) {
Browser* browser = browser_tracker_->GetResource(handle);
if (browser->command_updater()->SupportsCommand(command) &&
browser->command_updater()->IsCommandEnabled(command)) {
browser->ExecuteCommand(command);
*success = true;
}
}
}
void AutomationProvider::ExecuteBrowserCommand(
int handle, int command, IPC::Message* reply_message) {
if (browser_tracker_->ContainsHandle(handle)) {
Browser* browser = browser_tracker_->GetResource(handle);
if (browser->command_updater()->SupportsCommand(command) &&
browser->command_updater()->IsCommandEnabled(command)) {
if (ExecuteBrowserCommandObserver::CreateAndRegisterObserver(
this, browser, command, reply_message)) {
browser->ExecuteCommand(command);
return;
}
}
}
AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message, false);
Send(reply_message);
}
void AutomationProvider::WindowGetViewBounds(int handle, int view_id,
bool screen_coordinates,
bool* success,
gfx::Rect* bounds) {
*success = false;
#if defined(OS_WIN)
void* iter = NULL;
if (window_tracker_->ContainsHandle(handle)) {
HWND hwnd = window_tracker_->GetResource(handle);
views::RootView* root_view = views::WidgetWin::FindRootView(hwnd);
if (root_view) {
views::View* view = root_view->GetViewByID(view_id);
if (view) {
*success = true;
gfx::Point point;
if (screen_coordinates)
views::View::ConvertPointToScreen(view, &point);
else
views::View::ConvertPointToView(view, root_view, &point);
*bounds = view->GetLocalBounds(false);
bounds->set_origin(point);
}
}
}
#else
// TODO(port): Enable when window_tracker is ported.
NOTIMPLEMENTED();
#endif
}
#if defined(OS_WIN)
// TODO(port): Use portable replacement for POINT.
// This task enqueues a mouse event on the event loop, so that the view
// that it's being sent to can do the requisite post-processing.
class MouseEventTask : public Task {
public:
MouseEventTask(views::View* view,
views::Event::EventType type,
POINT point,
int flags)
: view_(view), type_(type), point_(point), flags_(flags) {}
virtual ~MouseEventTask() {}
virtual void Run() {
views::MouseEvent event(type_, point_.x, point_.y, flags_);
// We need to set the cursor position before we process the event because
// some code (tab dragging, for instance) queries the actual cursor location
// rather than the location of the mouse event. Note that the reason why
// the drag code moved away from using mouse event locations was because
// our conversion to screen location doesn't work well with multiple
// monitors, so this only works reliably in a single monitor setup.
gfx::Point screen_location(point_.x, point_.y);
view_->ConvertPointToScreen(view_, &screen_location);
::SetCursorPos(screen_location.x(), screen_location.y());
switch (type_) {
case views::Event::ET_MOUSE_PRESSED:
view_->OnMousePressed(event);
break;
case views::Event::ET_MOUSE_DRAGGED:
view_->OnMouseDragged(event);
break;
case views::Event::ET_MOUSE_RELEASED:
view_->OnMouseReleased(event, false);
break;
default:
NOTREACHED();
}
}
private:
views::View* view_;
views::Event::EventType type_;
POINT point_;
int flags_;
DISALLOW_COPY_AND_ASSIGN(MouseEventTask);
};
void AutomationProvider::ScheduleMouseEvent(views::View* view,
views::Event::EventType type,
POINT point,
int flags) {
MessageLoop::current()->PostTask(FROM_HERE,
new MouseEventTask(view, type, point, flags));
}
#endif // defined(OS_WIN)
// This task just adds another task to the event queue. This is useful if
// you want to ensure that any tasks added to the event queue after this one
// have already been processed by the time |task| is run.
class InvokeTaskLaterTask : public Task {
public:
explicit InvokeTaskLaterTask(Task* task) : task_(task) {}
virtual ~InvokeTaskLaterTask() {}
virtual void Run() {
MessageLoop::current()->PostTask(FROM_HERE, task_);
}
private:
Task* task_;
DISALLOW_COPY_AND_ASSIGN(InvokeTaskLaterTask);
};
#if defined(OS_WIN)
// TODO(port): Replace POINT and other windowsisms.
// This task sends a WindowDragResponse message with the appropriate
// routing ID to the automation proxy. This is implemented as a task so that
// we know that the mouse events (and any tasks that they spawn on the message
// loop) have been processed by the time this is sent.
class WindowDragResponseTask : public Task {
public:
WindowDragResponseTask(AutomationProvider* provider,
IPC::Message* reply_message)
: provider_(provider), reply_message_(reply_message) {}
virtual ~WindowDragResponseTask() {}
virtual void Run() {
DCHECK(reply_message_ != NULL);
AutomationMsg_WindowDrag::WriteReplyParams(reply_message_, true);
provider_->Send(reply_message_);
}
private:
AutomationProvider* provider_;
IPC::Message* reply_message_;
DISALLOW_COPY_AND_ASSIGN(WindowDragResponseTask);
};
void AutomationProvider::WindowSimulateClick(const IPC::Message& message,
int handle,
POINT click,
int flags) {
HWND hwnd = 0;
if (window_tracker_->ContainsHandle(handle)) {
hwnd = window_tracker_->GetResource(handle);
ui_controls::SendMouseMove(click.x, click.y);
ui_controls::MouseButton button = ui_controls::LEFT;
if ((flags & views::Event::EF_LEFT_BUTTON_DOWN) ==
views::Event::EF_LEFT_BUTTON_DOWN) {
button = ui_controls::LEFT;
} else if ((flags & views::Event::EF_RIGHT_BUTTON_DOWN) ==
views::Event::EF_RIGHT_BUTTON_DOWN) {
button = ui_controls::RIGHT;
} else if ((flags & views::Event::EF_MIDDLE_BUTTON_DOWN) ==
views::Event::EF_MIDDLE_BUTTON_DOWN) {
button = ui_controls::MIDDLE;
} else {
NOTREACHED();
}
ui_controls::SendMouseClick(button);
}
}
void AutomationProvider::WindowSimulateDrag(int handle,
std::vector<POINT> drag_path,
int flags,
bool press_escape_en_route,
IPC::Message* reply_message) {
bool succeeded = false;
if (browser_tracker_->ContainsHandle(handle) && (drag_path.size() > 1)) {
succeeded = true;
UINT down_message = 0;
UINT up_message = 0;
WPARAM wparam_flags = 0;
if (flags & views::Event::EF_SHIFT_DOWN)
wparam_flags |= MK_SHIFT;
if (flags & views::Event::EF_CONTROL_DOWN)
wparam_flags |= MK_CONTROL;
if (flags & views::Event::EF_LEFT_BUTTON_DOWN) {
wparam_flags |= MK_LBUTTON;
down_message = WM_LBUTTONDOWN;
up_message = WM_LBUTTONUP;
}
if (flags & views::Event::EF_MIDDLE_BUTTON_DOWN) {
wparam_flags |= MK_MBUTTON;
down_message = WM_MBUTTONDOWN;
up_message = WM_MBUTTONUP;
}
if (flags & views::Event::EF_RIGHT_BUTTON_DOWN) {
wparam_flags |= MK_RBUTTON;
down_message = WM_LBUTTONDOWN;
up_message = WM_LBUTTONUP;
}
Browser* browser = browser_tracker_->GetResource(handle);
DCHECK(browser);
HWND top_level_hwnd =
reinterpret_cast<HWND>(browser->window()->GetNativeHandle());
POINT temp = drag_path[0];
MapWindowPoints(top_level_hwnd, HWND_DESKTOP, &temp, 1);
SetCursorPos(temp.x, temp.y);
SendMessage(top_level_hwnd, down_message, wparam_flags,
MAKELPARAM(drag_path[0].x, drag_path[0].y));
for (int i = 1; i < static_cast<int>(drag_path.size()); ++i) {
temp = drag_path[i];
MapWindowPoints(top_level_hwnd, HWND_DESKTOP, &temp, 1);
SetCursorPos(temp.x, temp.y);
SendMessage(top_level_hwnd, WM_MOUSEMOVE, wparam_flags,
MAKELPARAM(drag_path[i].x, drag_path[i].y));
}
POINT end = drag_path[drag_path.size() - 1];
MapWindowPoints(top_level_hwnd, HWND_DESKTOP, &end, 1);
SetCursorPos(end.x, end.y);
if (press_escape_en_route) {
// Press Escape.
ui_controls::SendKeyPress(VK_ESCAPE,
((flags & views::Event::EF_CONTROL_DOWN)
== views::Event::EF_CONTROL_DOWN),
((flags & views::Event::EF_SHIFT_DOWN) ==
views::Event::EF_SHIFT_DOWN),
((flags & views::Event::EF_ALT_DOWN) ==
views::Event::EF_ALT_DOWN));
}
SendMessage(top_level_hwnd, up_message, wparam_flags,
MAKELPARAM(end.x, end.y));
MessageLoop::current()->PostTask(FROM_HERE, new InvokeTaskLaterTask(
new WindowDragResponseTask(this, reply_message)));
} else {
AutomationMsg_WindowDrag::WriteReplyParams(reply_message, true);
Send(reply_message);
}
}
void AutomationProvider::WindowSimulateKeyPress(const IPC::Message& message,
int handle,
wchar_t key,
int flags) {
if (!window_tracker_->ContainsHandle(handle))
return;
// The key event is sent to whatever window is active.
ui_controls::SendKeyPress(key,
((flags & views::Event::EF_CONTROL_DOWN) ==
views::Event::EF_CONTROL_DOWN),
((flags & views::Event::EF_SHIFT_DOWN) ==
views::Event::EF_SHIFT_DOWN),
((flags & views::Event::EF_ALT_DOWN) ==
views::Event::EF_ALT_DOWN));
}
void AutomationProvider::GetFocusedViewID(int handle, int* view_id) {
*view_id = -1;
if (window_tracker_->ContainsHandle(handle)) {
HWND hwnd = window_tracker_->GetResource(handle);
views::FocusManager* focus_manager =
views::FocusManager::GetFocusManagerForNativeView(hwnd);
DCHECK(focus_manager);
views::View* focused_view = focus_manager->GetFocusedView();
if (focused_view)
*view_id = focused_view->GetID();
}
}
void AutomationProvider::SetWindowBounds(int handle, const gfx::Rect& bounds,
bool* success) {
*success = false;
if (window_tracker_->ContainsHandle(handle)) {
HWND hwnd = window_tracker_->GetResource(handle);
if (::MoveWindow(hwnd, bounds.x(), bounds.y(), bounds.width(),
bounds.height(), true)) {
*success = true;
}
}
}
void AutomationProvider::SetWindowVisible(int handle, bool visible,
bool* result) {
if (window_tracker_->ContainsHandle(handle)) {
HWND hwnd = window_tracker_->GetResource(handle);
::ShowWindow(hwnd, visible ? SW_SHOW : SW_HIDE);
*result = true;
} else {
*result = false;
}
}
#endif // defined(OS_WIN)
void AutomationProvider::IsWindowActive(int handle, bool* success,
bool* is_active) {
if (window_tracker_->ContainsHandle(handle)) {
*is_active =
platform_util::IsWindowActive(window_tracker_->GetResource(handle));
*success = true;
} else {
*success = false;
*is_active = false;
}
}
// TODO(port): port this.
#if defined(OS_WIN)
void AutomationProvider::ActivateWindow(int handle) {
if (window_tracker_->ContainsHandle(handle)) {
::SetActiveWindow(window_tracker_->GetResource(handle));
}
}
#endif
void AutomationProvider::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_count();
}
}
void AutomationProvider::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_count()) {
TabContents* tab_contents =
browser->GetTabContentsAt(tab_index);
*tab_handle = tab_tracker_->Add(&tab_contents->controller());
}
}
}
void AutomationProvider::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->title());
} else {
*title = std::wstring();
}
*title_string_size = static_cast<int>(title->size());
}
}
void AutomationProvider::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 = Browser::GetBrowserForController(tab, NULL);
*tabstrip_index = browser->tabstrip_model()->GetIndexOfController(tab);
}
}
void AutomationProvider::HandleUnused(const IPC::Message& message, int handle) {
if (window_tracker_->ContainsHandle(handle)) {
window_tracker_->Remove(window_tracker_->GetResource(handle));
}
}
void AutomationProvider::OnChannelError() {
LOG(ERROR) << "AutomationProxy went away, shutting down app.";
AutomationProviderList::GetInstance()->RemoveProvider(this);
}
// TODO(brettw) change this to accept GURLs when history supports it
void AutomationProvider::OnRedirectQueryComplete(
HistoryService::Handle request_handle,
GURL from_url,
bool success,
history::RedirectList* redirects) {
DCHECK(request_handle == redirect_query_);
DCHECK(reply_message_ != NULL);
std::vector<GURL> redirects_gurl;
if (success) {
reply_message_->WriteBool(true);
for (size_t i = 0; i < redirects->size(); i++)
redirects_gurl.push_back(redirects->at(i));
} else {
reply_message_->WriteInt(-1); // Negative count indicates failure.
}
IPC::ParamTraits<std::vector<GURL> >::Write(reply_message_, redirects_gurl);
Send(reply_message_);
redirect_query_ = NULL;
reply_message_ = NULL;
}
bool AutomationProvider::Send(IPC::Message* msg) {
DCHECK(channel_.get());
return channel_->Send(msg);
}
Browser* AutomationProvider::FindAndActivateTab(
NavigationController* controller) {
int tab_index;
Browser* browser = Browser::GetBrowserForController(controller, &tab_index);
if (browser)
browser->SelectTabContentsAt(tab_index, true);
return browser;
}
void AutomationProvider::GetCookies(const GURL& url, int handle,
int* value_size,
std::string* value) {
*value_size = -1;
if (url.is_valid() && tab_tracker_->ContainsHandle(handle)) {
NavigationController* tab = tab_tracker_->GetResource(handle);
*value =
tab->profile()->GetRequestContext()->cookie_store()->GetCookies(url);
*value_size = static_cast<int>(value->size());
}
}
void AutomationProvider::SetCookie(const GURL& url,
const std::string value,
int handle,
int* response_value) {
*response_value = -1;
if (url.is_valid() && tab_tracker_->ContainsHandle(handle)) {
NavigationController* tab = tab_tracker_->GetResource(handle);
URLRequestContext* context = tab->profile()->GetRequestContext();
if (context->cookie_store()->SetCookie(url, value))
*response_value = 1;
}
}
void AutomationProvider::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()->display_url();
*success = true;
}
}
#if defined(OS_WIN)
void AutomationProvider::GetTabHWND(int handle, HWND* tab_hwnd) {
*tab_hwnd = NULL;
if (tab_tracker_->ContainsHandle(handle)) {
NavigationController* tab = tab_tracker_->GetResource(handle);
*tab_hwnd = tab->tab_contents()->GetNativeView();
}
}
#endif // defined(OS_WIN)
void AutomationProvider::GetTabProcessID(int handle, int* process_id) {
*process_id = -1;
if (tab_tracker_->ContainsHandle(handle)) {
*process_id = 0;
TabContents* tab_contents =
tab_tracker_->GetResource(handle)->tab_contents();
if (tab_contents->process())
*process_id = tab_contents->process()->process().pid();
}
}
void AutomationProvider::ApplyAccelerator(int handle, int id) {
NOTREACHED() << "This function has been deprecated. "
<< "Please use ExecuteBrowserCommandAsync instead.";
}
void AutomationProvider::ExecuteJavascript(int handle,
const std::wstring& frame_xpath,
const std::wstring& script,
IPC::Message* reply_message) {
bool succeeded = false;
TabContents* tab_contents = GetTabContentsForHandle(handle, NULL);
if (tab_contents) {
// 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.
std::wstring set_automation_id;
SStringPrintf(&set_automation_id,
L"window.domAutomationController.setAutomationId(%d);",
reply_message->routing_id());
DCHECK(reply_message_ == NULL);
reply_message_ = reply_message;
tab_contents->render_view_host()->ExecuteJavascriptInWebFrame(
frame_xpath, set_automation_id);
tab_contents->render_view_host()->ExecuteJavascriptInWebFrame(
frame_xpath, script);
succeeded = true;
}
if (!succeeded) {
AutomationMsg_DomOperation::WriteReplyParams(reply_message, std::string());
Send(reply_message);
}
}
void AutomationProvider::GetShelfVisibility(int handle, bool* visible) {
*visible = false;
if (browser_tracker_->ContainsHandle(handle)) {
Browser* browser = browser_tracker_->GetResource(handle);
if (browser) {
*visible = browser->window()->IsDownloadShelfVisible();
}
}
}
void AutomationProvider::SetShelfVisibility(int handle, bool visible) {
if (browser_tracker_->ContainsHandle(handle)) {
Browser* browser = browser_tracker_->GetResource(handle);
if (browser) {
if (visible)
browser->window()->GetDownloadShelf()->Show();
else
browser->window()->GetDownloadShelf()->Close();
}
}
}
void AutomationProvider::GetConstrainedWindowCount(int handle, int* count) {
*count = -1; // -1 is the error code
if (tab_tracker_->ContainsHandle(handle)) {
NavigationController* nav_controller = tab_tracker_->GetResource(handle);
TabContents* tab_contents = nav_controller->tab_contents();
if (tab_contents) {
*count = static_cast<int>(tab_contents->child_windows_.size());
}
}
}
void AutomationProvider::HandleFindInPageRequest(
int handle, const std::wstring& find_request,
int forward, int match_case, int* active_ordinal, int* matches_found) {
NOTREACHED() << "This function has been deprecated."
<< "Please use HandleFindRequest instead.";
*matches_found = -1;
return;
}
void AutomationProvider::HandleFindRequest(
int handle,
const AutomationMsg_Find_Params& params,
IPC::Message* reply_message) {
if (!tab_tracker_->ContainsHandle(handle)) {
AutomationMsg_FindInPage::WriteReplyParams(reply_message, -1, -1);
Send(reply_message);
return;
}
NavigationController* nav = tab_tracker_->GetResource(handle);
TabContents* tab_contents = nav->tab_contents();
find_in_page_observer_.reset(new
FindInPageNotificationObserver(this, tab_contents, reply_message));
tab_contents->set_current_find_request_id(
FindInPageNotificationObserver::kFindInPageRequestId);
tab_contents->render_view_host()->StartFinding(
FindInPageNotificationObserver::kFindInPageRequestId,
params.search_string, params.forward, params.match_case,
params.find_next);
}
void AutomationProvider::HandleOpenFindInPageRequest(
const IPC::Message& message, int handle) {
if (browser_tracker_->ContainsHandle(handle)) {
Browser* browser = browser_tracker_->GetResource(handle);
browser->FindInPage(false, false);
}
}
void AutomationProvider::GetFindWindowVisibility(int handle, bool* visible) {
gfx::Point position;
*visible = false;
if (browser_tracker_->ContainsHandle(handle)) {
Browser* browser = browser_tracker_->GetResource(handle);
FindBarTesting* find_bar =
browser->find_bar()->find_bar()->GetFindBarTesting();
find_bar->GetFindBarWindowInfo(&position, visible);
}
}
void AutomationProvider::HandleFindWindowLocationRequest(int handle, int* x,
int* y) {
gfx::Point position(0, 0);
bool visible = false;
if (browser_tracker_->ContainsHandle(handle)) {
Browser* browser = browser_tracker_->GetResource(handle);
FindBarTesting* find_bar =
browser->find_bar()->find_bar()->GetFindBarTesting();
find_bar->GetFindBarWindowInfo(&position, &visible);
}
*x = position.x();
*y = position.y();
}
void AutomationProvider::GetBookmarkBarVisibility(int handle, bool* visible,
bool* animating) {
*visible = false;
*animating = false;
#if defined(OS_WIN)
if (browser_tracker_->ContainsHandle(handle)) {
Browser* browser = browser_tracker_->GetResource(handle);
if (browser) {
BrowserWindowTesting* testing =
browser->window()->GetBrowserWindowTesting();
BookmarkBarView* bookmark_bar = testing->GetBookmarkBarView();
if (bookmark_bar) {
*animating = bookmark_bar->IsAnimating();
*visible = browser->window()->IsBookmarkBarVisible();
}
}
}
#else
// TODO(port): Enable when bookmarks ui is ported.
NOTIMPLEMENTED();
#endif
}
void AutomationProvider::HandleInspectElementRequest(
int handle, int x, int y, IPC::Message* reply_message) {
TabContents* tab_contents = GetTabContentsForHandle(handle, NULL);
if (tab_contents) {
DCHECK(reply_message_ == NULL);
reply_message_ = reply_message;
DevToolsManager::GetInstance()->InspectElement(
tab_contents->render_view_host(), x, y);
} else {
AutomationMsg_InspectElement::WriteReplyParams(reply_message, -1);
Send(reply_message);
}
}
void AutomationProvider::ReceivedInspectElementResponse(int num_resources) {
if (reply_message_) {
AutomationMsg_InspectElement::WriteReplyParams(reply_message_,
num_resources);
Send(reply_message_);
reply_message_ = NULL;
}
}
// Helper class for making changes to the URLRequest ProtocolFactory on the
// IO thread.
class SetFilteredInetTask : public Task {
public:
explicit SetFilteredInetTask(bool enabled) : enabled_(enabled) { }
virtual void Run() {
if (enabled_) {
URLRequestFilter::GetInstance()->ClearHandlers();
URLRequestFailedDnsJob::AddUITestUrls();
URLRequestSlowDownloadJob::AddUITestUrls();
std::wstring root_http;
PathService::Get(chrome::DIR_TEST_DATA, &root_http);
URLRequestMockHTTPJob::AddUITestUrls(root_http);
} else {
// Revert to the default handlers.
URLRequestFilter::GetInstance()->ClearHandlers();
}
}
private:
bool enabled_;
};
void AutomationProvider::SetFilteredInet(const IPC::Message& message,
bool enabled) {
// Since this involves changing the URLRequest ProtocolFactory, we want to
// run on the main thread.
g_browser_process->io_thread()->message_loop()->PostTask(FROM_HERE,
new SetFilteredInetTask(enabled));
}
class SetProxyConfigTask : public Task {
public:
explicit SetProxyConfigTask(net::ProxyService* proxy_service,
const std::string& new_proxy_config)
: proxy_service_(proxy_service), proxy_config_(new_proxy_config) {}
virtual void Run() {
// First, deserialize the JSON string. If this fails, log and bail.
JSONStringValueSerializer deserializer(proxy_config_);
std::string error_message;
scoped_ptr<Value> root(deserializer.Deserialize(&error_message));
if (!root.get() || root->GetType() != Value::TYPE_DICTIONARY) {
DLOG(WARNING) << "Received bad JSON string for ProxyConfig: "
<< error_message;
return;
}
scoped_ptr<DictionaryValue> dict(
static_cast<DictionaryValue*>(root.release()));
// Now put together a proxy configuration from the deserialized string.
net::ProxyConfig pc;
PopulateProxyConfig(*dict.get(), &pc);
DCHECK(proxy_service_);
scoped_ptr<net::ProxyConfigService> proxy_config_service(
new net::ProxyConfigServiceFixed(pc));
proxy_service_->ResetConfigService(proxy_config_service.release());
}
void PopulateProxyConfig(const DictionaryValue& dict, net::ProxyConfig* pc) {
DCHECK(pc);
bool no_proxy = false;
if (dict.GetBoolean(automation::kJSONProxyNoProxy, &no_proxy)) {
// Make no changes to the ProxyConfig.
return;
}
bool auto_config;
if (dict.GetBoolean(automation::kJSONProxyAutoconfig, &auto_config)) {
pc->auto_detect = true;
}
std::string pac_url;
if (dict.GetString(automation::kJSONProxyPacUrl, &pac_url)) {
pc->pac_url = GURL(pac_url);
}
std::string proxy_bypass_list;
if (dict.GetString(automation::kJSONProxyBypassList, &proxy_bypass_list)) {
pc->ParseNoProxyList(proxy_bypass_list);
}
std::string proxy_server;
if (dict.GetString(automation::kJSONProxyServer, &proxy_server)) {
pc->proxy_rules.ParseFromString(proxy_server);
}
}
private:
net::ProxyService* proxy_service_;
std::string proxy_config_;
};
void AutomationProvider::SetProxyConfig(const std::string& new_proxy_config) {
URLRequestContext* context = Profile::GetDefaultRequestContext();
// If we don't have a default request context yet then we have to create
// one.
bool run_on_ui_thread = false;
if (!context) {
FilePath user_data_dir;
PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
ProfileManager* profile_manager = g_browser_process->profile_manager();
DCHECK(profile_manager);
Profile* profile = profile_manager->GetDefaultProfile(user_data_dir);
DCHECK(profile);
context = profile->GetRequestContext();
run_on_ui_thread = true;
}
DCHECK(context);
// Every URLRequestContext should have a proxy service.
net::ProxyService* proxy_service = context->proxy_service();
DCHECK(proxy_service);
// If we just now created the URLRequestContext then we can immediately
// set the proxy settings on this (the UI) thread. If there was already
// a URLRequestContext, then run the reset on the IO thread.
if (run_on_ui_thread) {
SetProxyConfigTask set_proxy_config_task(proxy_service, new_proxy_config);
set_proxy_config_task.Run();
} else {
g_browser_process->io_thread()->message_loop()->PostTask(FROM_HERE,
new SetProxyConfigTask(proxy_service, new_proxy_config));
}
}
void AutomationProvider::GetDownloadDirectory(
int handle, std::wstring* download_directory) {
DLOG(INFO) << "Handling download directory request";
if (tab_tracker_->ContainsHandle(handle)) {
NavigationController* tab = tab_tracker_->GetResource(handle);
DownloadManager* dlm = tab->profile()->GetDownloadManager();
DCHECK(dlm);
*download_directory = dlm->download_path().ToWStringHack();
}
}
void AutomationProvider::OpenNewBrowserWindow(bool show,
IPC::Message* reply_message) {
new BrowserOpenedNotificationObserver(this, reply_message);
// 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 = Browser::Create(profile_);
browser->AddBlankTab(true);
if (show)
browser->window()->Show();
}
void AutomationProvider::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()->GetNativeHandle();
// Add() returns the existing handle for the resource if any.
*handle = window_tracker_->Add(win);
*success = true;
}
}
#if defined(OS_WIN) || defined(OS_LINUX)
void AutomationProvider::GetAutocompleteEditForBrowser(
int browser_handle,
bool* success,
int* autocomplete_edit_handle) {
*success = false;
*autocomplete_edit_handle = 0;
if (browser_tracker_->ContainsHandle(browser_handle)) {
Browser* browser = browser_tracker_->GetResource(browser_handle);
LocationBar* loc_bar = browser->window()->GetLocationBar();
AutocompleteEditView* edit_view = loc_bar->location_entry();
// Add() returns the existing handle for the resource if any.
*autocomplete_edit_handle = autocomplete_edit_tracker_->Add(edit_view);
*success = true;
}
}
#endif // defined(OS_WIN) || defined(OS_LINUX)
#if defined(OS_WIN)
// TODO(port): Remove windowsisms.
void AutomationProvider::GetBrowserForWindow(int window_handle,
bool* success,
int* browser_handle) {
*success = false;
*browser_handle = 0;
if (window_tracker_->ContainsHandle(window_handle)) {
HWND window = window_tracker_->GetResource(window_handle);
BrowserList::const_iterator iter = BrowserList::begin();
Browser* browser = NULL;
for (;iter != BrowserList::end(); ++iter) {
HWND hwnd = reinterpret_cast<HWND>((*iter)->window()->GetNativeHandle());
if (window == hwnd) {
browser = *iter;
break;
}
}
if (browser) {
// Add() returns the existing handle for the resource if any.
*browser_handle = browser_tracker_->Add(browser);
*success = true;
}
}
}
#endif // defined(OS_WIN)
void AutomationProvider::ShowInterstitialPage(int tab_handle,
const std::string& html_text,
IPC::Message* reply_message) {
if (tab_tracker_->ContainsHandle(tab_handle)) {
NavigationController* controller = tab_tracker_->GetResource(tab_handle);
TabContents* tab_contents = controller->tab_contents();
AddNavigationStatusListener<bool>(controller, reply_message, true,
false, false);
AutomationInterstitialPage* interstitial =
new AutomationInterstitialPage(tab_contents,
GURL("about:interstitial"),
html_text);
interstitial->Show();
return;
}
AutomationMsg_ShowInterstitialPage::WriteReplyParams(reply_message, false);
Send(reply_message);
}
void AutomationProvider::HideInterstitialPage(int tab_handle,
bool* success) {
*success = false;
TabContents* tab_contents = GetTabContentsForHandle(tab_handle, NULL);
if (tab_contents && tab_contents->interstitial_page()) {
tab_contents->interstitial_page()->DontProceed();
*success = true;
}
}
void AutomationProvider::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);
int index;
Browser* browser = Browser::GetBrowserForController(controller, &index);
DCHECK(browser);
new TabClosedNotificationObserver(this, wait_until_closed, reply_message);
browser->CloseContents(controller->tab_contents());
return;
}
AutomationMsg_CloseTab::WriteReplyParams(reply_message, false);
}
void AutomationProvider::CloseBrowser(int browser_handle,
IPC::Message* reply_message) {
if (browser_tracker_->ContainsHandle(browser_handle)) {
Browser* browser = browser_tracker_->GetResource(browser_handle);
new BrowserClosedNotificationObserver(browser, this,
reply_message);
browser->window()->Close();
} else {
NOTREACHED();
}
}
void AutomationProvider::CloseBrowserAsync(int browser_handle) {
if (browser_tracker_->ContainsHandle(browser_handle)) {
Browser* browser = browser_tracker_->GetResource(browser_handle);
browser->window()->Close();
} else {
NOTREACHED();
}
}
#if defined(OS_WIN)
// TODO(port): Remove windowsisms.
void AutomationProvider::CreateExternalTab(HWND parent,
const gfx::Rect& dimensions,
unsigned int style,
bool incognito,
HWND* tab_container_window,
HWND* tab_window,
int* tab_handle) {
*tab_handle = 0;
*tab_container_window = NULL;
*tab_window = NULL;
ExternalTabContainer *external_tab_container =
new ExternalTabContainer(this);
Profile* profile = incognito? profile_->GetOffTheRecordProfile() : profile_;
external_tab_container->Init(profile, parent, dimensions, style);
TabContents* tab_contents = external_tab_container->tab_contents();
if (tab_contents) {
*tab_handle = tab_tracker_->Add(&tab_contents->controller());
external_tab_container->set_tab_handle(*tab_handle);
*tab_container_window = external_tab_container->GetNativeView();
*tab_window = tab_contents->GetNativeView();
} else {
delete external_tab_container;
}
}
#endif
void AutomationProvider::NavigateInExternalTab(
int handle, const GURL& url,
AutomationMsg_NavigationResponseValues* status) {
*status = AUTOMATION_MSG_NAVIGATION_ERROR;
if (tab_tracker_->ContainsHandle(handle)) {
NavigationController* tab = tab_tracker_->GetResource(handle);
tab->LoadURL(url, GURL(), PageTransition::TYPED);
*status = AUTOMATION_MSG_NAVIGATION_SUCCESS;
}
}
#if defined(OS_WIN)
// TODO(port): remove windowisms.
void AutomationProvider::SetAcceleratorsForTab(int handle,
HACCEL accel_table,
int accel_entry_count,
bool* status) {
*status = false;
ExternalTabContainer* external_tab = GetExternalTabForHandle(handle);
if (external_tab) {
external_tab->SetAccelerators(accel_table, accel_entry_count);
*status = true;
}
}
void AutomationProvider::ProcessUnhandledAccelerator(
const IPC::Message& message, int handle, const MSG& msg) {
ExternalTabContainer* external_tab = GetExternalTabForHandle(handle);
if (external_tab) {
external_tab->ProcessUnhandledAccelerator(msg);
}
// This message expects no response.
}
#endif
void AutomationProvider::WaitForTabToBeRestored(int tab_handle,
IPC::Message* reply_message) {
if (tab_tracker_->ContainsHandle(tab_handle)) {
NavigationController* tab = tab_tracker_->GetResource(tab_handle);
restore_tracker_.reset(
new NavigationControllerRestoredObserver(this, tab, reply_message));
}
}
void AutomationProvider::SetInitialFocus(const IPC::Message& message,
int handle, bool reverse) {
#if defined(OS_WIN)
ExternalTabContainer* external_tab = GetExternalTabForHandle(handle);
if (external_tab) {
external_tab->FocusThroughTabTraversal(reverse);
}
// This message expects no response.
#elif defined(OS_POSIX)
// TODO(port) enable this function.
NOTIMPLEMENTED();
#endif
}
// TODO(port): enable these functions.
#if defined(OS_WIN)
void AutomationProvider::GetSecurityState(int handle, bool* success,
SecurityStyle* security_style,
int* ssl_cert_status,
int* mixed_content_status) {
if (tab_tracker_->ContainsHandle(handle)) {
NavigationController* tab = tab_tracker_->GetResource(handle);
NavigationEntry* entry = tab->GetActiveEntry();
*success = true;
*security_style = entry->ssl().security_style();
*ssl_cert_status = entry->ssl().cert_status();
*mixed_content_status = entry->ssl().content_status();
} else {
*success = false;
*security_style = SECURITY_STYLE_UNKNOWN;
*ssl_cert_status = 0;
*mixed_content_status = 0;
}
}
void AutomationProvider::GetPageType(int handle, bool* success,
NavigationEntry::PageType* page_type) {
if (tab_tracker_->ContainsHandle(handle)) {
NavigationController* tab = tab_tracker_->GetResource(handle);
NavigationEntry* entry = tab->GetActiveEntry();
*page_type = entry->page_type();
*success = true;
// In order to return the proper result when an interstitial is shown and
// no navigation entry were created for it we need to ask the TabContents.
if (*page_type == NavigationEntry::NORMAL_PAGE &&
tab->tab_contents()->showing_interstitial_page())
*page_type = NavigationEntry::INTERSTITIAL_PAGE;
} else {
*success = false;
*page_type = NavigationEntry::NORMAL_PAGE;
}
}
void AutomationProvider::ActionOnSSLBlockingPage(int handle, bool proceed,
IPC::Message* reply_message) {
if (tab_tracker_->ContainsHandle(handle)) {
NavigationController* tab = tab_tracker_->GetResource(handle);
NavigationEntry* entry = tab->GetActiveEntry();
if (entry->page_type() == NavigationEntry::INTERSTITIAL_PAGE) {
TabContents* tab_contents = tab->tab_contents();
InterstitialPage* ssl_blocking_page =
InterstitialPage::GetInterstitialPage(tab_contents);
if (ssl_blocking_page) {
if (proceed) {
AddNavigationStatusListener<bool>(tab, reply_message, true, true,
false);
ssl_blocking_page->Proceed();
return;
}
ssl_blocking_page->DontProceed();
AutomationMsg_ActionOnSSLBlockingPage::WriteReplyParams(reply_message,
true);
Send(reply_message);
return;
}
}
}
// We failed.
AutomationMsg_ActionOnSSLBlockingPage::WriteReplyParams(reply_message,
false);
Send(reply_message);
}
#endif // defined(OS_WIN)
void AutomationProvider::BringBrowserToFront(int browser_handle,
bool* success) {
if (browser_tracker_->ContainsHandle(browser_handle)) {
Browser* browser = browser_tracker_->GetResource(browser_handle);
browser->window()->Activate();
*success = true;
} else {
*success = false;
}
}
void AutomationProvider::IsPageMenuCommandEnabled(int browser_handle,
int message_num,
bool* menu_item_enabled) {
if (browser_tracker_->ContainsHandle(browser_handle)) {
Browser* browser = browser_tracker_->GetResource(browser_handle);
*menu_item_enabled =
browser->command_updater()->IsCommandEnabled(message_num);
} else {
*menu_item_enabled = false;
}
}
#if defined(OS_WIN)
// TODO(port): Enable this.
void AutomationProvider::PrintNow(int tab_handle,
IPC::Message* reply_message) {
NavigationController* tab = NULL;
TabContents* tab_contents = GetTabContentsForHandle(tab_handle, &tab);
if (tab_contents) {
FindAndActivateTab(tab);
notification_observer_list_.AddObserver(
new DocumentPrintedNotificationObserver(this, reply_message));
if (tab_contents->PrintNow())
return;
}
AutomationMsg_PrintNow::WriteReplyParams(reply_message, false);
Send(reply_message);
}
#endif
void AutomationProvider::SavePage(int tab_handle,
const std::wstring& file_name,
const std::wstring& dir_path,
int type,
bool* success) {
if (!tab_tracker_->ContainsHandle(tab_handle)) {
*success = false;
return;
}
NavigationController* nav = tab_tracker_->GetResource(tab_handle);
Browser* browser = FindAndActivateTab(nav);
DCHECK(browser);
if (!browser->command_updater()->IsCommandEnabled(IDC_SAVE_PAGE)) {
*success = false;
return;
}
SavePackage::SavePackageType save_type =
static_cast<SavePackage::SavePackageType>(type);
DCHECK(save_type >= SavePackage::SAVE_AS_ONLY_HTML &&
save_type <= SavePackage::SAVE_AS_COMPLETE_HTML);
nav->tab_contents()->SavePage(file_name, dir_path, save_type);
*success = true;
}
#if defined(OS_WIN) || defined(OS_LINUX)
// TODO(port): Enable these.
void AutomationProvider::GetAutocompleteEditText(int autocomplete_edit_handle,
bool* success,
std::wstring* text) {
*success = false;
if (autocomplete_edit_tracker_->ContainsHandle(autocomplete_edit_handle)) {
*text = autocomplete_edit_tracker_->GetResource(autocomplete_edit_handle)->
GetText();
*success = true;
}
}
void AutomationProvider::SetAutocompleteEditText(int autocomplete_edit_handle,
const std::wstring& text,
bool* success) {
*success = false;
if (autocomplete_edit_tracker_->ContainsHandle(autocomplete_edit_handle)) {
autocomplete_edit_tracker_->GetResource(autocomplete_edit_handle)->
SetUserText(text);
*success = true;
}
}
void AutomationProvider::AutocompleteEditGetMatches(
int autocomplete_edit_handle,
bool* success,
std::vector<AutocompleteMatchData>* matches) {
*success = false;
if (autocomplete_edit_tracker_->ContainsHandle(autocomplete_edit_handle)) {
const AutocompleteResult& result = autocomplete_edit_tracker_->
GetResource(autocomplete_edit_handle)->model()->result();
for (AutocompleteResult::const_iterator i = result.begin();
i != result.end(); ++i)
matches->push_back(AutocompleteMatchData(*i));
*success = true;
}
}
void AutomationProvider::AutocompleteEditIsQueryInProgress(
int autocomplete_edit_handle,
bool* success,
bool* query_in_progress) {
*success = false;
*query_in_progress = false;
if (autocomplete_edit_tracker_->ContainsHandle(autocomplete_edit_handle)) {
*query_in_progress = autocomplete_edit_tracker_->
GetResource(autocomplete_edit_handle)->model()->query_in_progress();
*success = true;
}
}
void AutomationProvider::OnMessageFromExternalHost(int handle,
const std::string& message,
const std::string& origin,
const std::string& target) {
if (tab_tracker_->ContainsHandle(handle)) {
NavigationController* tab = tab_tracker_->GetResource(handle);
if (!tab) {
NOTREACHED();
return;
}
TabContents* tab_contents = tab->tab_contents();
if (!tab_contents) {
NOTREACHED();
return;
}
RenderViewHost* view_host = tab_contents->render_view_host();
if (!view_host) {
return;
}
if (AutomationExtensionFunction::InterceptMessageFromExternalHost(
view_host, message, origin, target)) {
// Message was diverted.
return;
}
if (ExtensionPortContainer::InterceptMessageFromExternalHost(message,
origin, target, this, view_host, handle)) {
// Message was diverted.
return;
}
if (InterceptBrowserEventMessageFromExternalHost(message, origin, target)) {
// Message was diverted.
return;
}
view_host->ForwardMessageFromExternalHost(message, origin, target);
}
}
bool AutomationProvider::InterceptBrowserEventMessageFromExternalHost(
const std::string& message, const std::string& origin,
const std::string& target) {
if (target !=
extension_automation_constants::kAutomationBrowserEventRequestTarget)
return false;
if (origin != extension_automation_constants::kAutomationOrigin) {
LOG(WARNING) << "Wrong origin on automation browser event " << origin;
return false;
}
// The message is a JSON-encoded array with two elements, both strings. The
// first is the name of the event to dispatch. The second is a JSON-encoding
// of the arguments specific to that event.
scoped_ptr<Value> message_value(JSONReader::Read(message, false));
if (!message_value.get() || !message_value->IsType(Value::TYPE_LIST)) {
LOG(WARNING) << "Invalid browser event specified through automation";
return false;
}
const ListValue* args = static_cast<const ListValue*>(message_value.get());
std::string event_name;
if (!args->GetString(0, &event_name)) {
LOG(WARNING) << "No browser event name specified through automation";
return false;
}
std::string json_args;
if (!args->GetString(1, &json_args)) {
LOG(WARNING) << "No browser event args specified through automation";
return false;
}
ExtensionMessageService::GetInstance(profile()->GetRequestContext())->
DispatchEventToRenderers(event_name.c_str(), json_args);
return true;
}
#endif // defined(OS_WIN) || defined(OS_LINUX)
TabContents* AutomationProvider::GetTabContentsForHandle(
int handle, NavigationController** tab) {
if (tab_tracker_->ContainsHandle(handle)) {
NavigationController* nav_controller = tab_tracker_->GetResource(handle);
if (tab)
*tab = nav_controller;
return nav_controller->tab_contents();
}
return NULL;
}
#if defined(OS_WIN)
ExternalTabContainer* AutomationProvider::GetExternalTabForHandle(int handle) {
if (tab_tracker_->ContainsHandle(handle)) {
NavigationController* tab = tab_tracker_->GetResource(handle);
return ExternalTabContainer::GetContainerForTab(
tab->tab_contents()->GetNativeView());
}
return NULL;
}
#endif // defined(OS_WIN)
TestingAutomationProvider::TestingAutomationProvider(Profile* profile)
: AutomationProvider(profile) {
BrowserList::AddObserver(this);
registrar_.Add(this, NotificationType::SESSION_END,
NotificationService::AllSources());
}
TestingAutomationProvider::~TestingAutomationProvider() {
BrowserList::RemoveObserver(this);
}
void TestingAutomationProvider::OnChannelError() {
BrowserList::CloseAllBrowsers(true);
AutomationProvider::OnChannelError();
}
void TestingAutomationProvider::OnBrowserRemoving(const Browser* browser) {
// 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.
if (BrowserList::size() == 1) {
// If you change this, update Observer for NotificationType::SESSION_END
// below.
MessageLoop::current()->PostTask(FROM_HERE,
NewRunnableMethod(this, &TestingAutomationProvider::OnRemoveProvider));
}
}
void TestingAutomationProvider::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
DCHECK(type == NotificationType::SESSION_END);
// OnBrowserRemoving 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 OnBrowserRemoving.
Release();
}
void TestingAutomationProvider::OnRemoveProvider() {
AutomationProviderList::GetInstance()->RemoveProvider(this);
}
void AutomationProvider::GetSSLInfoBarCount(int handle, int* count) {
*count = -1; // -1 means error.
if (tab_tracker_->ContainsHandle(handle)) {
NavigationController* nav_controller = tab_tracker_->GetResource(handle);
if (nav_controller)
*count = nav_controller->tab_contents()->infobar_delegate_count();
}
}
void AutomationProvider::ClickSSLInfoBarLink(int handle,
int info_bar_index,
bool wait_for_navigation,
IPC::Message* reply_message) {
bool success = false;
if (tab_tracker_->ContainsHandle(handle)) {
NavigationController* nav_controller = tab_tracker_->GetResource(handle);
if (nav_controller) {
int count = nav_controller->tab_contents()->infobar_delegate_count();
if (info_bar_index >= 0 && info_bar_index < count) {
if (wait_for_navigation) {
AddNavigationStatusListener<bool>(nav_controller, reply_message,
true, true, false);
}
InfoBarDelegate* delegate =
nav_controller->tab_contents()->GetInfoBarDelegateAt(
info_bar_index);
if (delegate->AsConfirmInfoBarDelegate())
delegate->AsConfirmInfoBarDelegate()->Accept();
success = true;
}
}
}
if (!wait_for_navigation || !success)
AutomationMsg_ClickSSLInfoBarLink::WriteReplyParams(reply_message,
success);
}
void AutomationProvider::GetLastNavigationTime(int handle,
int64* last_navigation_time) {
Time time = tab_tracker_->GetLastNavigationTime(handle);
*last_navigation_time = time.ToInternalValue();
}
void AutomationProvider::WaitForNavigation(int handle,
int64 last_navigation_time,
IPC::Message* reply_message) {
NavigationController* controller = NULL;
if (tab_tracker_->ContainsHandle(handle))
controller = tab_tracker_->GetResource(handle);
Time time = tab_tracker_->GetLastNavigationTime(handle);
if (time.ToInternalValue() > last_navigation_time || !controller) {
AutomationMsg_WaitForNavigation::WriteReplyParams(reply_message,
controller != NULL);
return;
}
AddNavigationStatusListener<bool>(controller, reply_message, true, true,
false);
}
void AutomationProvider::SetIntPreference(int handle,
const std::wstring& name,
int value,
bool* success) {
*success = false;
if (browser_tracker_->ContainsHandle(handle)) {
Browser* browser = browser_tracker_->GetResource(handle);
browser->profile()->GetPrefs()->SetInteger(name.c_str(), value);
*success = true;
}
}
void AutomationProvider::SetStringPreference(int handle,
const std::wstring& name,
const std::wstring& value,
bool* success) {
*success = false;
if (browser_tracker_->ContainsHandle(handle)) {
Browser* browser = browser_tracker_->GetResource(handle);
browser->profile()->GetPrefs()->SetString(name.c_str(), value);
*success = true;
}
}
void AutomationProvider::GetBooleanPreference(int handle,
const std::wstring& name,
bool* success,
bool* value) {
*success = false;
*value = false;
if (browser_tracker_->ContainsHandle(handle)) {
Browser* browser = browser_tracker_->GetResource(handle);
*value = browser->profile()->GetPrefs()->GetBoolean(name.c_str());
*success = true;
}
}
void AutomationProvider::SetBooleanPreference(int handle,
const std::wstring& name,
bool value,
bool* success) {
*success = false;
if (browser_tracker_->ContainsHandle(handle)) {
Browser* browser = browser_tracker_->GetResource(handle);
browser->profile()->GetPrefs()->SetBoolean(name.c_str(), value);
*success = true;
}
}
// Gets the current used encoding name of the page in the specified tab.
void AutomationProvider::GetPageCurrentEncoding(
int tab_handle, std::wstring* current_encoding) {
if (tab_tracker_->ContainsHandle(tab_handle)) {
NavigationController* nav = tab_tracker_->GetResource(tab_handle);
Browser* browser = FindAndActivateTab(nav);
DCHECK(browser);
if (browser->command_updater()->IsCommandEnabled(IDC_ENCODING_MENU))
*current_encoding = nav->tab_contents()->encoding();
}
}
// Gets the current used encoding name of the page in the specified tab.
void AutomationProvider::OverrideEncoding(int tab_handle,
const std::wstring& encoding_name,
bool* success) {
*success = false;
#if defined(OS_WIN)
if (tab_tracker_->ContainsHandle(tab_handle)) {
NavigationController* nav = tab_tracker_->GetResource(tab_handle);
Browser* browser = FindAndActivateTab(nav);
DCHECK(browser);
if (browser->command_updater()->IsCommandEnabled(IDC_ENCODING_MENU)) {
TabContents* tab_contents = nav->tab_contents();
int selected_encoding_id =
CharacterEncoding::GetCommandIdByCanonicalEncodingName(encoding_name);
if (selected_encoding_id) {
browser->OverrideEncoding(selected_encoding_id);
*success = true;
}
}
}
#else
// TODO(port): Enable when encoding-related parts of Browser are ported.
NOTIMPLEMENTED();
#endif
}
void AutomationProvider::SavePackageShouldPromptUser(bool should_prompt) {
SavePackage::SetShouldPromptUser(should_prompt);
}
void AutomationProvider::SetEnableExtensionAutomation(bool automation_enabled) {
AutomationExtensionFunction::SetEnabled(automation_enabled);
}
#if defined(OS_WIN)
// TODO(port): Reposition_Params is win-specific. We'll need to port it.
void AutomationProvider::OnTabReposition(
int tab_handle, const IPC::Reposition_Params& params) {
if (!tab_tracker_->ContainsHandle(tab_handle))
return;
if (!IsWindow(params.window))
return;
unsigned long process_id = 0;
unsigned long thread_id = 0;
thread_id = GetWindowThreadProcessId(params.window, &process_id);
if (thread_id != GetCurrentThreadId()) {
NOTREACHED();
return;
}
SetWindowPos(params.window, params.window_insert_after, params.left,
params.top, params.width, params.height, params.flags);
if (params.set_parent) {
if (IsWindow(params.parent_window)) {
if (!SetParent(params.window, params.parent_window))
DLOG(WARNING) << "SetParent failed. Error 0x%x" << GetLastError();
}
}
}
void AutomationProvider::OnForwardContextMenuCommandToChrome(int tab_handle,
int command) {
if (tab_tracker_->ContainsHandle(tab_handle)) {
NavigationController* tab = tab_tracker_->GetResource(tab_handle);
if (!tab) {
NOTREACHED();
return;
}
TabContents* tab_contents = tab->tab_contents();
if (!tab_contents || !tab_contents->delegate()) {
NOTREACHED();
return;
}
tab_contents->delegate()->ExecuteContextMenuCommand(command);
}
}
#endif // defined(OS_WIN)
void AutomationProvider::GetWindowTitle(int handle, string16* text) {
gfx::NativeWindow window = window_tracker_->GetResource(handle);
text->assign(platform_util::GetWindowTitle(window));
}
void AutomationProvider::GetBlockedPopupCount(int handle, int* count) {
*count = -1; // -1 is the error code
if (tab_tracker_->ContainsHandle(handle)) {
NavigationController* nav_controller = tab_tracker_->GetResource(handle);
TabContents* tab_contents = nav_controller->tab_contents();
if (tab_contents) {
BlockedPopupContainer* container =
tab_contents->blocked_popup_container();
if (container) {
*count = static_cast<int>(container->GetBlockedPopupCount());
} else {
// If we don't have a container, we don't have any blocked popups to
// contain!
*count = 0;
}
}
}
}