diff options
Diffstat (limited to 'chrome/browser/automation/automation_provider.cc')
-rw-r--r-- | chrome/browser/automation/automation_provider.cc | 747 |
1 files changed, 1 insertions, 746 deletions
diff --git a/chrome/browser/automation/automation_provider.cc b/chrome/browser/automation/automation_provider.cc index a3c2c09..93aad4d 100644 --- a/chrome/browser/automation/automation_provider.cc +++ b/chrome/browser/automation/automation_provider.cc @@ -21,6 +21,7 @@ #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/automation_provider_observers.h" #include "chrome/browser/automation/extension_automation_constants.h" #include "chrome/browser/automation/extension_port_container.h" #include "chrome/browser/blocked_popup_container.h" @@ -70,752 +71,6 @@ 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); -}; - -class NavigationNotificationObserver : public NotificationObserver { - public: - NavigationNotificationObserver(NavigationController* controller, - AutomationProvider* automation, - IPC::Message* reply_message, - int number_of_navigations) - : automation_(automation), - reply_message_(reply_message), - controller_(controller), - navigations_remaining_(number_of_navigations), - navigation_started_(false) { - DCHECK_LT(0, navigations_remaining_); - 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<AutomationMsg_NavigationResponseValues>::Write( - reply_message_, AUTOMATION_MSG_NAVIGATION_ERROR); - automation_->Send(reply_message_); - reply_message_ = NULL; - } - - automation_->RemoveNavigationStatusListener(this); - } - - void ConditionMet(AutomationMsg_NavigationResponseValues navigation_result) { - DCHECK(reply_message_ != NULL); - - IPC::ParamTraits<AutomationMsg_NavigationResponseValues>::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; - if (--navigations_remaining_ == 0) - ConditionMet(AUTOMATION_MSG_NAVIGATION_SUCCESS); - } - } 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(AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED); - } 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_; - int navigations_remaining_; - bool navigation_started_; -}; - -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; - } - - automation_->AddNavigationStatusListener(controller, reply_message_, 1); - } - - 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_; -}; - -class BrowserCountChangeNotificationObserver : public NotificationObserver { - public: - BrowserCountChangeNotificationObserver(int target_count, - AutomationProvider* automation, - IPC::Message* reply_message) - : target_count_(target_count), - automation_(automation), - reply_message_(reply_message) { - registrar_.Add(this, NotificationType::BROWSER_OPENED, - NotificationService::AllSources()); - registrar_.Add(this, NotificationType::BROWSER_CLOSED, - NotificationService::AllSources()); - } - - virtual void Observe(NotificationType type, - const NotificationSource& source, - const NotificationDetails& details) { - DCHECK(type == NotificationType::BROWSER_OPENED || - type == NotificationType::BROWSER_CLOSED); - int current_count = static_cast<int>(BrowserList::size()); - if (type == NotificationType::BROWSER_CLOSED) { - // At the time of the notification the browser being closed is not removed - // from the list. The real count is one less than the reported count. - DCHECK_LT(0, current_count); - current_count--; - } - if (current_count == target_count_) { - AutomationMsg_WaitForBrowserWindowCountToBecome::WriteReplyParams( - reply_message_, true); - automation_->Send(reply_message_); - reply_message_ = NULL; - delete this; - } - } - - private: - int target_count_; - NotificationRegistrar registrar_; - AutomationProvider* automation_; - IPC::Message* reply_message_; -}; - -class AppModalDialogShownObserver : public NotificationObserver { - public: - AppModalDialogShownObserver(AutomationProvider* automation, - IPC::Message* reply_message) - : automation_(automation), - reply_message_(reply_message) { - registrar_.Add(this, NotificationType::APP_MODAL_DIALOG_SHOWN, - NotificationService::AllSources()); - } - - ~AppModalDialogShownObserver() { - } - - virtual void Observe(NotificationType type, - const NotificationSource& source, - const NotificationDetails& details) { - DCHECK(type == NotificationType::APP_MODAL_DIALOG_SHOWN); - AutomationMsg_WaitForAppModalDialogToBeShown::WriteReplyParams( - reply_message_, true); - automation_->Send(reply_message_); - reply_message_ = NULL; - delete this; - } - - private: - NotificationRegistrar registrar_; - AutomationProvider* automation_; - IPC::Message* reply_message_; -}; - -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( - &browser->GetSelectedTabContents()->controller(), - reply_message, 1); - 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, ¬ification_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()) { - if (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(WARNING) << "Multiple final Find messages observed."; - } - } 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, |