| // Copyright (c) 2010 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_observers.h" |
| |
| #include <deque> |
| #include <string> |
| #include <vector> |
| |
| #include "base/basictypes.h" |
| #include "base/callback.h" |
| #include "base/file_util.h" |
| #include "base/json/json_writer.h" |
| #include "base/scoped_ptr.h" |
| #include "base/string_util.h" |
| #include "base/stringprintf.h" |
| #include "base/threading/thread_restrictions.h" |
| #include "base/values.h" |
| #include "chrome/app/chrome_command_ids.h" |
| #include "chrome/browser/automation/automation_provider.h" |
| #include "chrome/browser/automation/automation_provider_json.h" |
| #include "chrome/browser/bookmarks/bookmark_model.h" |
| #include "chrome/browser/browser_list.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/dom_operation_notification_details.h" |
| #include "chrome/browser/dom_ui/most_visited_handler.h" |
| #include "chrome/browser/dom_ui/new_tab_ui.h" |
| #include "chrome/browser/download/download_item.h" |
| #include "chrome/browser/download/save_package.h" |
| #include "chrome/browser/extensions/extension_host.h" |
| #include "chrome/browser/extensions/extension_process_manager.h" |
| #include "chrome/browser/extensions/extension_updater.h" |
| #include "chrome/browser/history/top_sites.h" |
| #include "chrome/browser/metrics/metric_event_duration_details.h" |
| #include "chrome/browser/notifications/balloon.h" |
| #include "chrome/browser/notifications/balloon_host.h" |
| #include "chrome/browser/notifications/balloon_collection.h" |
| #include "chrome/browser/notifications/notification.h" |
| #include "chrome/browser/notifications/notification_ui_manager.h" |
| #include "chrome/browser/printing/print_job.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/renderer_host/render_process_host.h" |
| #include "chrome/browser/renderer_host/render_view_host.h" |
| #include "chrome/browser/search_engines/template_url_model.h" |
| #include "chrome/browser/sessions/tab_restore_service.h" |
| #include "chrome/browser/tab_contents/navigation_controller.h" |
| #include "chrome/browser/tab_contents/tab_contents.h" |
| #include "chrome/browser/tab_contents/thumbnail_generator.h" |
| #include "chrome/browser/translate/page_translated_details.h" |
| #include "chrome/browser/translate/translate_infobar_delegate.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/browser/ui/login/login_prompt.h" |
| #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" |
| #include "chrome/common/automation_constants.h" |
| #include "chrome/common/extensions/extension.h" |
| #include "chrome/common/notification_service.h" |
| #include "gfx/codec/png_codec.h" |
| #include "gfx/rect.h" |
| #include "googleurl/src/gurl.h" |
| |
| #if defined(OS_CHROMEOS) |
| #include "chrome/browser/chromeos/login/authentication_notification_details.h" |
| #endif |
| |
| // Holds onto start and stop timestamps for a particular tab |
| class InitialLoadObserver::TabTime { |
| public: |
| explicit TabTime(base::TimeTicks started) |
| : load_start_time_(started) { |
| } |
| void set_stop_time(base::TimeTicks stopped) { |
| load_stop_time_ = stopped; |
| } |
| base::TimeTicks stop_time() const { |
| return load_stop_time_; |
| } |
| base::TimeTicks start_time() const { |
| return load_start_time_; |
| } |
| private: |
| base::TimeTicks load_start_time_; |
| base::TimeTicks load_stop_time_; |
| }; |
| |
| InitialLoadObserver::InitialLoadObserver(size_t tab_count, |
| AutomationProvider* automation) |
| : automation_(automation), |
| outstanding_tab_count_(tab_count), |
| init_time_(base::TimeTicks::Now()) { |
| if (outstanding_tab_count_ > 0) { |
| registrar_.Add(this, NotificationType::LOAD_START, |
| NotificationService::AllSources()); |
| registrar_.Add(this, NotificationType::LOAD_STOP, |
| NotificationService::AllSources()); |
| } |
| } |
| |
| InitialLoadObserver::~InitialLoadObserver() { |
| } |
| |
| void InitialLoadObserver::Observe(NotificationType type, |
| const NotificationSource& source, |
| const NotificationDetails& details) { |
| if (type == NotificationType::LOAD_START) { |
| if (outstanding_tab_count_ > loading_tabs_.size()) |
| loading_tabs_.insert(TabTimeMap::value_type( |
| source.map_key(), |
| TabTime(base::TimeTicks::Now()))); |
| } else if (type == NotificationType::LOAD_STOP) { |
| if (outstanding_tab_count_ > finished_tabs_.size()) { |
| TabTimeMap::iterator iter = loading_tabs_.find(source.map_key()); |
| if (iter != loading_tabs_.end()) { |
| finished_tabs_.insert(source.map_key()); |
| iter->second.set_stop_time(base::TimeTicks::Now()); |
| } |
| if (outstanding_tab_count_ == finished_tabs_.size()) |
| ConditionMet(); |
| } |
| } else { |
| NOTREACHED(); |
| } |
| } |
| |
| DictionaryValue* InitialLoadObserver::GetTimingInformation() const { |
| ListValue* items = new ListValue; |
| for (TabTimeMap::const_iterator it = loading_tabs_.begin(); |
| it != loading_tabs_.end(); |
| ++it) { |
| DictionaryValue* item = new DictionaryValue; |
| base::TimeDelta delta_start = it->second.start_time() - init_time_; |
| |
| item->SetReal("load_start_ms", delta_start.InMillisecondsF()); |
| if (it->second.stop_time().is_null()) { |
| item->Set("load_stop_ms", Value::CreateNullValue()); |
| } else { |
| base::TimeDelta delta_stop = it->second.stop_time() - init_time_; |
| item->SetReal("load_stop_ms", delta_stop.InMillisecondsF()); |
| } |
| items->Append(item); |
| } |
| DictionaryValue* return_value = new DictionaryValue; |
| return_value->Set("tabs", items); |
| return return_value; |
| } |
| |
| void InitialLoadObserver::ConditionMet() { |
| registrar_.RemoveAll(); |
| automation_->OnInitialLoadsComplete(); |
| } |
| |
| NewTabUILoadObserver::NewTabUILoadObserver(AutomationProvider* automation) |
| : automation_(automation) { |
| registrar_.Add(this, NotificationType::INITIAL_NEW_TAB_UI_LOAD, |
| NotificationService::AllSources()); |
| } |
| |
| NewTabUILoadObserver::~NewTabUILoadObserver() { |
| } |
| |
| void NewTabUILoadObserver::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(*load_time.ptr())); |
| } else { |
| NOTREACHED(); |
| } |
| } |
| |
| NavigationControllerRestoredObserver::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::~NavigationControllerRestoredObserver() { |
| } |
| |
| void NavigationControllerRestoredObserver::Observe( |
| NotificationType type, const NotificationSource& source, |
| const NotificationDetails& details) { |
| if (FinishedRestoring()) { |
| SendDone(); |
| registrar_.RemoveAll(); |
| } |
| } |
| |
| bool NavigationControllerRestoredObserver::FinishedRestoring() { |
| return (!controller_->needs_reload() && !controller_->pending_entry() && |
| !controller_->tab_contents()->is_loading()); |
| } |
| |
| void NavigationControllerRestoredObserver::SendDone() { |
| DCHECK(reply_message_ != NULL); |
| automation_->Send(reply_message_); |
| } |
| |
| NavigationNotificationObserver::NavigationNotificationObserver( |
| NavigationController* controller, |
| AutomationProvider* automation, |
| IPC::Message* reply_message, |
| int number_of_navigations, |
| bool include_current_navigation) |
| : 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); |
| registrar_.Add(this, NotificationType::AUTH_CANCELLED, source); |
| |
| if (include_current_navigation && controller->tab_contents()->is_loading()) |
| navigation_started_ = true; |
| } |
| |
| NavigationNotificationObserver::~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 NavigationNotificationObserver::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 || |
| type == NotificationType::AUTH_CANCELLED) { |
| // 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) { |
| // Remember the login handler that wants authentication. |
| // We do this in all cases (not just when navigation_started_ == true) so |
| // tests can still wait for auth dialogs outside of navigation. |
| 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(); |
| } |
| } |
| |
| void NavigationNotificationObserver::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; |
| } |
| |
| TabStripNotificationObserver::TabStripNotificationObserver( |
| NotificationType notification, AutomationProvider* automation) |
| : automation_(automation), |
| notification_(notification) { |
| registrar_.Add(this, notification_, NotificationService::AllSources()); |
| } |
| |
| TabStripNotificationObserver::~TabStripNotificationObserver() { |
| } |
| |
| void TabStripNotificationObserver::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(); |
| } |
| } |
| |
| TabAppendedNotificationObserver::TabAppendedNotificationObserver( |
| Browser* parent, AutomationProvider* automation, |
| IPC::Message* reply_message) |
| : TabStripNotificationObserver(NotificationType::TAB_PARENTED, automation), |
| parent_(parent), |
| reply_message_(reply_message) { |
| } |
| |
| void TabAppendedNotificationObserver::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, |
| false); |
| } |
| |
| TabClosedNotificationObserver::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) { |
| } |
| |
| void TabClosedNotificationObserver::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 TabClosedNotificationObserver::set_for_browser_command( |
| bool for_browser_command) { |
| for_browser_command_ = for_browser_command; |
| } |
| |
| TabCountChangeObserver::TabCountChangeObserver(AutomationProvider* automation, |
| Browser* browser, |
| IPC::Message* reply_message, |
| int target_tab_count) |
| : automation_(automation), |
| reply_message_(reply_message), |
| tab_strip_model_(browser->tabstrip_model()), |
| target_tab_count_(target_tab_count) { |
| tab_strip_model_->AddObserver(this); |
| CheckTabCount(); |
| } |
| |
| TabCountChangeObserver::~TabCountChangeObserver() { |
| tab_strip_model_->RemoveObserver(this); |
| } |
| |
| void TabCountChangeObserver::TabInsertedAt(TabContentsWrapper* contents, |
| int index, |
| bool foreground) { |
| CheckTabCount(); |
| } |
| |
| void TabCountChangeObserver::TabDetachedAt(TabContentsWrapper* contents, |
| int index) { |
| CheckTabCount(); |
| } |
| |
| void TabCountChangeObserver::TabStripModelDeleted() { |
| AutomationMsg_WaitForTabCountToBecome::WriteReplyParams(reply_message_, |
| false); |
| automation_->Send(reply_message_); |
| delete this; |
| } |
| |
| void TabCountChangeObserver::CheckTabCount() { |
| if (tab_strip_model_->count() != target_tab_count_) |
| return; |
| |
| AutomationMsg_WaitForTabCountToBecome::WriteReplyParams(reply_message_, |
| true); |
| automation_->Send(reply_message_); |
| delete this; |
| } |
| |
| bool DidExtensionHostsStopLoading(ExtensionProcessManager* manager) { |
| for (ExtensionProcessManager::const_iterator iter = manager->begin(); |
| iter != manager->end(); ++iter) { |
| if (!(*iter)->did_stop_loading()) |
| return false; |
| } |
| return true; |
| } |
| |
| ExtensionInstallNotificationObserver::ExtensionInstallNotificationObserver( |
| AutomationProvider* automation, int id, IPC::Message* reply_message) |
| : automation_(automation), |
| id_(id), |
| reply_message_(reply_message) { |
| registrar_.Add(this, NotificationType::EXTENSION_LOADED, |
| NotificationService::AllSources()); |
| registrar_.Add(this, NotificationType::EXTENSION_INSTALL_ERROR, |
| NotificationService::AllSources()); |
| registrar_.Add(this, NotificationType::EXTENSION_UPDATE_DISABLED, |
| NotificationService::AllSources()); |
| } |
| |
| ExtensionInstallNotificationObserver::~ExtensionInstallNotificationObserver() { |
| } |
| |
| void ExtensionInstallNotificationObserver::Observe( |
| NotificationType type, const NotificationSource& source, |
| const NotificationDetails& details) { |
| switch (type.value) { |
| case NotificationType::EXTENSION_LOADED: |
| SendResponse(AUTOMATION_MSG_EXTENSION_INSTALL_SUCCEEDED); |
| break; |
| case NotificationType::EXTENSION_INSTALL_ERROR: |
| case NotificationType::EXTENSION_UPDATE_DISABLED: |
| SendResponse(AUTOMATION_MSG_EXTENSION_INSTALL_FAILED); |
| break; |
| default: |
| NOTREACHED(); |
| break; |
| } |
| |
| delete this; |
| } |
| |
| void ExtensionInstallNotificationObserver::SendResponse( |
| AutomationMsg_ExtensionResponseValues response) { |
| if (reply_message_ != NULL) { |
| switch (id_) { |
| case AutomationMsg_InstallExtension::ID: |
| AutomationMsg_InstallExtension::WriteReplyParams(reply_message_, |
| response); |
| break; |
| case AutomationMsg_LoadExpandedExtension::ID: |
| AutomationMsg_LoadExpandedExtension::WriteReplyParams(reply_message_, |
| response); |
| break; |
| default: |
| NOTREACHED(); |
| break; |
| } |
| |
| automation_->Send(reply_message_); |
| reply_message_ = NULL; |
| } |
| } |
| |
| ExtensionReadyNotificationObserver::ExtensionReadyNotificationObserver( |
| ExtensionProcessManager* manager, AutomationProvider* automation, int id, |
| IPC::Message* reply_message) |
| : manager_(manager), |
| automation_(automation), |
| id_(id), |
| reply_message_(reply_message), |
| extension_(NULL) { |
| registrar_.Add(this, NotificationType::EXTENSION_HOST_DID_STOP_LOADING, |
| NotificationService::AllSources()); |
| registrar_.Add(this, NotificationType::EXTENSION_LOADED, |
| NotificationService::AllSources()); |
| registrar_.Add(this, NotificationType::EXTENSION_INSTALL_ERROR, |
| NotificationService::AllSources()); |
| registrar_.Add(this, NotificationType::EXTENSION_UPDATE_DISABLED, |
| NotificationService::AllSources()); |
| } |
| |
| ExtensionReadyNotificationObserver::~ExtensionReadyNotificationObserver() { |
| } |
| |
| void ExtensionReadyNotificationObserver::Observe( |
| NotificationType type, const NotificationSource& source, |
| const NotificationDetails& details) { |
| bool success = false; |
| switch (type.value) { |
| case NotificationType::EXTENSION_HOST_DID_STOP_LOADING: |
| // Only continue on with this method if our extension has been loaded |
| // and all the extension hosts have stopped loading. |
| if (!extension_ || !DidExtensionHostsStopLoading(manager_)) |
| return; |
| success = true; |
| break; |
| case NotificationType::EXTENSION_LOADED: |
| extension_ = Details<const Extension>(details).ptr(); |
| if (!DidExtensionHostsStopLoading(manager_)) |
| return; |
| success = true; |
| break; |
| case NotificationType::EXTENSION_INSTALL_ERROR: |
| case NotificationType::EXTENSION_UPDATE_DISABLED: |
| success = false; |
| break; |
| default: |
| NOTREACHED(); |
| break; |
| } |
| |
| if (id_ == AutomationMsg_InstallExtensionAndGetHandle::ID) { |
| // A handle of zero indicates an error. |
| int extension_handle = 0; |
| if (extension_) |
| extension_handle = automation_->AddExtension(extension_); |
| AutomationMsg_InstallExtensionAndGetHandle::WriteReplyParams( |
| reply_message_, extension_handle); |
| } else if (id_ == AutomationMsg_EnableExtension::ID) { |
| AutomationMsg_EnableExtension::WriteReplyParams(reply_message_, true); |
| } else { |
| NOTREACHED(); |
| LOG(ERROR) << "Cannot write reply params for unknown message id."; |
| } |
| |
| automation_->Send(reply_message_); |
| delete this; |
| } |
| |
| ExtensionUnloadNotificationObserver::ExtensionUnloadNotificationObserver() |
| : did_receive_unload_notification_(false) { |
| registrar_.Add(this, NotificationType::EXTENSION_UNLOADED, |
| NotificationService::AllSources()); |
| } |
| |
| ExtensionUnloadNotificationObserver::~ExtensionUnloadNotificationObserver() { |
| } |
| |
| void ExtensionUnloadNotificationObserver::Observe( |
| NotificationType type, const NotificationSource& source, |
| const NotificationDetails& details) { |
| if (type.value == NotificationType::EXTENSION_UNLOADED) { |
| did_receive_unload_notification_ = true; |
| } else { |
| NOTREACHED(); |
| } |
| } |
| |
| ExtensionTestResultNotificationObserver:: |
| ExtensionTestResultNotificationObserver(AutomationProvider* automation) |
| : automation_(automation) { |
| registrar_.Add(this, NotificationType::EXTENSION_TEST_PASSED, |
| NotificationService::AllSources()); |
| registrar_.Add(this, NotificationType::EXTENSION_TEST_FAILED, |
| NotificationService::AllSources()); |
| } |
| |
| ExtensionTestResultNotificationObserver:: |
| ~ExtensionTestResultNotificationObserver() { |
| } |
| |
| void ExtensionTestResultNotificationObserver::Observe( |
| NotificationType type, const NotificationSource& source, |
| const NotificationDetails& details) { |
| switch (type.value) { |
| case NotificationType::EXTENSION_TEST_PASSED: |
| results_.push_back(true); |
| messages_.push_back(""); |
| break; |
| |
| case NotificationType::EXTENSION_TEST_FAILED: |
| results_.push_back(false); |
| messages_.push_back(*(Details<std::string>(details).ptr())); |
| break; |
| |
| default: |
| NOTREACHED(); |
| } |
| // There may be a reply message waiting for this event, so check. |
| MaybeSendResult(); |
| } |
| |
| void ExtensionTestResultNotificationObserver::MaybeSendResult() { |
| if (results_.size() > 0) { |
| // This release method should return the automation's current |
| // reply message, or NULL if there is no current one. If it is not |
| // NULL, we are stating that we will handle this reply message. |
| IPC::Message* reply_message = automation_->reply_message_release(); |
| // Send the result back if we have a reply message. |
| if (reply_message) { |
| AutomationMsg_WaitForExtensionTestResult::WriteReplyParams( |
| reply_message, results_.front(), messages_.front()); |
| results_.pop_front(); |
| messages_.pop_front(); |
| automation_->Send(reply_message); |
| } |
| } |
| } |
| |
| BrowserOpenedNotificationObserver::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::~BrowserOpenedNotificationObserver() { |
| } |
| |
| void BrowserOpenedNotificationObserver::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 BrowserOpenedNotificationObserver::set_for_browser_command( |
| bool for_browser_command) { |
| for_browser_command_ = for_browser_command; |
| } |
| |
| BrowserClosedNotificationObserver::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)); |
| } |
| |
| void BrowserClosedNotificationObserver::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 BrowserClosedNotificationObserver::set_for_browser_command( |
| bool for_browser_command) { |
| for_browser_command_ = for_browser_command; |
| } |
| |
| BrowserCountChangeNotificationObserver::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()); |
| } |
| |
| void BrowserCountChangeNotificationObserver::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; |
| } |
| } |
| |
| AppModalDialogShownObserver::AppModalDialogShownObserver( |
| AutomationProvider* automation, IPC::Message* reply_message) |
| : automation_(automation), |
| reply_message_(reply_message) { |
| registrar_.Add(this, NotificationType::APP_MODAL_DIALOG_SHOWN, |
| NotificationService::AllSources()); |
| } |
| |
| AppModalDialogShownObserver::~AppModalDialogShownObserver() { |
| } |
| |
| void AppModalDialogShownObserver::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; |
| } |
| |
| 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::INITIAL_NEW_TAB_UI_LOAD}, |
| |
| // 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}, |
| |
| // For the following commands, we need to wait for a new tab to be created, |
| // load to finish, and title to change. |
| {IDC_MANAGE_EXTENSIONS, NotificationType::TAB_CONTENTS_TITLE_UPDATED}, |
| {IDC_OPTIONS, NotificationType::TAB_CONTENTS_TITLE_UPDATED}, |
| {IDC_PRINT, NotificationType::TAB_CONTENTS_TITLE_UPDATED}, |
| {IDC_SHOW_DOWNLOADS, NotificationType::TAB_CONTENTS_TITLE_UPDATED}, |
| {IDC_SHOW_HISTORY, NotificationType::TAB_CONTENTS_TITLE_UPDATED}, |
| }; |
| |
| } // namespace |
| |
| ExecuteBrowserCommandObserver::~ExecuteBrowserCommandObserver() { |
| } |
| |
| // static |
| bool ExecuteBrowserCommandObserver::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, false); |
| break; |
| } |
| default: { |
| ExecuteBrowserCommandObserver* observer = |
| new ExecuteBrowserCommandObserver(automation, reply_message); |
| if (!observer->Register(command)) { |
| delete observer; |
| result = false; |
| } |
| break; |
| } |
| } |
| return result; |
| } |
| |
| void ExecuteBrowserCommandObserver::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(); |
| } |
| } |
| |
| ExecuteBrowserCommandObserver::ExecuteBrowserCommandObserver( |
| AutomationProvider* automation, IPC::Message* reply_message) |
| : automation_(automation), |
| notification_type_(NotificationType::ALL), |
| reply_message_(reply_message) { |
| } |
| |
| bool ExecuteBrowserCommandObserver::Register(int command) { |
| if (!GetNotificationType(command, ¬ification_type_)) |
| return false; |
| registrar_.Add(this, notification_type_, NotificationService::AllSources()); |
| return true; |
| } |
| |
| bool ExecuteBrowserCommandObserver::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; |
| } |
| |
| FindInPageNotificationObserver::FindInPageNotificationObserver( |
| AutomationProvider* automation, TabContents* parent_tab, |
| bool reply_with_json, IPC::Message* reply_message) |
| : automation_(automation), |
| active_match_ordinal_(-1), |
| reply_with_json_(reply_with_json), |
| reply_message_(reply_message) { |
| registrar_.Add(this, NotificationType::FIND_RESULT_AVAILABLE, |
| Source<TabContents>(parent_tab)); |
| } |
| |
| FindInPageNotificationObserver::~FindInPageNotificationObserver() { |
| } |
| |
| void FindInPageNotificationObserver::Observe( |
| NotificationType type, const NotificationSource& source, |
| const NotificationDetails& details) { |
| Details<FindNotificationDetails> find_details(details); |
| if (!(find_details->final_update() && reply_message_ != NULL)) { |
| DVLOG(1) << "Ignoring, since we only care about the final message"; |
| return; |
| } |
| // 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->request_id() == kFindInPageRequestId) { |
| if (reply_with_json_) { |
| scoped_ptr<DictionaryValue> return_value(new DictionaryValue); |
| return_value->SetInteger("match_count", |
| find_details->number_of_matches()); |
| gfx::Rect rect = find_details->selection_rect(); |
| // If MatchCount is > 0, then rect should not be Empty. |
| // We dont guard it here because we want to let the test |
| // code catch this invalid case if needed. |
| if (!rect.IsEmpty()) { |
| return_value->SetInteger("match_left", rect.x()); |
| return_value->SetInteger("match_top", rect.y()); |
| return_value->SetInteger("match_right", rect.right()); |
| return_value->SetInteger("match_bottom", rect.bottom()); |
| } |
| AutomationJSONReply(automation_, reply_message_) |
| .SendSuccess(return_value.get()); |
| delete this; |
| } else { |
| if (find_details->active_match_ordinal() > -1) { |
| active_match_ordinal_ = find_details->active_match_ordinal(); |
| AutomationMsg_Find::WriteReplyParams(reply_message_, |
| active_match_ordinal_, find_details->number_of_matches()); |
| automation_->Send(reply_message_); |
| reply_message_ = NULL; |
| } |
| } |
| } |
| } |
| |
| // static |
| const int FindInPageNotificationObserver::kFindInPageRequestId = -1; |
| |
| DomOperationObserver::DomOperationObserver() { |
| registrar_.Add(this, NotificationType::DOM_OPERATION_RESPONSE, |
| NotificationService::AllSources()); |
| } |
| |
| void DomOperationObserver::Observe( |
| NotificationType type, const NotificationSource& source, |
| const NotificationDetails& details) { |
| if (NotificationType::DOM_OPERATION_RESPONSE == type) { |
| Details<DomOperationNotificationDetails> dom_op_details(details); |
| OnDomOperationCompleted(dom_op_details->json()); |
| } |
| } |
| |
| void DomOperationMessageSender::OnDomOperationCompleted( |
| const std::string& json) { |
| IPC::Message* reply_message = automation_->reply_message_release(); |
| if (reply_message) { |
| AutomationMsg_DomOperation::WriteReplyParams(reply_message, json); |
| automation_->Send(reply_message); |
| } else { |
| LOG(ERROR) << "DOM operation completed, but no reply message"; |
| } |
| } |
| |
| DocumentPrintedNotificationObserver::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::~DocumentPrintedNotificationObserver() { |
| DCHECK(reply_message_ != NULL); |
| AutomationMsg_PrintNow::WriteReplyParams(reply_message_, success_); |
| automation_->Send(reply_message_); |
| automation_->RemoveNavigationStatusListener(this); |
| } |
| |
| void DocumentPrintedNotificationObserver::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; |
| } |
| } |
| } |
| |
| MetricEventDurationObserver::MetricEventDurationObserver() { |
| registrar_.Add(this, NotificationType::METRIC_EVENT_DURATION, |
| NotificationService::AllSources()); |
| } |
| |
| MetricEventDurationObserver::~MetricEventDurationObserver() {} |
| |
| int MetricEventDurationObserver::GetEventDurationMs( |
| const std::string& event_name) { |
| EventDurationMap::const_iterator it = durations_.find(event_name); |
| if (it == durations_.end()) |
| return -1; |
| return it->second; |
| } |
| |
| void MetricEventDurationObserver::Observe(NotificationType type, |
| const NotificationSource& source, const NotificationDetails& details) { |
| if (type != NotificationType::METRIC_EVENT_DURATION) { |
| NOTREACHED(); |
| return; |
| } |
| MetricEventDurationDetails* metric_event_duration = |
| Details<MetricEventDurationDetails>(details).ptr(); |
| durations_[metric_event_duration->event_name] = |
| metric_event_duration->duration_ms; |
| } |
| |
| PageTranslatedObserver::PageTranslatedObserver(AutomationProvider* automation, |
| IPC::Message* reply_message, |
| TabContents* tab_contents) |
| : automation_(automation), |
| reply_message_(reply_message) { |
| registrar_.Add(this, NotificationType::PAGE_TRANSLATED, |
| Source<TabContents>(tab_contents)); |
| } |
| |
| PageTranslatedObserver::~PageTranslatedObserver() {} |
| |
| void PageTranslatedObserver::Observe(NotificationType type, |
| const NotificationSource& source, |
| const NotificationDetails& details) { |
| DCHECK(type == NotificationType::PAGE_TRANSLATED); |
| AutomationJSONReply reply(automation_, reply_message_); |
| |
| PageTranslatedDetails* translated_details = |
| Details<PageTranslatedDetails>(details).ptr(); |
| scoped_ptr<DictionaryValue> return_value(new DictionaryValue); |
| return_value->SetBoolean( |
| "translation_success", |
| translated_details->error_type == TranslateErrors::NONE); |
| reply.SendSuccess(return_value.get()); |
| delete this; |
| } |
| |
| TabLanguageDeterminedObserver::TabLanguageDeterminedObserver( |
| AutomationProvider* automation, IPC::Message* reply_message, |
| TabContents* tab_contents, TranslateInfoBarDelegate* translate_bar) |
| : automation_(automation), |
| reply_message_(reply_message), |
| tab_contents_(tab_contents), |
| translate_bar_(translate_bar) { |
| registrar_.Add(this, NotificationType::TAB_LANGUAGE_DETERMINED, |
| Source<TabContents>(tab_contents)); |
| } |
| |
| void TabLanguageDeterminedObserver::Observe( |
| NotificationType type, const NotificationSource& source, |
| const NotificationDetails& details) { |
| DCHECK(type == NotificationType::TAB_LANGUAGE_DETERMINED); |
| |
| scoped_ptr<DictionaryValue> return_value(new DictionaryValue); |
| return_value->SetBoolean("page_translated", |
| tab_contents_->language_state().IsPageTranslated()); |
| return_value->SetBoolean( |
| "can_translate_page", TranslatePrefs::CanTranslate( |
| automation_->profile()->GetPrefs(), |
| tab_contents_->language_state().original_language(), |
| tab_contents_->GetURL())); |
| return_value->SetString( |
| "original_language", |
| tab_contents_->language_state().original_language()); |
| if (translate_bar_) { |
| DictionaryValue* bar_info = new DictionaryValue; |
| std::map<TranslateInfoBarDelegate::Type, std::string> type_to_string; |
| type_to_string[TranslateInfoBarDelegate::BEFORE_TRANSLATE] = |
| "BEFORE_TRANSLATE"; |
| type_to_string[TranslateInfoBarDelegate::TRANSLATING] = |
| "TRANSLATING"; |
| type_to_string[TranslateInfoBarDelegate::AFTER_TRANSLATE] = |
| "AFTER_TRANSLATE"; |
| type_to_string[TranslateInfoBarDelegate::TRANSLATION_ERROR] = |
| "TRANSLATION_ERROR"; |
| |
| bar_info->SetBoolean("always_translate_lang_button_showing", |
| translate_bar_->ShouldShowAlwaysTranslateButton()); |
| bar_info->SetBoolean("never_translate_lang_button_showing", |
| translate_bar_->ShouldShowNeverTranslateButton()); |
| bar_info->SetString("bar_state", type_to_string[translate_bar_->type()]); |
| bar_info->SetString("target_lang_code", |
| translate_bar_->GetTargetLanguageCode()); |
| bar_info->SetString("original_lang_code", |
| translate_bar_->GetOriginalLanguageCode()); |
| return_value->Set("translate_bar", bar_info); |
| } |
| AutomationJSONReply(automation_, reply_message_) |
| .SendSuccess(return_value.get()); |
| delete this; |
| } |
| |
| InfoBarCountObserver::InfoBarCountObserver(AutomationProvider* automation, |
| IPC::Message* reply_message, |
| TabContents* tab_contents, |
| int target_count) |
| : automation_(automation), |
| reply_message_(reply_message), |
| tab_contents_(tab_contents), |
| target_count_(target_count) { |
| Source<TabContents> source(tab_contents); |
| registrar_.Add(this, NotificationType::TAB_CONTENTS_INFOBAR_ADDED, source); |
| registrar_.Add(this, NotificationType::TAB_CONTENTS_INFOBAR_REMOVED, source); |
| CheckCount(); |
| } |
| |
| void InfoBarCountObserver::Observe(NotificationType type, |
| const NotificationSource& source, |
| const NotificationDetails& details) { |
| DCHECK(type == NotificationType::TAB_CONTENTS_INFOBAR_ADDED || |
| type == NotificationType::TAB_CONTENTS_INFOBAR_REMOVED); |
| CheckCount(); |
| } |
| |
| void InfoBarCountObserver::CheckCount() { |
| if (tab_contents_->infobar_delegate_count() != target_count_) |
| return; |
| |
| AutomationMsg_WaitForInfoBarCount::WriteReplyParams(reply_message_, true); |
| automation_->Send(reply_message_); |
| delete this; |
| } |
| |
| #if defined(OS_CHROMEOS) |
| LoginManagerObserver::LoginManagerObserver( |
| AutomationProvider* automation, |
| IPC::Message* reply_message) |
| : automation_(automation), |
| reply_message_(reply_message) { |
| |
| registrar_.Add(this, NotificationType::LOGIN_AUTHENTICATION, |
| NotificationService::AllSources()); |
| } |
| |
| void LoginManagerObserver::Observe(NotificationType type, |
| const NotificationSource& source, |
| const NotificationDetails& details) { |
| DCHECK(type == NotificationType::LOGIN_AUTHENTICATION); |
| Details<AuthenticationNotificationDetails> auth_details(details); |
| AutomationMsg_LoginWithUserAndPass::WriteReplyParams(reply_message_, |
| auth_details->success()); |
| automation_->Send(reply_message_); |
| delete this; |
| } |
| #endif |
| |
| AutomationProviderBookmarkModelObserver:: |
| AutomationProviderBookmarkModelObserver( |
| AutomationProvider* provider, |
| IPC::Message* reply_message, |
| BookmarkModel* model) { |
| automation_provider_ = provider; |
| reply_message_ = reply_message; |
| model_ = model; |
| model_->AddObserver(this); |
| } |
| |
| AutomationProviderBookmarkModelObserver:: |
| ~AutomationProviderBookmarkModelObserver() { |
| model_->RemoveObserver(this); |
| } |
| |
| void AutomationProviderBookmarkModelObserver::Loaded(BookmarkModel* model) { |
| ReplyAndDelete(true); |
| } |
| |
| void AutomationProviderBookmarkModelObserver::BookmarkModelBeingDeleted( |
| BookmarkModel* model) { |
| ReplyAndDelete(false); |
| } |
| |
| void AutomationProviderBookmarkModelObserver::ReplyAndDelete(bool success) { |
| AutomationMsg_WaitForBookmarkModelToLoad::WriteReplyParams( |
| reply_message_, success); |
| automation_provider_->Send(reply_message_); |
| delete this; |
| } |
| |
| void AutomationProviderDownloadItemObserver::OnDownloadFileCompleted( |
| DownloadItem* download) { |
| download->RemoveObserver(this); |
| if (--downloads_ == 0) { |
| AutomationJSONReply(provider_, reply_message_).SendSuccess(NULL); |
| delete this; |
| } |
| } |
| |
| void AutomationProviderDownloadUpdatedObserver::OnDownloadUpdated( |
| DownloadItem* download) { |
| // If this observer is watching for open, only send the reply if the download |
| // has been auto-opened. |
| if (wait_for_open_ && !download->auto_opened()) |
| return; |
| |
| download->RemoveObserver(this); |
| scoped_ptr<DictionaryValue> return_value( |
| provider_->GetDictionaryFromDownloadItem(download)); |
| AutomationJSONReply(provider_, reply_message_).SendSuccess( |
| return_value.get()); |
| delete this; |
| } |
| |
| void AutomationProviderDownloadUpdatedObserver::OnDownloadOpened( |
| DownloadItem* download) { |
| download->RemoveObserver(this); |
| scoped_ptr<DictionaryValue> return_value( |
| provider_->GetDictionaryFromDownloadItem(download)); |
| AutomationJSONReply(provider_, reply_message_).SendSuccess( |
| return_value.get()); |
| delete this; |
| } |
| |
| void AutomationProviderDownloadModelChangedObserver::ModelChanged() { |
| AutomationJSONReply(provider_, reply_message_).SendSuccess(NULL); |
| download_manager_->RemoveObserver(this); |
| delete this; |
| } |
| |
| void AutomationProviderSearchEngineObserver::OnTemplateURLModelChanged() { |
| TemplateURLModel* url_model = provider_->profile()->GetTemplateURLModel(); |
| url_model->RemoveObserver(this); |
| AutomationJSONReply(provider_, reply_message_).SendSuccess(NULL); |
| delete this; |
| } |
| |
| void AutomationProviderHistoryObserver::HistoryQueryComplete( |
| HistoryService::Handle request_handle, |
| history::QueryResults* results) { |
| scoped_ptr<DictionaryValue> return_value(new DictionaryValue); |
| |
| ListValue* history_list = new ListValue; |
| for (size_t i = 0; i < results->size(); ++i) { |
| DictionaryValue* page_value = new DictionaryValue; |
| history::URLResult const &page = (*results)[i]; |
| page_value->SetString("title", page.title()); |
| page_value->SetString("url", page.url().spec()); |
| page_value->SetReal("time", |
| static_cast<double>(page.visit_time().ToDoubleT())); |
| page_value->SetString("snippet", page.snippet().text()); |
| page_value->SetBoolean( |
| "starred", |
| provider_->profile()->GetBookmarkModel()->IsBookmarked(page.url())); |
| history_list->Append(page_value); |
| } |
| |
| return_value->Set("history", history_list); |
| // Return history info. |
| AutomationJSONReply reply(provider_, reply_message_); |
| reply.SendSuccess(return_value.get()); |
| delete this; |
| } |
| |
| void AutomationProviderImportSettingsObserver::ImportEnded() { |
| // Send back an empty success message. |
| AutomationJSONReply(provider_, reply_message_).SendSuccess(NULL); |
| delete this; |
| } |
| |
| void AutomationProviderGetPasswordsObserver::OnPasswordStoreRequestDone( |
| int handle, const std::vector<webkit_glue::PasswordForm*>& result) { |
| scoped_ptr<DictionaryValue> return_value(new DictionaryValue); |
| |
| ListValue* passwords = new ListValue; |
| for (std::vector<webkit_glue::PasswordForm*>::const_iterator it = |
| result.begin(); it != result.end(); ++it) { |
| DictionaryValue* password_val = new DictionaryValue; |
| webkit_glue::PasswordForm* password_form = *it; |
| password_val->SetString("username_value", password_form->username_value); |
| password_val->SetString("password_value", password_form->password_value); |
| password_val->SetString("signon_realm", password_form->signon_realm); |
| password_val->SetReal( |
| "time", static_cast<double>(password_form->date_created.ToDoubleT())); |
| password_val->SetString("origin_url", password_form->origin.spec()); |
| password_val->SetString("username_element", |
| password_form->username_element); |
| password_val->SetString("password_element", |
| password_form->password_element); |
| password_val->SetString("submit_element", |
| password_form->submit_element); |
| password_val->SetString("action_target", password_form->action.spec()); |
| password_val->SetBoolean("blacklist", password_form->blacklisted_by_user); |
| passwords->Append(password_val); |
| } |
| |
| return_value->Set("passwords", passwords); |
| AutomationJSONReply(provider_, reply_message_).SendSuccess( |
| return_value.get()); |
| delete this; |
| } |
| |
| void AutomationProviderBrowsingDataObserver::OnBrowsingDataRemoverDone() { |
| // Send back an empty success message |
| AutomationJSONReply(provider_, reply_message_).SendSuccess(NULL); |
| delete this; |
| } |
| |
| OmniboxAcceptNotificationObserver::OmniboxAcceptNotificationObserver( |
| NavigationController* controller, |
| AutomationProvider* automation, |
| IPC::Message* reply_message) |
| : automation_(automation), |
| reply_message_(reply_message), |
| controller_(controller) { |
| Source<NavigationController> source(controller_); |
| registrar_.Add(this, NotificationType::LOAD_STOP, source); |
| // Pages requiring auth don't send LOAD_STOP. |
| registrar_.Add(this, NotificationType::AUTH_NEEDED, source); |
| } |
| |
| OmniboxAcceptNotificationObserver::~OmniboxAcceptNotificationObserver() { |
| automation_->RemoveNavigationStatusListener(this); |
| } |
| |
| void OmniboxAcceptNotificationObserver::Observe( |
| NotificationType type, |
| const NotificationSource& source, |
| const NotificationDetails& details) { |
| if (type == NotificationType::LOAD_STOP || |
| type == NotificationType::AUTH_NEEDED) { |
| AutomationJSONReply(automation_, reply_message_).SendSuccess(NULL); |
| delete this; |
| } else { |
| NOTREACHED(); |
| } |
| } |
| |
| SavePackageNotificationObserver::SavePackageNotificationObserver( |
| SavePackage* save_package, |
| AutomationProvider* automation, |
| IPC::Message* reply_message) : automation_(automation), |
| reply_message_(reply_message) { |
| Source<SavePackage> source(save_package); |
| registrar_.Add(this, NotificationType::SAVE_PACKAGE_SUCCESSFULLY_FINISHED, |
| source); |
| } |
| |
| void SavePackageNotificationObserver::Observe( |
| NotificationType type, |
| const NotificationSource& source, |
| const NotificationDetails& details) { |
| if (type == NotificationType::SAVE_PACKAGE_SUCCESSFULLY_FINISHED) { |
| AutomationJSONReply(automation_, reply_message_).SendSuccess(NULL); |
| delete this; |
| } else { |
| NOTREACHED(); |
| } |
| } |
| |
| PageSnapshotTaker::PageSnapshotTaker(AutomationProvider* automation, |
| IPC::Message* reply_message, |
| RenderViewHost* render_view, |
| const FilePath& path) |
| : automation_(automation), |
| reply_message_(reply_message), |
| render_view_(render_view), |
| image_path_(path), |
| received_width_(false) {} |
| |
| void PageSnapshotTaker::Start() { |
| ExecuteScript(L"window.domAutomationController.send(document.width);"); |
| } |
| |
| void PageSnapshotTaker::OnDomOperationCompleted(const std::string& json) { |
| int dimension; |
| if (!base::StringToInt(json, &dimension)) { |
| LOG(ERROR) << "Could not parse received dimensions: " << json; |
| SendMessage(false); |
| } else if (!received_width_) { |
| received_width_ = true; |
| entire_page_size_.set_width(dimension); |
| |
| ExecuteScript(L"window.domAutomationController.send(document.height);"); |
| } else { |
| entire_page_size_.set_height(dimension); |
| |
| ThumbnailGenerator* generator = |
| g_browser_process->GetThumbnailGenerator(); |
| ThumbnailGenerator::ThumbnailReadyCallback* callback = |
| NewCallback(this, &PageSnapshotTaker::OnSnapshotTaken); |
| // Don't actually start the thumbnail generator, this leads to crashes on |
| // Mac, crbug.com/62986. Instead, just hook the generator to the |
| // RenderViewHost manually. |
| render_view_->set_painting_observer(generator); |
| generator->AskForSnapshot(render_view_, false, callback, |
| entire_page_size_, entire_page_size_); |
| } |
| } |
| |
| void PageSnapshotTaker::OnSnapshotTaken(const SkBitmap& bitmap) { |
| base::ThreadRestrictions::ScopedAllowIO allow_io; |
| std::vector<unsigned char> png_data; |
| gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, true, &png_data); |
| int bytes_written = file_util::WriteFile(image_path_, |
| reinterpret_cast<char*>(&png_data[0]), png_data.size()); |
| SendMessage(bytes_written == static_cast<int>(png_data.size())); |
| } |
| |
| void PageSnapshotTaker::ExecuteScript(const std::wstring& javascript) { |
| std::wstring set_automation_id; |
| base::SStringPrintf( |
| &set_automation_id, |
| L"window.domAutomationController.setAutomationId(%d);", |
| reply_message_->routing_id()); |
| |
| render_view_->ExecuteJavascriptInWebFrame(L"", set_automation_id); |
| render_view_->ExecuteJavascriptInWebFrame(L"", javascript); |
| } |
| |
| void PageSnapshotTaker::SendMessage(bool success) { |
| AutomationMsg_CaptureEntirePageAsPNG::WriteReplyParams(reply_message_, |
| success); |
| automation_->Send(reply_message_); |
| delete this; |
| } |
| |
| NTPInfoObserver::NTPInfoObserver( |
| AutomationProvider* automation, |
| IPC::Message* reply_message, |
| CancelableRequestConsumer* consumer) |
| : automation_(automation), |
| reply_message_(reply_message), |
| consumer_(consumer), |
| request_(NULL), |
| ntp_info_(new DictionaryValue) { |
| top_sites_ = automation_->profile()->GetTopSites(); |
| if (!top_sites_) { |
| AutomationJSONReply(automation_, reply_message_) |
| .SendError("Profile does not have service for querying the top sites."); |
| return; |
| } |
| TabRestoreService* service = automation_->profile()->GetTabRestoreService(); |
| if (!service) { |
| AutomationJSONReply(automation_, reply_message_) |
| .SendError("No TabRestoreService."); |
| return; |
| } |
| |
| // Get the info that would be displayed in the recently closed section. |
| ListValue* recently_closed_list = new ListValue; |
| NewTabUI::AddRecentlyClosedEntries(service->entries(), |
| recently_closed_list); |
| ntp_info_->Set("recently_closed", recently_closed_list); |
| |
| // Add default site URLs. |
| ListValue* default_sites_list = new ListValue; |
| std::vector<GURL> urls = MostVisitedHandler::GetPrePopulatedUrls(); |
| for (size_t i = 0; i < urls.size(); ++i) { |
| default_sites_list->Append(Value::CreateStringValue( |
| urls[i].possibly_invalid_spec())); |
| } |
| ntp_info_->Set("default_sites", default_sites_list); |
| |
| registrar_.Add(this, NotificationType::TOP_SITES_UPDATED, |
| Source<history::TopSites>(top_sites_)); |
| if (top_sites_->loaded()) { |
| OnTopSitesLoaded(); |
| } else { |
| registrar_.Add(this, NotificationType::TOP_SITES_LOADED, |
| Source<Profile>(automation_->profile())); |
| } |
| } |
| |
| NTPInfoObserver::~NTPInfoObserver() {} |
| |
| void NTPInfoObserver::Observe(NotificationType type, |
| const NotificationSource& source, |
| const NotificationDetails& details) { |
| if (type == NotificationType::TOP_SITES_LOADED) { |
| OnTopSitesLoaded(); |
| } else if (type == NotificationType::TOP_SITES_UPDATED) { |
| Details<CancelableRequestProvider::Handle> request_details(details); |
| if (request_ == *request_details.ptr()) { |
| top_sites_->GetMostVisitedURLs( |
| consumer_, |
| NewCallback(this, &NTPInfoObserver::OnTopSitesReceived)); |
| } |
| } |
| } |
| |
| void NTPInfoObserver::OnTopSitesLoaded() { |
| request_ = top_sites_->StartQueryForMostVisited(); |
| } |
| |
| void NTPInfoObserver::OnTopSitesReceived( |
| const history::MostVisitedURLList& visited_list) { |
| ListValue* list_value = new ListValue; |
| for (size_t i = 0; i < visited_list.size(); ++i) { |
| const history::MostVisitedURL& visited = visited_list[i]; |
| if (visited.url.spec().empty()) |
| break; // This is the signal that there are no more real visited sites. |
| DictionaryValue* dict = new DictionaryValue; |
| dict->SetString("url", visited.url.spec()); |
| dict->SetString("title", visited.title); |
| dict->SetBoolean("is_pinned", top_sites_->IsURLPinned(visited.url)); |
| list_value->Append(dict); |
| } |
| ntp_info_->Set("most_visited", list_value); |
| AutomationJSONReply(automation_, reply_message_).SendSuccess(ntp_info_.get()); |
| delete this; |
| } |
| |
| AutocompleteEditFocusedObserver::AutocompleteEditFocusedObserver( |
| AutomationProvider* automation, |
| AutocompleteEditModel* autocomplete_edit, |
| IPC::Message* reply_message) |
| : automation_(automation), |
| reply_message_(reply_message), |
| autocomplete_edit_model_(autocomplete_edit) { |
| Source<AutocompleteEditModel> source(autocomplete_edit); |
| registrar_.Add(this, NotificationType::AUTOCOMPLETE_EDIT_FOCUSED, source); |
| } |
| |
| void AutocompleteEditFocusedObserver::Observe( |
| NotificationType type, |
| const NotificationSource& source, |
| const NotificationDetails& details) { |
| DCHECK(type == NotificationType::AUTOCOMPLETE_EDIT_FOCUSED); |
| AutomationMsg_WaitForAutocompleteEditFocus::WriteReplyParams( |
| reply_message_, true); |
| automation_->Send(reply_message_); |
| delete this; |
| } |
| |
| namespace { |
| |
| // Returns whether the notification's host has a non-null process handle. |
| bool IsNotificationProcessReady(Balloon* balloon) { |
| return balloon->view() && |
| balloon->view()->GetHost() && |
| balloon->view()->GetHost()->render_view_host() && |
| balloon->view()->GetHost()->render_view_host()->process()->GetHandle(); |
| } |
| |
| // Returns whether all active notifications have an associated process ID. |
| bool AreActiveNotificationProcessesReady() { |
| NotificationUIManager* manager = g_browser_process->notification_ui_manager(); |
| const BalloonCollection::Balloons& balloons = |
| manager->balloon_collection()->GetActiveBalloons(); |
| BalloonCollection::Balloons::const_iterator iter; |
| for (iter = balloons.begin(); iter != balloons.end(); ++iter) { |
| if (!IsNotificationProcessReady(*iter)) |
| return false; |
| } |
| return true; |
| } |
| |
| } // namespace |
| |
| GetActiveNotificationsObserver::GetActiveNotificationsObserver( |
| AutomationProvider* automation, |
| IPC::Message* reply_message) |
| : reply_(automation, reply_message) { |
| if (AreActiveNotificationProcessesReady()) { |
| SendMessage(); |
| } else { |
| registrar_.Add(this, NotificationType::RENDERER_PROCESS_CREATED, |
| NotificationService::AllSources()); |
| } |
| } |
| |
| void GetActiveNotificationsObserver::Observe( |
| NotificationType type, |
| const NotificationSource& source, |
| const NotificationDetails& details) { |
| if (AreActiveNotificationProcessesReady()) |
| SendMessage(); |
| } |
| |
| void GetActiveNotificationsObserver::SendMessage() { |
| NotificationUIManager* manager = |
| g_browser_process->notification_ui_manager(); |
| const BalloonCollection::Balloons& balloons = |
| manager->balloon_collection()->GetActiveBalloons(); |
| scoped_ptr<DictionaryValue> return_value(new DictionaryValue); |
| ListValue* list = new ListValue; |
| return_value->Set("notifications", list); |
| BalloonCollection::Balloons::const_iterator iter; |
| for (iter = balloons.begin(); iter != balloons.end(); ++iter) { |
| const Notification& notification = (*iter)->notification(); |
| DictionaryValue* balloon = new DictionaryValue; |
| balloon->SetString("content_url", notification.content_url().spec()); |
| balloon->SetString("origin_url", notification.origin_url().spec()); |
| balloon->SetString("display_source", notification.display_source()); |
| BalloonView* view = (*iter)->view(); |
| balloon->SetInteger("pid", base::GetProcId( |
| view->GetHost()->render_view_host()->process()->GetHandle())); |
| list->Append(balloon); |
| } |
| reply_.SendSuccess(return_value.get()); |
| delete this; |
| } |
| |
| OnNotificationBalloonCountObserver::OnNotificationBalloonCountObserver( |
| AutomationProvider* provider, |
| IPC::Message* reply_message, |
| BalloonCollection* collection, |
| int count) |
| : reply_(provider, reply_message), |
| collection_(collection), |
| count_(count) { |
| collection->set_on_collection_changed_callback(NewCallback( |
| this, &OnNotificationBalloonCountObserver::OnBalloonCollectionChanged)); |
| } |
| |
| void OnNotificationBalloonCountObserver::OnBalloonCollectionChanged() { |
| if (static_cast<int>(collection_->GetActiveBalloons().size()) == count_) { |
| collection_->set_on_collection_changed_callback(NULL); |
| reply_.SendSuccess(NULL); |
| delete this; |
| } |
| } |
| |
| RendererProcessClosedObserver::RendererProcessClosedObserver( |
| AutomationProvider* automation, |
| IPC::Message* reply_message) |
| : automation_(automation), |
| reply_message_(reply_message) { |
| registrar_.Add(this, NotificationType::RENDERER_PROCESS_CLOSED, |
| NotificationService::AllSources()); |
| } |
| |
| void RendererProcessClosedObserver::Observe( |
| NotificationType type, |
| const NotificationSource& source, |
| const NotificationDetails& details) { |
| AutomationJSONReply(automation_, reply_message_).SendSuccess(NULL); |
| delete this; |
| } |