| // Copyright (c) 2012 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/bind.h" |
| #include "base/bind_helpers.h" |
| #include "base/callback.h" |
| #include "base/file_util.h" |
| #include "base/json/json_writer.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/stl_util.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/strings/utf_string_conversions.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/bookmarks/bookmark_model_factory.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/chrome_notification_types.h" |
| #include "chrome/browser/content_settings/tab_specific_content_settings.h" |
| #include "chrome/browser/extensions/crx_installer.h" |
| #include "chrome/browser/extensions/extension_host.h" |
| #include "chrome/browser/extensions/extension_process_manager.h" |
| #include "chrome/browser/extensions/extension_service.h" |
| #include "chrome/browser/extensions/extension_system.h" |
| #include "chrome/browser/extensions/extension_tab_util.h" |
| #include "chrome/browser/history/history_types.h" |
| #include "chrome/browser/history/top_sites.h" |
| #include "chrome/browser/infobars/confirm_infobar_delegate.h" |
| #include "chrome/browser/infobars/infobar_service.h" |
| #include "chrome/browser/metrics/metric_event_duration_details.h" |
| #include "chrome/browser/notifications/balloon.h" |
| #include "chrome/browser/notifications/balloon_collection.h" |
| #include "chrome/browser/notifications/balloon_host.h" |
| #include "chrome/browser/notifications/balloon_notification_ui_manager.h" |
| #include "chrome/browser/notifications/notification.h" |
| #include "chrome/browser/password_manager/password_store_change.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/renderer_host/chrome_render_message_filter.h" |
| #include "chrome/browser/search_engines/template_url_service.h" |
| #include "chrome/browser/search_engines/template_url_service_factory.h" |
| #include "chrome/browser/sessions/session_tab_helper.h" |
| #include "chrome/browser/sessions/tab_restore_service.h" |
| #include "chrome/browser/sessions/tab_restore_service_factory.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/browser/ui/browser_iterator.h" |
| #include "chrome/browser/ui/browser_list.h" |
| #include "chrome/browser/ui/browser_window.h" |
| #include "chrome/browser/ui/find_bar/find_notification_details.h" |
| #include "chrome/browser/ui/host_desktop.h" |
| #include "chrome/browser/ui/login/login_prompt.h" |
| #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| #include "chrome/browser/ui/webui/ntp/app_launcher_handler.h" |
| #include "chrome/browser/ui/webui/ntp/most_visited_handler.h" |
| #include "chrome/browser/ui/webui/ntp/new_tab_ui.h" |
| #include "chrome/browser/ui/webui/ntp/recently_closed_tabs_handler.h" |
| #include "chrome/common/automation_constants.h" |
| #include "chrome/common/automation_messages.h" |
| #include "chrome/common/content_settings_types.h" |
| #include "chrome/common/extensions/extension.h" |
| #include "content/public/browser/dom_operation_notification_details.h" |
| #include "content/public/browser/navigation_controller.h" |
| #include "content/public/browser/notification_service.h" |
| #include "content/public/browser/render_process_host.h" |
| #include "content/public/browser/render_view_host.h" |
| #include "content/public/browser/web_contents.h" |
| #include "content/public/common/process_type.h" |
| #include "extensions/common/manifest.h" |
| #include "extensions/common/view_type.h" |
| #include "ui/gfx/codec/png_codec.h" |
| #include "ui/gfx/rect.h" |
| #include "url/gurl.h" |
| |
| using content::BrowserThread; |
| using content::DomOperationNotificationDetails; |
| using content::DownloadItem; |
| using content::DownloadManager; |
| using content::NavigationController; |
| using content::RenderViewHost; |
| using content::WebContents; |
| |
| // 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->AsWeakPtr()), |
| crashed_tab_count_(0), |
| outstanding_tab_count_(tab_count), |
| init_time_(base::TimeTicks::Now()) { |
| if (outstanding_tab_count_ > 0) { |
| registrar_.Add(this, content::NOTIFICATION_LOAD_START, |
| content::NotificationService::AllSources()); |
| registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, |
| content::NotificationService::AllSources()); |
| registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, |
| content::NotificationService::AllSources()); |
| } |
| } |
| |
| InitialLoadObserver::~InitialLoadObserver() { |
| } |
| |
| void InitialLoadObserver::Observe(int type, |
| const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| if (type == content::NOTIFICATION_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 == content::NOTIFICATION_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()); |
| } |
| } |
| } else if (type == content::NOTIFICATION_RENDERER_PROCESS_CLOSED) { |
| base::TerminationStatus status = |
| content::Details<content::RenderProcessHost::RendererClosedDetails>( |
| details)->status; |
| switch (status) { |
| case base::TERMINATION_STATUS_NORMAL_TERMINATION: |
| break; |
| |
| case base::TERMINATION_STATUS_ABNORMAL_TERMINATION: |
| case base::TERMINATION_STATUS_PROCESS_WAS_KILLED: |
| case base::TERMINATION_STATUS_PROCESS_CRASHED: |
| crashed_tab_count_++; |
| break; |
| |
| case base::TERMINATION_STATUS_STILL_RUNNING: |
| LOG(ERROR) << "Got RENDERER_PROCESS_CLOSED notification, " |
| << "but the process is still running. We may miss further " |
| << "crash notification, resulting in hangs."; |
| break; |
| |
| default: |
| LOG(ERROR) << "Unhandled termination status " << status; |
| NOTREACHED(); |
| break; |
| } |
| } else { |
| NOTREACHED(); |
| } |
| |
| if (finished_tabs_.size() + crashed_tab_count_ >= outstanding_tab_count_) |
| ConditionMet(); |
| } |
| |
| 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->SetDouble("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->SetDouble("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(); |
| if (automation_.get()) |
| automation_->OnInitialTabLoadsComplete(); |
| } |
| |
| NewTabUILoadObserver::NewTabUILoadObserver(AutomationProvider* automation, |
| Profile* profile) |
| : automation_(automation->AsWeakPtr()) { |
| registrar_.Add(this, chrome::NOTIFICATION_INITIAL_NEW_TAB_UI_LOAD, |
| content::Source<Profile>(profile)); |
| } |
| |
| NewTabUILoadObserver::~NewTabUILoadObserver() { |
| } |
| |
| void NewTabUILoadObserver::Observe(int type, |
| const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| if (type == chrome::NOTIFICATION_INITIAL_NEW_TAB_UI_LOAD) { |
| content::Details<int> load_time(details); |
| if (automation_.get()) { |
| automation_->Send( |
| new AutomationMsg_InitialNewTabUILoadComplete(*load_time.ptr())); |
| } |
| } else { |
| NOTREACHED(); |
| } |
| } |
| |
| NavigationControllerRestoredObserver::NavigationControllerRestoredObserver( |
| AutomationProvider* automation, |
| NavigationController* controller, |
| IPC::Message* reply_message) |
| : automation_(automation->AsWeakPtr()), |
| controller_(controller), |
| reply_message_(reply_message) { |
| if (FinishedRestoring()) { |
| SendDone(); |
| } else { |
| registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, |
| content::NotificationService::AllSources()); |
| } |
| } |
| |
| NavigationControllerRestoredObserver::~NavigationControllerRestoredObserver() { |
| } |
| |
| void NavigationControllerRestoredObserver::Observe( |
| int type, const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| if (FinishedRestoring()) { |
| registrar_.RemoveAll(); |
| SendDone(); |
| } |
| } |
| |
| bool NavigationControllerRestoredObserver::FinishedRestoring() { |
| return (!controller_->NeedsReload() && !controller_->GetPendingEntry() && |
| !controller_->GetWebContents()->IsLoading()); |
| } |
| |
| void NavigationControllerRestoredObserver::SendDone() { |
| if (automation_.get()) { |
| AutomationJSONReply(automation_.get(), reply_message_.release()) |
| .SendSuccess(NULL); |
| } |
| delete this; |
| } |
| |
| NavigationNotificationObserver::NavigationNotificationObserver( |
| NavigationController* controller, |
| AutomationProvider* automation, |
| IPC::Message* reply_message, |
| int number_of_navigations, |
| bool include_current_navigation, |
| bool use_json_interface) |
| : automation_(automation->AsWeakPtr()), |
| reply_message_(reply_message), |
| controller_(controller), |
| navigations_remaining_(number_of_navigations), |
| navigation_started_(false), |
| use_json_interface_(use_json_interface) { |
| if (number_of_navigations == 0) { |
| ConditionMet(AUTOMATION_MSG_NAVIGATION_SUCCESS); |
| return; |
| } |
| DCHECK_LT(0, navigations_remaining_); |
| content::Source<NavigationController> source(controller_); |
| registrar_.Add(this, content::NOTIFICATION_NAV_ENTRY_COMMITTED, source); |
| registrar_.Add(this, content::NOTIFICATION_LOAD_START, source); |
| registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, source); |
| registrar_.Add(this, chrome::NOTIFICATION_AUTH_NEEDED, source); |
| registrar_.Add(this, chrome::NOTIFICATION_AUTH_SUPPLIED, source); |
| registrar_.Add(this, chrome::NOTIFICATION_AUTH_CANCELLED, source); |
| registrar_.Add(this, chrome::NOTIFICATION_APP_MODAL_DIALOG_SHOWN, |
| content::NotificationService::AllSources()); |
| |
| if (include_current_navigation && controller->GetWebContents()->IsLoading()) |
| navigation_started_ = true; |
| } |
| |
| NavigationNotificationObserver::~NavigationNotificationObserver() { |
| } |
| |
| void NavigationNotificationObserver::Observe( |
| int type, const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| if (!automation_.get()) { |
| delete this; |
| return; |
| } |
| |
| // 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 chrome::NAV_ENTRY_COMMITTED until after we authenticate, so |
| // we need the chrome::LOAD_START. |
| if (type == content::NOTIFICATION_NAV_ENTRY_COMMITTED || |
| type == content::NOTIFICATION_LOAD_START) { |
| navigation_started_ = true; |
| } else if (type == content::NOTIFICATION_LOAD_STOP) { |
| if (navigation_started_) { |
| navigation_started_ = false; |
| if (--navigations_remaining_ == 0) |
| ConditionMet(AUTOMATION_MSG_NAVIGATION_SUCCESS); |
| } |
| } else if (type == chrome::NOTIFICATION_AUTH_SUPPLIED || |
| type == chrome::NOTIFICATION_AUTH_CANCELLED) { |
| // Treat this as if navigation started again, since load start/stop don't |
| // occur while authentication is ongoing. |
| navigation_started_ = true; |
| } else if (type == chrome::NOTIFICATION_AUTH_NEEDED) { |
| // Respond that authentication is needed. |
| navigation_started_ = false; |
| ConditionMet(AUTOMATION_MSG_NAVIGATION_AUTH_NEEDED); |
| } else if (type == chrome::NOTIFICATION_APP_MODAL_DIALOG_SHOWN) { |
| ConditionMet(AUTOMATION_MSG_NAVIGATION_BLOCKED_BY_MODAL_DIALOG); |
| } else { |
| NOTREACHED(); |
| } |
| } |
| |
| void NavigationNotificationObserver::ConditionMet( |
| AutomationMsg_NavigationResponseValues navigation_result) { |
| if (automation_.get()) { |
| if (use_json_interface_) { |
| if (navigation_result == AUTOMATION_MSG_NAVIGATION_SUCCESS) { |
| DictionaryValue dict; |
| dict.SetInteger("result", navigation_result); |
| AutomationJSONReply(automation_.get(), reply_message_.release()) |
| .SendSuccess(&dict); |
| } else { |
| AutomationJSONReply(automation_.get(), reply_message_.release()) |
| .SendError(base::StringPrintf( |
| "Navigation failed with error code=%d.", navigation_result)); |
| } |
| } else { |
| IPC::ParamTraits<int>::Write( |
| reply_message_.get(), navigation_result); |
| automation_->Send(reply_message_.release()); |
| } |
| } |
| |
| delete this; |
| } |
| |
| TabStripNotificationObserver::TabStripNotificationObserver( |
| int notification, AutomationProvider* automation) |
| : automation_(automation->AsWeakPtr()), |
| notification_(notification) { |
| registrar_.Add(this, notification_, |
| content::NotificationService::AllSources()); |
| } |
| |
| TabStripNotificationObserver::~TabStripNotificationObserver() { |
| } |
| |
| void TabStripNotificationObserver::Observe( |
| int type, |
| const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| DCHECK_EQ(notification_, type); |
| if (type == chrome::NOTIFICATION_TAB_PARENTED) { |
| ObserveTab(&content::Source<content::WebContents>(source)->GetController()); |
| } else if (type == content::NOTIFICATION_WEB_CONTENTS_DESTROYED) { |
| ObserveTab(&content::Source<content::WebContents>(source)->GetController()); |
| } else { |
| ObserveTab(content::Source<NavigationController>(source).ptr()); |
| } |
| delete this; |
| } |
| |
| TabAppendedNotificationObserver::TabAppendedNotificationObserver( |
| Browser* parent, |
| AutomationProvider* automation, |
| IPC::Message* reply_message, |
| bool use_json_interface) |
| : TabStripNotificationObserver(chrome::NOTIFICATION_TAB_PARENTED, |
| automation), |
| parent_(parent), |
| reply_message_(reply_message), |
| use_json_interface_(use_json_interface) { |
| } |
| |
| TabAppendedNotificationObserver::~TabAppendedNotificationObserver() {} |
| |
| void TabAppendedNotificationObserver::ObserveTab( |
| NavigationController* controller) { |
| if (!automation_.get() || !reply_message_.get()) |
| return; |
| |
| if (automation_->GetIndexForNavigationController(controller, parent_) == |
| TabStripModel::kNoTab) { |
| // This tab notification doesn't belong to the parent_. |
| return; |
| } |
| |
| new NavigationNotificationObserver(controller, |
| automation_.get(), |
| reply_message_.release(), |
| 1, |
| false, |
| use_json_interface_); |
| } |
| |
| IPC::Message* TabAppendedNotificationObserver::ReleaseReply() { |
| return reply_message_.release(); |
| } |
| |
| TabClosedNotificationObserver::TabClosedNotificationObserver( |
| AutomationProvider* automation, |
| bool wait_until_closed, |
| IPC::Message* reply_message, |
| bool use_json_interface) |
| : TabStripNotificationObserver((wait_until_closed ? |
| static_cast<int>(content::NOTIFICATION_WEB_CONTENTS_DESTROYED) : |
| static_cast<int>(chrome::NOTIFICATION_TAB_CLOSING)), automation), |
| reply_message_(reply_message), |
| use_json_interface_(use_json_interface), |
| for_browser_command_(false) { |
| } |
| |
| TabClosedNotificationObserver::~TabClosedNotificationObserver() {} |
| |
| void TabClosedNotificationObserver::ObserveTab( |
| NavigationController* controller) { |
| if (!automation_.get()) |
| return; |
| |
| if (use_json_interface_) { |
| AutomationJSONReply(automation_.get(), reply_message_.release()) |
| .SendSuccess(NULL); |
| } else { |
| if (for_browser_command_) { |
| AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message_.get(), |
| true); |
| } else { |
| AutomationMsg_CloseTab::WriteReplyParams(reply_message_.get(), true); |
| } |
| automation_->Send(reply_message_.release()); |
| } |
| } |
| |
| 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->AsWeakPtr()), |
| reply_message_(reply_message), |
| tab_strip_model_(browser->tab_strip_model()), |
| target_tab_count_(target_tab_count) { |
| tab_strip_model_->AddObserver(this); |
| CheckTabCount(); |
| } |
| |
| TabCountChangeObserver::~TabCountChangeObserver() { |
| tab_strip_model_->RemoveObserver(this); |
| } |
| |
| void TabCountChangeObserver::TabInsertedAt(WebContents* contents, |
| int index, |
| bool foreground) { |
| CheckTabCount(); |
| } |
| |
| void TabCountChangeObserver::TabDetachedAt(WebContents* contents, |
| int index) { |
| CheckTabCount(); |
| } |
| |
| void TabCountChangeObserver::TabStripModelDeleted() { |
| if (automation_.get()) { |
| AutomationMsg_WaitForTabCountToBecome::WriteReplyParams( |
| reply_message_.get(), false); |
| automation_->Send(reply_message_.release()); |
| } |
| |
| delete this; |
| } |
| |
| void TabCountChangeObserver::CheckTabCount() { |
| if (tab_strip_model_->count() != target_tab_count_) |
| return; |
| |
| if (automation_.get()) { |
| AutomationMsg_WaitForTabCountToBecome::WriteReplyParams( |
| reply_message_.get(), true); |
| automation_->Send(reply_message_.release()); |
| } |
| |
| delete this; |
| } |
| |
| bool DidExtensionViewsStopLoading(ExtensionProcessManager* manager) { |
| ExtensionProcessManager::ViewSet all_views = manager->GetAllViews(); |
| for (ExtensionProcessManager::ViewSet::const_iterator iter = |
| all_views.begin(); |
| iter != all_views.end(); ++iter) { |
| if ((*iter)->IsLoading()) |
| return false; |
| } |
| return true; |
| } |
| |
| ExtensionUninstallObserver::ExtensionUninstallObserver( |
| AutomationProvider* automation, |
| IPC::Message* reply_message, |
| const std::string& id) |
| : automation_(automation->AsWeakPtr()), |
| reply_message_(reply_message), |
| id_(id) { |
| registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALLED, |
| content::NotificationService::AllSources()); |
| registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNINSTALL_NOT_ALLOWED, |
| content::NotificationService::AllSources()); |
| } |
| |
| ExtensionUninstallObserver::~ExtensionUninstallObserver() { |
| } |
| |
| void ExtensionUninstallObserver::Observe( |
| int type, |
| const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| if (!automation_.get()) { |
| delete this; |
| return; |
| } |
| |
| switch (type) { |
| case chrome::NOTIFICATION_EXTENSION_UNINSTALLED: { |
| if (id_ == content::Details<extensions::Extension>(details).ptr()->id()) { |
| scoped_ptr<DictionaryValue> return_value(new DictionaryValue); |
| return_value->SetBoolean("success", true); |
| AutomationJSONReply(automation_.get(), reply_message_.release()) |
| .SendSuccess(return_value.get()); |
| delete this; |
| return; |
| } |
| break; |
| } |
| |
| case chrome::NOTIFICATION_EXTENSION_UNINSTALL_NOT_ALLOWED: { |
| const extensions::Extension* extension = |
| content::Details<extensions::Extension>(details).ptr(); |
| if (id_ == extension->id()) { |
| scoped_ptr<DictionaryValue> return_value(new DictionaryValue); |
| return_value->SetBoolean("success", false); |
| AutomationJSONReply(automation_.get(), reply_message_.release()) |
| .SendSuccess(return_value.get()); |
| delete this; |
| return; |
| } |
| break; |
| } |
| |
| default: |
| NOTREACHED(); |
| } |
| } |
| |
| ExtensionReadyNotificationObserver::ExtensionReadyNotificationObserver( |
| ExtensionProcessManager* manager, ExtensionService* service, |
| AutomationProvider* automation, IPC::Message* reply_message) |
| : manager_(manager), |
| service_(service), |
| automation_(automation->AsWeakPtr()), |
| reply_message_(reply_message), |
| extension_(NULL) { |
| Init(); |
| } |
| |
| ExtensionReadyNotificationObserver::~ExtensionReadyNotificationObserver() { |
| } |
| |
| void ExtensionReadyNotificationObserver::Init() { |
| registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, |
| content::NotificationService::AllSources()); |
| registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED, |
| content::NotificationService::AllSources()); |
| registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOAD_ERROR, |
| content::NotificationService::AllSources()); |
| registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR, |
| content::NotificationService::AllSources()); |
| registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UPDATE_DISABLED, |
| content::NotificationService::AllSources()); |
| } |
| |
| void ExtensionReadyNotificationObserver::Observe( |
| int type, const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| if (!automation_.get()) { |
| delete this; |
| return; |
| } |
| |
| switch (type) { |
| case content::NOTIFICATION_LOAD_STOP: |
| // Only continue on with this method if our extension has been loaded |
| // and all the extension views have stopped loading. |
| if (!extension_ || !DidExtensionViewsStopLoading(manager_)) |
| return; |
| break; |
| case chrome::NOTIFICATION_EXTENSION_LOADED: { |
| const extensions::Extension* loaded_extension = |
| content::Details<const extensions::Extension>(details).ptr(); |
| // Only track an internal or unpacked extension load. |
| extensions::Manifest::Location location = loaded_extension->location(); |
| if (location != extensions::Manifest::INTERNAL && |
| !extensions::Manifest::IsUnpackedLocation(location)) |
| return; |
| extension_ = loaded_extension; |
| if (!DidExtensionViewsStopLoading(manager_)) |
| return; |
| // For some reason, the background extension view is not yet |
| // created at this point so just checking whether all extension views |
| // are loaded is not sufficient. If background page is not ready, |
| // we wait for NOTIFICATION_LOAD_STOP. |
| if (!service_->IsBackgroundPageReady(extension_)) |
| return; |
| break; |
| } |
| case chrome::NOTIFICATION_EXTENSION_INSTALL_ERROR: |
| case chrome::NOTIFICATION_EXTENSION_LOAD_ERROR: |
| case chrome::NOTIFICATION_EXTENSION_UPDATE_DISABLED: |
| break; |
| default: |
| NOTREACHED(); |
| break; |
| } |
| |
| AutomationJSONReply reply(automation_.get(), reply_message_.release()); |
| if (extension_) { |
| DictionaryValue dict; |
| dict.SetString("id", extension_->id()); |
| reply.SendSuccess(&dict); |
| } else { |
| reply.SendError("Extension could not be installed"); |
| } |
| delete this; |
| } |
| |
| ExtensionUnloadNotificationObserver::ExtensionUnloadNotificationObserver() |
| : did_receive_unload_notification_(false) { |
| registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED, |
| content::NotificationService::AllSources()); |
| } |
| |
| ExtensionUnloadNotificationObserver::~ExtensionUnloadNotificationObserver() { |
| } |
| |
| void ExtensionUnloadNotificationObserver::Observe( |
| int type, const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| if (type == chrome::NOTIFICATION_EXTENSION_UNLOADED) { |
| did_receive_unload_notification_ = true; |
| } else { |
| NOTREACHED(); |
| } |
| } |
| |
| ExtensionsUpdatedObserver::ExtensionsUpdatedObserver( |
| ExtensionProcessManager* manager, AutomationProvider* automation, |
| IPC::Message* reply_message) |
| : manager_(manager), automation_(automation->AsWeakPtr()), |
| reply_message_(reply_message), updater_finished_(false) { |
| registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, |
| content::NotificationService::AllSources()); |
| } |
| |
| ExtensionsUpdatedObserver::~ExtensionsUpdatedObserver() { |
| } |
| |
| void ExtensionsUpdatedObserver::Observe( |
| int type, const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| if (!automation_.get()) { |
| delete this; |
| return; |
| } |
| |
| DCHECK(type == content::NOTIFICATION_LOAD_STOP); |
| MaybeReply(); |
| } |
| |
| void ExtensionsUpdatedObserver::UpdateCheckFinished() { |
| if (!automation_.get()) { |
| delete this; |
| return; |
| } |
| |
| // Extension updater has completed updating all extensions. |
| updater_finished_ = true; |
| MaybeReply(); |
| } |
| |
| void ExtensionsUpdatedObserver::MaybeReply() { |
| // Send the reply if (1) the extension updater has finished updating all |
| // extensions; and (2) all extension views have stopped loading. |
| if (updater_finished_ && DidExtensionViewsStopLoading(manager_)) { |
| AutomationJSONReply reply(automation_.get(), reply_message_.release()); |
| reply.SendSuccess(NULL); |
| delete this; |
| } |
| } |
| |
| BrowserOpenedNotificationObserver::BrowserOpenedNotificationObserver( |
| AutomationProvider* automation, |
| IPC::Message* reply_message, |
| bool use_json_interface) |
| : automation_(automation->AsWeakPtr()), |
| reply_message_(reply_message), |
| new_window_id_(extension_misc::kUnknownWindowId), |
| use_json_interface_(use_json_interface), |
| for_browser_command_(false) { |
| registrar_.Add(this, chrome::NOTIFICATION_BROWSER_OPENED, |
| content::NotificationService::AllBrowserContextsAndSources()); |
| registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, |
| content::NotificationService::AllBrowserContextsAndSources()); |
| } |
| |
| BrowserOpenedNotificationObserver::~BrowserOpenedNotificationObserver() { |
| } |
| |
| void BrowserOpenedNotificationObserver::Observe( |
| int type, |
| const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| if (!automation_.get()) { |
| delete this; |
| return; |
| } |
| |
| if (type == chrome::NOTIFICATION_BROWSER_OPENED) { |
| // Store the new browser ID and continue waiting for a new tab within it |
| // to stop loading. |
| new_window_id_ = ExtensionTabUtil::GetWindowId( |
| content::Source<Browser>(source).ptr()); |
| } else { |
| DCHECK_EQ(content::NOTIFICATION_LOAD_STOP, type); |
| // Only send the result if the loaded tab is in the new window. |
| NavigationController* controller = |
| content::Source<NavigationController>(source).ptr(); |
| SessionTabHelper* session_tab_helper = |
| SessionTabHelper::FromWebContents(controller->GetWebContents()); |
| int window_id = session_tab_helper ? session_tab_helper->window_id().id() |
| : -1; |
| if (window_id == new_window_id_) { |
| if (use_json_interface_) { |
| AutomationJSONReply(automation_.get(), reply_message_.release()) |
| .SendSuccess(NULL); |
| } else { |
| if (for_browser_command_) { |
| AutomationMsg_WindowExecuteCommand::WriteReplyParams( |
| reply_message_.get(), true); |
| } |
| automation_->Send(reply_message_.release()); |
| } |
| delete this; |
| return; |
| } |
| } |
| } |
| |
| 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, |
| bool use_json_interface) |
| : automation_(automation->AsWeakPtr()), |
| reply_message_(reply_message), |
| use_json_interface_(use_json_interface), |
| for_browser_command_(false) { |
| registrar_.Add(this, chrome::NOTIFICATION_BROWSER_CLOSED, |
| content::Source<Browser>(browser)); |
| } |
| |
| BrowserClosedNotificationObserver::~BrowserClosedNotificationObserver() {} |
| |
| void BrowserClosedNotificationObserver::Observe( |
| int type, const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| DCHECK_EQ(chrome::NOTIFICATION_BROWSER_CLOSED, type); |
| |
| if (!automation_.get()) { |
| delete this; |
| return; |
| } |
| |
| // The automation layer doesn't support non-native desktops. |
| int browser_count = static_cast<int>(BrowserList::GetInstance( |
| chrome::HOST_DESKTOP_TYPE_NATIVE)->size()); |
| // We get the notification before the browser is removed from the BrowserList. |
| bool app_closing = browser_count == 1; |
| |
| if (use_json_interface_) { |
| AutomationJSONReply(automation_.get(), reply_message_.release()) |
| .SendSuccess(NULL); |
| } else { |
| if (for_browser_command_) { |
| AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message_.get(), |
| true); |
| } else { |
| AutomationMsg_CloseBrowser::WriteReplyParams(reply_message_.get(), true, |
| app_closing); |
| } |
| automation_->Send(reply_message_.release()); |
| } |
| 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->AsWeakPtr()), |
| reply_message_(reply_message) { |
| registrar_.Add(this, chrome::NOTIFICATION_BROWSER_OPENED, |
| content::NotificationService::AllBrowserContextsAndSources()); |
| registrar_.Add(this, chrome::NOTIFICATION_BROWSER_CLOSED, |
| content::NotificationService::AllBrowserContextsAndSources()); |
| } |
| |
| BrowserCountChangeNotificationObserver:: |
| ~BrowserCountChangeNotificationObserver() {} |
| |
| void BrowserCountChangeNotificationObserver::Observe( |
| int type, |
| const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| DCHECK(type == chrome::NOTIFICATION_BROWSER_OPENED || |
| type == chrome::NOTIFICATION_BROWSER_CLOSED); |
| |
| // The automation layer doesn't support non-native desktops. |
| int current_count = static_cast<int>(BrowserList::GetInstance( |
| chrome::HOST_DESKTOP_TYPE_NATIVE)->size()); |
| if (type == chrome::NOTIFICATION_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 (!automation_.get()) { |
| delete this; |
| return; |
| } |
| |
| if (current_count == target_count_) { |
| AutomationMsg_WaitForBrowserWindowCountToBecome::WriteReplyParams( |
| reply_message_.get(), true); |
| automation_->Send(reply_message_.release()); |
| delete this; |
| } |
| } |
| |
| namespace { |
| |
| // Define mapping from command to notification |
| struct CommandNotification { |
| int command; |
| int notification_type; |
| }; |
| |
| const struct CommandNotification command_notifications[] = { |
| {IDC_DUPLICATE_TAB, chrome::NOTIFICATION_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, chrome::NOTIFICATION_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, content::NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED}, |
| {IDC_OPTIONS, content::NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED}, |
| {IDC_PRINT, content::NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED}, |
| {IDC_SHOW_DOWNLOADS, content::NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED}, |
| {IDC_SHOW_HISTORY, content::NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED}, |
| }; |
| |
| } // namespace |
| |
| ExecuteBrowserCommandObserver::~ExecuteBrowserCommandObserver() { |
| } |
| |
| // static |
| bool ExecuteBrowserCommandObserver::CreateAndRegisterObserver( |
| AutomationProvider* automation, |
| Browser* browser, |
| int command, |
| IPC::Message* reply_message, |
| bool use_json_interface) { |
| bool result = true; |
| switch (command) { |
| case IDC_NEW_TAB: { |
| new NewTabObserver(automation, reply_message, use_json_interface); |
| break; |
| } |
| case IDC_NEW_WINDOW: |
| case IDC_NEW_INCOGNITO_WINDOW: { |
| BrowserOpenedNotificationObserver* observer = |
| new BrowserOpenedNotificationObserver(automation, reply_message, |
| use_json_interface); |
| observer->set_for_browser_command(true); |
| break; |
| } |
| case IDC_CLOSE_WINDOW: { |
| BrowserClosedNotificationObserver* observer = |
| new BrowserClosedNotificationObserver(browser, automation, |
| reply_message, |
| use_json_interface); |
| observer->set_for_browser_command(true); |
| break; |
| } |
| case IDC_CLOSE_TAB: { |
| TabClosedNotificationObserver* observer = |
| new TabClosedNotificationObserver(automation, true, reply_message, |
| use_json_interface); |
| observer->set_for_browser_command(true); |
| break; |
| } |
| case IDC_BACK: |
| case IDC_FORWARD: |
| case IDC_RELOAD: { |
| new NavigationNotificationObserver( |
| &browser->tab_strip_model()->GetActiveWebContents()->GetController(), |
| automation, reply_message, 1, false, use_json_interface); |
| break; |
| } |
| default: { |
| ExecuteBrowserCommandObserver* observer = |
| new ExecuteBrowserCommandObserver(automation, reply_message, |
| use_json_interface); |
| if (!observer->Register(command)) { |
| observer->ReleaseReply(); |
| delete observer; |
| result = false; |
| } |
| break; |
| } |
| } |
| return result; |
| } |
| |
| void ExecuteBrowserCommandObserver::Observe( |
| int type, const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| if (type == notification_type_) { |
| if (automation_.get()) { |
| if (use_json_interface_) { |
| AutomationJSONReply(automation_.get(), reply_message_.release()) |
| .SendSuccess(NULL); |
| } else { |
| AutomationMsg_WindowExecuteCommand::WriteReplyParams( |
| reply_message_.get(), true); |
| automation_->Send(reply_message_.release()); |
| } |
| } |
| delete this; |
| } else { |
| NOTREACHED(); |
| } |
| } |
| |
| ExecuteBrowserCommandObserver::ExecuteBrowserCommandObserver( |
| AutomationProvider* automation, |
| IPC::Message* reply_message, |
| bool use_json_interface) |
| : automation_(automation->AsWeakPtr()), |
| notification_type_(content::NOTIFICATION_ALL), |
| reply_message_(reply_message), |
| use_json_interface_(use_json_interface) { |
| } |
| |
| bool ExecuteBrowserCommandObserver::Register(int command) { |
| if (!Getint(command, ¬ification_type_)) |
| return false; |
| registrar_.Add(this, notification_type_, |
| content::NotificationService::AllSources()); |
| return true; |
| } |
| |
| bool ExecuteBrowserCommandObserver::Getint( |
| int command, int* 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; |
| } |
| |
| IPC::Message* ExecuteBrowserCommandObserver::ReleaseReply() { |
| return reply_message_.release(); |
| } |
| |
| FindInPageNotificationObserver::FindInPageNotificationObserver( |
| AutomationProvider* automation, WebContents* parent_tab, |
| bool reply_with_json, IPC::Message* reply_message) |
| : automation_(automation->AsWeakPtr()), |
| active_match_ordinal_(-1), |
| reply_with_json_(reply_with_json), |
| reply_message_(reply_message) { |
| registrar_.Add(this, chrome::NOTIFICATION_FIND_RESULT_AVAILABLE, |
| content::Source<WebContents>(parent_tab)); |
| } |
| |
| FindInPageNotificationObserver::~FindInPageNotificationObserver() { |
| } |
| |
| void FindInPageNotificationObserver::Observe( |
| int type, const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| content::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; |
| } |
| |
| if (!automation_.get()) { |
| delete this; |
| 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_.get(), reply_message_.release()) |
| .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_.get(), |
| active_match_ordinal_, find_details->number_of_matches()); |
| automation_->Send(reply_message_.release()); |
| } |
| } |
| } |
| } |
| |
| // static |
| const int FindInPageNotificationObserver::kFindInPageRequestId = -1; |
| |
| DomOperationObserver::DomOperationObserver(int automation_id) |
| : automation_id_(automation_id) { |
| registrar_.Add(this, content::NOTIFICATION_DOM_OPERATION_RESPONSE, |
| content::NotificationService::AllSources()); |
| registrar_.Add(this, chrome::NOTIFICATION_APP_MODAL_DIALOG_SHOWN, |
| content::NotificationService::AllSources()); |
| registrar_.Add(this, chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED, |
| content::NotificationService::AllSources()); |
| } |
| |
| DomOperationObserver::~DomOperationObserver() {} |
| |
| void DomOperationObserver::Observe( |
| int type, const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| if (type == content::NOTIFICATION_DOM_OPERATION_RESPONSE) { |
| content::Details<DomOperationNotificationDetails> dom_op_details(details); |
| if (dom_op_details->automation_id == automation_id_) |
| OnDomOperationCompleted(dom_op_details->json); |
| } else if (type == chrome::NOTIFICATION_APP_MODAL_DIALOG_SHOWN) { |
| OnModalDialogShown(); |
| } else { |
| DCHECK_EQ(chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED, type); |
| WebContents* web_contents = content::Source<WebContents>(source).ptr(); |
| if (web_contents) { |
| TabSpecificContentSettings* tab_content_settings = |
| TabSpecificContentSettings::FromWebContents(web_contents); |
| if (tab_content_settings && |
| tab_content_settings->IsContentBlocked( |
| CONTENT_SETTINGS_TYPE_JAVASCRIPT)) |
| OnJavascriptBlocked(); |
| } |
| } |
| } |
| |
| DomOperationMessageSender::DomOperationMessageSender( |
| AutomationProvider* automation, |
| IPC::Message* reply_message, |
| bool use_json_interface) |
| : DomOperationObserver(0), |
| automation_(automation->AsWeakPtr()), |
| reply_message_(reply_message), |
| use_json_interface_(use_json_interface) { |
| } |
| |
| DomOperationMessageSender::~DomOperationMessageSender() {} |
| |
| void DomOperationMessageSender::OnDomOperationCompleted( |
| const std::string& json) { |
| if (automation_.get()) { |
| if (use_json_interface_) { |
| DictionaryValue dict; |
| dict.SetString("result", json); |
| AutomationJSONReply(automation_.get(), reply_message_.release()) |
| .SendSuccess(&dict); |
| } else { |
| AutomationMsg_DomOperation::WriteReplyParams(reply_message_.get(), json); |
| automation_->Send(reply_message_.release()); |
| } |
| } |
| delete this; |
| } |
| |
| void DomOperationMessageSender::OnModalDialogShown() { |
| if (automation_.get() && use_json_interface_) { |
| AutomationJSONReply(automation_.get(), reply_message_.release()) |
| .SendErrorCode(automation::kBlockedByModalDialog); |
| delete this; |
| } |
| } |
| |
| void DomOperationMessageSender::OnJavascriptBlocked() { |
| if (automation_.get() && use_json_interface_) { |
| AutomationJSONReply(automation_.get(), reply_message_.release()) |
| .SendError("Javascript execution was blocked"); |
| delete this; |
| } |
| } |
| |
| MetricEventDurationObserver::MetricEventDurationObserver() { |
| registrar_.Add(this, chrome::NOTIFICATION_METRIC_EVENT_DURATION, |
| content::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( |
| int type, |
| const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| if (type != chrome::NOTIFICATION_METRIC_EVENT_DURATION) { |
| NOTREACHED(); |
| return; |
| } |
| MetricEventDurationDetails* metric_event_duration = |
| content::Details<MetricEventDurationDetails>(details).ptr(); |
| durations_[metric_event_duration->event_name] = |
| metric_event_duration->duration_ms; |
| } |
| |
| InfoBarCountObserver::InfoBarCountObserver(AutomationProvider* automation, |
| IPC::Message* reply_message, |
| WebContents* web_contents, |
| size_t target_count) |
| : automation_(automation->AsWeakPtr()), |
| reply_message_(reply_message), |
| web_contents_(web_contents), |
| target_count_(target_count) { |
| content::Source<InfoBarService> source( |
| InfoBarService::FromWebContents(web_contents)); |
| registrar_.Add(this, chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_ADDED, |
| source); |
| registrar_.Add(this, chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED, |
| source); |
| CheckCount(); |
| } |
| |
| InfoBarCountObserver::~InfoBarCountObserver() {} |
| |
| void InfoBarCountObserver::Observe( |
| int type, |
| const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| DCHECK(type == chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_ADDED || |
| type == chrome::NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED); |
| CheckCount(); |
| } |
| |
| void InfoBarCountObserver::CheckCount() { |
| if (InfoBarService::FromWebContents(web_contents_)->infobar_count() != |
| target_count_) |
| return; |
| |
| if (automation_.get()) { |
| AutomationMsg_WaitForInfoBarCount::WriteReplyParams(reply_message_.get(), |
| true); |
| automation_->Send(reply_message_.release()); |
| } |
| delete this; |
| } |
| |
| AutomationProviderBookmarkModelObserver:: |
| AutomationProviderBookmarkModelObserver( |
| AutomationProvider* provider, |
| IPC::Message* reply_message, |
| BookmarkModel* model, |
| bool use_json_interface) |
| : automation_provider_(provider->AsWeakPtr()), |
| reply_message_(reply_message), |
| model_(model), |
| use_json_interface_(use_json_interface) { |
| model_->AddObserver(this); |
| } |
| |
| AutomationProviderBookmarkModelObserver:: |
| ~AutomationProviderBookmarkModelObserver() { |
| model_->RemoveObserver(this); |
| } |
| |
| void AutomationProviderBookmarkModelObserver::Loaded(BookmarkModel* model, |
| bool ids_reassigned) { |
| ReplyAndDelete(true); |
| } |
| |
| void AutomationProviderBookmarkModelObserver::BookmarkModelBeingDeleted( |
| BookmarkModel* model) { |
| ReplyAndDelete(false); |
| } |
| |
| IPC::Message* AutomationProviderBookmarkModelObserver::ReleaseReply() { |
| return reply_message_.release(); |
| } |
| |
| void AutomationProviderBookmarkModelObserver::ReplyAndDelete(bool success) { |
| if (automation_provider_.get()) { |
| if (use_json_interface_) { |
| AutomationJSONReply(automation_provider_.get(), reply_message_.release()) |
| .SendSuccess(NULL); |
| } else { |
| AutomationMsg_WaitForBookmarkModelToLoad::WriteReplyParams( |
| reply_message_.get(), success); |
| automation_provider_->Send(reply_message_.release()); |
| } |
| } |
| delete this; |
| } |
| |
| AutomationProviderDownloadUpdatedObserver:: |
| AutomationProviderDownloadUpdatedObserver( |
| AutomationProvider* provider, |
| IPC::Message* reply_message, |
| bool wait_for_open, |
| bool incognito) |
| : provider_(provider->AsWeakPtr()), |
| reply_message_(reply_message), |
| wait_for_open_(wait_for_open), |
| incognito_(incognito) { |
| } |
| |
| AutomationProviderDownloadUpdatedObserver:: |
| ~AutomationProviderDownloadUpdatedObserver() {} |
| |
| 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->GetAutoOpened()) |
| return; |
| |
| download->RemoveObserver(this); |
| |
| if (provider_.get()) { |
| scoped_ptr<DictionaryValue> return_value( |
| provider_->GetDictionaryFromDownloadItem(download, incognito_)); |
| AutomationJSONReply(provider_.get(), reply_message_.release()) |
| .SendSuccess(return_value.get()); |
| } |
| delete this; |
| } |
| |
| void AutomationProviderDownloadUpdatedObserver::OnDownloadOpened( |
| DownloadItem* download) { |
| download->RemoveObserver(this); |
| |
| if (provider_.get()) { |
| scoped_ptr<DictionaryValue> return_value( |
| provider_->GetDictionaryFromDownloadItem(download, incognito_)); |
| AutomationJSONReply(provider_.get(), reply_message_.release()) |
| .SendSuccess(return_value.get()); |
| } |
| delete this; |
| } |
| |
| AutomationProviderDownloadModelChangedObserver:: |
| AutomationProviderDownloadModelChangedObserver( |
| AutomationProvider* provider, |
| IPC::Message* reply_message, |
| DownloadManager* download_manager) |
| : provider_(provider->AsWeakPtr()), |
| reply_message_(reply_message), |
| notifier_(download_manager, this) { |
| } |
| |
| AutomationProviderDownloadModelChangedObserver:: |
| ~AutomationProviderDownloadModelChangedObserver() {} |
| |
| void AutomationProviderDownloadModelChangedObserver::ModelChanged() { |
| if (provider_.get()) |
| AutomationJSONReply(provider_.get(), reply_message_.release()) |
| .SendSuccess(NULL); |
| delete this; |
| } |
| |
| void AutomationProviderDownloadModelChangedObserver::OnDownloadCreated( |
| DownloadManager* manager, DownloadItem* item) { |
| ModelChanged(); |
| } |
| |
| void AutomationProviderDownloadModelChangedObserver::OnDownloadRemoved( |
| DownloadManager* manager, DownloadItem* item) { |
| ModelChanged(); |
| } |
| |
| AllDownloadsCompleteObserver::AllDownloadsCompleteObserver( |
| AutomationProvider* provider, |
| IPC::Message* reply_message, |
| DownloadManager* download_manager, |
| ListValue* pre_download_ids) |
| : provider_(provider->AsWeakPtr()), |
| reply_message_(reply_message), |
| download_manager_(download_manager) { |
| for (ListValue::iterator it = pre_download_ids->begin(); |
| it != pre_download_ids->end(); ++it) { |
| int val = 0; |
| if ((*it)->GetAsInteger(&val)) { |
| pre_download_ids_.insert(val); |
| } else { |
| AutomationJSONReply(provider_.get(), reply_message_.release()) |
| .SendError("Cannot convert ID of prior download to integer."); |
| delete this; |
| return; |
| } |
| } |
| download_manager_->AddObserver(this); |
| DownloadManager::DownloadVector all_items; |
| download_manager->GetAllDownloads(&all_items); |
| for (DownloadManager::DownloadVector::const_iterator |
| it = all_items.begin(); it != all_items.end(); ++it) { |
| OnDownloadCreated(download_manager_, *it); |
| } |
| ReplyIfNecessary(); |
| } |
| |
| AllDownloadsCompleteObserver::~AllDownloadsCompleteObserver() { |
| if (download_manager_) { |
| download_manager_->RemoveObserver(this); |
| download_manager_ = NULL; |
| } |
| for (std::set<DownloadItem*>::const_iterator it = pending_downloads_.begin(); |
| it != pending_downloads_.end(); ++it) { |
| (*it)->RemoveObserver(this); |
| } |
| pending_downloads_.clear(); |
| } |
| |
| void AllDownloadsCompleteObserver::ManagerGoingDown(DownloadManager* manager) { |
| DCHECK_EQ(manager, download_manager_); |
| download_manager_->RemoveObserver(this); |
| download_manager_ = NULL; |
| } |
| |
| void AllDownloadsCompleteObserver::OnDownloadCreated( |
| DownloadManager* manager, DownloadItem* item) { |
| // This method is also called in the c-tor for previously existing items. |
| if (pre_download_ids_.find(item->GetId()) == pre_download_ids_.end() && |
| item->GetState() == DownloadItem::IN_PROGRESS) { |
| item->AddObserver(this); |
| pending_downloads_.insert(item); |
| } |
| } |
| |
| void AllDownloadsCompleteObserver::OnDownloadUpdated(DownloadItem* download) { |
| // If the current download's status has changed to a final state (not state |
| // "in progress"), remove it from the pending list. |
| if (download->GetState() != DownloadItem::IN_PROGRESS) { |
| download->RemoveObserver(this); |
| pending_downloads_.erase(download); |
| ReplyIfNecessary(); |
| } |
| } |
| |
| void AllDownloadsCompleteObserver::ReplyIfNecessary() { |
| if (!pending_downloads_.empty()) |
| return; |
| |
| download_manager_->RemoveObserver(this); |
| if (provider_.get()) |
| AutomationJSONReply(provider_.get(), reply_message_.release()) |
| .SendSuccess(NULL); |
| delete this; |
| } |
| |
| AutomationProviderSearchEngineObserver::AutomationProviderSearchEngineObserver( |
| AutomationProvider* provider, |
| Profile* profile, |
| IPC::Message* reply_message) |
| : provider_(provider->AsWeakPtr()), |
| profile_(profile), |
| reply_message_(reply_message) { |
| } |
| |
| AutomationProviderSearchEngineObserver:: |
| ~AutomationProviderSearchEngineObserver() {} |
| |
| void AutomationProviderSearchEngineObserver::OnTemplateURLServiceChanged() { |
| if (provider_.get()) { |
| TemplateURLService* url_service = |
| TemplateURLServiceFactory::GetForProfile(profile_); |
| url_service->RemoveObserver(this); |
| AutomationJSONReply(provider_.get(), reply_message_.release()) |
| .SendSuccess(NULL); |
| } |
| delete this; |
| } |
| |
| AutomationProviderHistoryObserver::AutomationProviderHistoryObserver( |
| AutomationProvider* provider, |
| IPC::Message* reply_message) |
| : provider_(provider->AsWeakPtr()), |
| reply_message_(reply_message) { |
| } |
| |
| AutomationProviderHistoryObserver::~AutomationProviderHistoryObserver() {} |
| |
| void AutomationProviderHistoryObserver::HistoryQueryComplete( |
| HistoryService::Handle request_handle, |
| history::QueryResults* results) { |
| if (!provider_.get()) { |
| delete this; |
| return; |
| } |
| |
| 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->SetDouble("time", |
| static_cast<double>(page.visit_time().ToDoubleT())); |
| page_value->SetString("snippet", page.snippet().text()); |
| page_value->SetBoolean( |
| "starred", |
| BookmarkModelFactory::GetForProfile( |
| provider_->profile())->IsBookmarked(page.url())); |
| history_list->Append(page_value); |
| } |
| |
| return_value->Set("history", history_list); |
| // Return history info. |
| AutomationJSONReply reply(provider_.get(), reply_message_.release()); |
| reply.SendSuccess(return_value.get()); |
| delete this; |
| } |
| |
| AutomationProviderImportSettingsObserver:: |
| AutomationProviderImportSettingsObserver( |
| AutomationProvider* provider, |
| IPC::Message* reply_message) |
| : provider_(provider->AsWeakPtr()), |
| reply_message_(reply_message) { |
| } |
| |
| AutomationProviderImportSettingsObserver:: |
| ~AutomationProviderImportSettingsObserver() {} |
| |
| void AutomationProviderImportSettingsObserver::ImportStarted() { |
| } |
| |
| void AutomationProviderImportSettingsObserver::ImportItemStarted( |
| importer::ImportItem item) { |
| } |
| |
| void AutomationProviderImportSettingsObserver::ImportItemEnded( |
| importer::ImportItem item) { |
| } |
| |
| void AutomationProviderImportSettingsObserver::ImportEnded() { |
| if (provider_.get()) |
| AutomationJSONReply(provider_.get(), reply_message_.release()) |
| .SendSuccess(NULL); |
| delete this; |
| } |
| |
| AutomationProviderGetPasswordsObserver::AutomationProviderGetPasswordsObserver( |
| AutomationProvider* provider, |
| IPC::Message* reply_message) |
| : provider_(provider->AsWeakPtr()), |
| reply_message_(reply_message) { |
| } |
| |
| AutomationProviderGetPasswordsObserver:: |
| ~AutomationProviderGetPasswordsObserver() {} |
| |
| void AutomationProviderGetPasswordsObserver::OnPasswordStoreRequestDone( |
| CancelableRequestProvider::Handle handle, |
| const std::vector<content::PasswordForm*>& result) { |
| if (!provider_.get()) { |
| delete this; |
| return; |
| } |
| |
| scoped_ptr<DictionaryValue> return_value(new DictionaryValue); |
| |
| ListValue* passwords = new ListValue; |
| for (std::vector<content::PasswordForm*>::const_iterator it = |
| result.begin(); it != result.end(); ++it) { |
| DictionaryValue* password_val = new DictionaryValue; |
| content::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->SetDouble( |
| "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_.get(), reply_message_.release()) |
| .SendSuccess(return_value.get()); |
| delete this; |
| } |
| |
| void AutomationProviderGetPasswordsObserver::OnGetPasswordStoreResults( |
| const std::vector<content::PasswordForm*>& results) { |
| // TODO(kaiwang): Implement when I refactor |
| // PasswordManager::GetAutofillableLogins. |
| NOTIMPLEMENTED(); |
| } |
| |
| PasswordStoreLoginsChangedObserver::PasswordStoreLoginsChangedObserver( |
| AutomationProvider* automation, |
| IPC::Message* reply_message, |
| PasswordStoreChange::Type expected_type, |
| const std::string& result_key) |
| : automation_(automation->AsWeakPtr()), |
| reply_message_(reply_message), |
| expected_type_(expected_type), |
| result_key_(result_key), |
| done_event_(false, false) { |
| AddRef(); |
| } |
| |
| PasswordStoreLoginsChangedObserver::~PasswordStoreLoginsChangedObserver() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| } |
| |
| void PasswordStoreLoginsChangedObserver::Init() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| BrowserThread::PostTask( |
| BrowserThread::DB, |
| FROM_HERE, |
| base::Bind(&PasswordStoreLoginsChangedObserver::RegisterObserversTask, |
| this)); |
| done_event_.Wait(); |
| } |
| |
| void PasswordStoreLoginsChangedObserver::RegisterObserversTask() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
| registrar_.reset(new content::NotificationRegistrar); |
| registrar_->Add(this, chrome::NOTIFICATION_LOGINS_CHANGED, |
| content::NotificationService::AllSources()); |
| done_event_.Signal(); |
| } |
| |
| void PasswordStoreLoginsChangedObserver::Observe( |
| int type, |
| const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); |
| DCHECK(type == chrome::NOTIFICATION_LOGINS_CHANGED); |
| registrar_.reset(); // Must be done from the DB thread. |
| PasswordStoreChangeList* change_details = |
| content::Details<PasswordStoreChangeList>(details).ptr(); |
| if (change_details->size() != 1 || |
| change_details->front().type() != expected_type_) { |
| // Notify the UI thread that there's an error. |
| std::string error = "Unexpected password store login change details."; |
| BrowserThread::PostTask( |
| BrowserThread::UI, |
| FROM_HERE, |
| base::Bind(&PasswordStoreLoginsChangedObserver::IndicateError, this, |
| error)); |
| return; |
| } |
| |
| // Notify the UI thread that we're done listening. |
| BrowserThread::PostTask( |
| BrowserThread::UI, |
| FROM_HERE, |
| base::Bind(&PasswordStoreLoginsChangedObserver::IndicateDone, this)); |
| } |
| |
| void PasswordStoreLoginsChangedObserver::IndicateDone() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| if (automation_.get()) { |
| if (result_key_.empty()) { |
| AutomationJSONReply(automation_.get(), reply_message_.release()) |
| .SendSuccess(NULL); |
| } else { |
| scoped_ptr<DictionaryValue> return_value(new DictionaryValue); |
| return_value->SetBoolean(result_key_, true); |
| AutomationJSONReply(automation_.get(), reply_message_.release()) |
| .SendSuccess(return_value.get()); |
| } |
| } |
| Release(); |
| } |
| |
| void PasswordStoreLoginsChangedObserver::IndicateError( |
| const std::string& error) { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| if (automation_.get()) |
| AutomationJSONReply(automation_.get(), reply_message_.release()) |
| .SendError(error); |
| Release(); |
| } |
| |
| OmniboxAcceptNotificationObserver::OmniboxAcceptNotificationObserver( |
| NavigationController* controller, |
| AutomationProvider* automation, |
| IPC::Message* reply_message) |
| : automation_(automation->AsWeakPtr()), |
| reply_message_(reply_message), |
| controller_(controller) { |
| content::Source<NavigationController> source(controller_); |
| registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, source); |
| // Pages requiring auth don't send LOAD_STOP. |
| registrar_.Add(this, chrome::NOTIFICATION_AUTH_NEEDED, source); |
| } |
| |
| OmniboxAcceptNotificationObserver::~OmniboxAcceptNotificationObserver() { |
| } |
| |
| void OmniboxAcceptNotificationObserver::Observe( |
| int type, |
| const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| if (type == content::NOTIFICATION_LOAD_STOP || |
| type == chrome::NOTIFICATION_AUTH_NEEDED) { |
| if (automation_.get()) { |
| AutomationJSONReply(automation_.get(), reply_message_.release()) |
| .SendSuccess(NULL); |
| } |
| delete this; |
| } else { |
| NOTREACHED(); |
| } |
| } |
| |
| SavePackageNotificationObserver::SavePackageNotificationObserver( |
| content::DownloadManager* download_manager, |
| AutomationProvider* automation, |
| IPC::Message* reply_message) |
| : download_manager_(download_manager), |
| automation_(automation->AsWeakPtr()), |
| reply_message_(reply_message) { |
| download_manager_->AddObserver(this); |
| } |
| |
| SavePackageNotificationObserver::~SavePackageNotificationObserver() { |
| download_manager_->RemoveObserver(this); |
| } |
| |
| void SavePackageNotificationObserver::OnSavePackageSuccessfullyFinished( |
| content::DownloadManager* manager, content::DownloadItem* item) { |
| if (automation_.get()) { |
| AutomationJSONReply(automation_.get(), reply_message_.release()) |
| .SendSuccess(NULL); |
| } |
| delete this; |
| } |
| |
| void SavePackageNotificationObserver::ManagerGoingDown( |
| content::DownloadManager* manager) { |
| delete this; |
| } |
| |
| namespace { |
| |
| // Returns a vector of dictionaries containing information about installed apps, |
| // as identified from a given list of extensions. The caller takes ownership |
| // of the created vector. |
| std::vector<DictionaryValue*>* GetAppInfoFromExtensions( |
| const ExtensionSet* extensions, |
| ExtensionService* ext_service) { |
| std::vector<DictionaryValue*>* apps_list = |
| new std::vector<DictionaryValue*>(); |
| for (ExtensionSet::const_iterator ext = extensions->begin(); |
| ext != extensions->end(); ++ext) { |
| // Only return information about extensions that are actually apps. |
| if ((*ext)->is_app()) { |
| DictionaryValue* app_info = new DictionaryValue(); |
| AppLauncherHandler::CreateAppInfo(ext->get(), ext_service, app_info); |
| app_info->SetBoolean( |
| "is_component_extension", |
| (*ext)->location() == extensions::Manifest::COMPONENT); |
| |
| // Convert the launch_type integer into a more descriptive string. |
| int launch_type; |
| const char* kLaunchType = "launch_type"; |
| if (!app_info->GetInteger(kLaunchType, &launch_type)) { |
| NOTREACHED() << "Can't get integer from key " << kLaunchType; |
| continue; |
| } |
| if (launch_type == extensions::ExtensionPrefs::LAUNCH_PINNED) { |
| app_info->SetString(kLaunchType, "pinned"); |
| } else if (launch_type == extensions::ExtensionPrefs::LAUNCH_REGULAR) { |
| app_info->SetString(kLaunchType, "regular"); |
| } else if (launch_type == extensions::ExtensionPrefs::LAUNCH_FULLSCREEN) { |
| app_info->SetString(kLaunchType, "fullscreen"); |
| } else if (launch_type == extensions::ExtensionPrefs::LAUNCH_WINDOW) { |
| app_info->SetString(kLaunchType, "window"); |
| } else { |
| app_info->SetString(kLaunchType, "unknown"); |
| } |
| |
| apps_list->push_back(app_info); |
| } |
| } |
| return apps_list; |
| } |
| |
| } // namespace |
| |
| NTPInfoObserver::NTPInfoObserver(AutomationProvider* automation, |
| IPC::Message* reply_message) |
| : automation_(automation->AsWeakPtr()), |
| reply_message_(reply_message), |
| request_(0), |
| ntp_info_(new DictionaryValue) { |
| top_sites_ = automation_->profile()->GetTopSites(); |
| if (!top_sites_) { |
| AutomationJSONReply(automation_.get(), reply_message_.release()) |
| .SendError("Profile does not have service for querying the top sites."); |
| return; |
| } |
| TabRestoreService* service = |
| TabRestoreServiceFactory::GetForProfile(automation_->profile()); |
| if (!service) { |
| AutomationJSONReply(automation_.get(), reply_message_.release()) |
| .SendError("No TabRestoreService."); |
| return; |
| } |
| |
| // Collect information about the apps in the new tab page. |
| ExtensionService* ext_service = extensions::ExtensionSystem::Get( |
| automation_->profile())->extension_service(); |
| if (!ext_service) { |
| AutomationJSONReply(automation_.get(), reply_message_.release()) |
| .SendError("No ExtensionService."); |
| return; |
| } |
| // Process enabled extensions. |
| ListValue* apps_list = new ListValue(); |
| const ExtensionSet* extensions = ext_service->extensions(); |
| std::vector<DictionaryValue*>* enabled_apps = GetAppInfoFromExtensions( |
| extensions, ext_service); |
| for (std::vector<DictionaryValue*>::const_iterator app = |
| enabled_apps->begin(); app != enabled_apps->end(); ++app) { |
| (*app)->SetBoolean("is_disabled", false); |
| apps_list->Append(*app); |
| } |
| delete enabled_apps; |
| // Process disabled extensions. |
| const ExtensionSet* disabled_extensions = ext_service->disabled_extensions(); |
| std::vector<DictionaryValue*>* disabled_apps = GetAppInfoFromExtensions( |
| disabled_extensions, ext_service); |
| for (std::vector<DictionaryValue*>::const_iterator app = |
| disabled_apps->begin(); app != disabled_apps->end(); ++app) { |
| (*app)->SetBoolean("is_disabled", true); |
| apps_list->Append(*app); |
| } |
| delete disabled_apps; |
| // Process terminated extensions. |
| const ExtensionSet* terminated_extensions = |
| ext_service->terminated_extensions(); |
| std::vector<DictionaryValue*>* terminated_apps = GetAppInfoFromExtensions( |
| terminated_extensions, ext_service); |
| for (std::vector<DictionaryValue*>::const_iterator app = |
| terminated_apps->begin(); app != terminated_apps->end(); ++app) { |
| (*app)->SetBoolean("is_disabled", true); |
| apps_list->Append(*app); |
| } |
| delete terminated_apps; |
| ntp_info_->Set("apps", apps_list); |
| |
| // Get the info that would be displayed in the recently closed section. |
| ListValue* recently_closed_list = new ListValue; |
| RecentlyClosedTabsHandler::CreateRecentlyClosedValues(service->entries(), |
| recently_closed_list); |
| ntp_info_->Set("recently_closed", recently_closed_list); |
| |
| // Add default site URLs. |
| ListValue* default_sites_list = new ListValue; |
| history::MostVisitedURLList urls = top_sites_->GetPrepopulatePages(); |
| for (size_t i = 0; i < urls.size(); ++i) { |
| default_sites_list->Append(Value::CreateStringValue( |
| urls[i].url.possibly_invalid_spec())); |
| } |
| ntp_info_->Set("default_sites", default_sites_list); |
| |
| registrar_.Add(this, chrome::NOTIFICATION_TOP_SITES_UPDATED, |
| content::Source<history::TopSites>(top_sites_)); |
| if (top_sites_->loaded()) { |
| OnTopSitesLoaded(); |
| } else { |
| registrar_.Add(this, chrome::NOTIFICATION_TOP_SITES_LOADED, |
| content::Source<Profile>(automation_->profile())); |
| } |
| } |
| |
| NTPInfoObserver::~NTPInfoObserver() {} |
| |
| void NTPInfoObserver::Observe(int type, |
| const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| if (type == chrome::NOTIFICATION_TOP_SITES_LOADED) { |
| OnTopSitesLoaded(); |
| } else if (type == chrome::NOTIFICATION_TOP_SITES_UPDATED) { |
| content::Details<CancelableRequestProvider::Handle> request_details( |
| details); |
| if (request_ == *request_details.ptr()) { |
| top_sites_->GetMostVisitedURLs( |
| base::Bind(&NTPInfoObserver::OnTopSitesReceived, |
| base::Unretained(this))); |
| } |
| } |
| } |
| |
| void NTPInfoObserver::OnTopSitesLoaded() { |
| request_ = top_sites_->StartQueryForMostVisited(); |
| } |
| |
| void NTPInfoObserver::OnTopSitesReceived( |
| const history::MostVisitedURLList& visited_list) { |
| if (!automation_.get()) { |
| delete this; |
| return; |
| } |
| |
| 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); |
| list_value->Append(dict); |
| } |
| ntp_info_->Set("most_visited", list_value); |
| AutomationJSONReply(automation_.get(), reply_message_.release()) |
| .SendSuccess(ntp_info_.get()); |
| delete this; |
| } |
| |
| AppLaunchObserver::AppLaunchObserver( |
| NavigationController* controller, |
| AutomationProvider* automation, |
| IPC::Message* reply_message, |
| extension_misc::LaunchContainer launch_container) |
| : controller_(controller), |
| automation_(automation->AsWeakPtr()), |
| reply_message_(reply_message), |
| launch_container_(launch_container), |
| new_window_id_(extension_misc::kUnknownWindowId) { |
| if (launch_container_ == extension_misc::LAUNCH_TAB) { |
| // Need to wait for the currently-active tab to reload. |
| content::Source<NavigationController> source(controller_); |
| registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, source); |
| } else { |
| // Need to wait for a new tab in a new window to load. |
| registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, |
| content::NotificationService::AllSources()); |
| registrar_.Add(this, chrome::NOTIFICATION_BROWSER_WINDOW_READY, |
| content::NotificationService::AllSources()); |
| } |
| } |
| |
| AppLaunchObserver::~AppLaunchObserver() {} |
| |
| void AppLaunchObserver::Observe(int type, |
| const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| if (type == chrome::NOTIFICATION_BROWSER_WINDOW_READY) { |
| new_window_id_ = |
| ExtensionTabUtil::GetWindowId(content::Source<Browser>(source).ptr()); |
| return; |
| } |
| |
| DCHECK_EQ(content::NOTIFICATION_LOAD_STOP, type); |
| SessionTabHelper* session_tab_helper = SessionTabHelper::FromWebContents( |
| content::Source<NavigationController>(source)->GetWebContents()); |
| if ((launch_container_ == extension_misc::LAUNCH_TAB) || |
| (session_tab_helper && |
| (session_tab_helper->window_id().id() == new_window_id_))) { |
| if (automation_.get()) { |
| AutomationJSONReply(automation_.get(), reply_message_.release()) |
| .SendSuccess(NULL); |
| } |
| delete this; |
| } |
| } |
| |
| namespace { |
| |
| // Returns whether all active notifications have an associated process ID. |
| bool AreActiveNotificationProcessesReady() { |
| BalloonNotificationUIManager* manager = |
| BalloonNotificationUIManager::GetInstanceForTesting(); |
| const BalloonCollection::Balloons& balloons = |
| manager->balloon_collection()->GetActiveBalloons(); |
| BalloonCollection::Balloons::const_iterator iter; |
| for (iter = balloons.begin(); iter != balloons.end(); ++iter) { |
| BalloonHost* balloon_host = (*iter)->balloon_view()->GetHost(); |
| if (balloon_host && !balloon_host->IsRenderViewReady()) |
| return false; |
| } |
| return true; |
| } |
| |
| } // namespace |
| |
| GetAllNotificationsObserver::GetAllNotificationsObserver( |
| AutomationProvider* automation, |
| IPC::Message* reply_message) |
| : automation_(automation->AsWeakPtr()), |
| reply_message_(reply_message) { |
| if (AreActiveNotificationProcessesReady()) { |
| SendMessage(); |
| } else { |
| registrar_.Add(this, chrome::NOTIFICATION_NOTIFY_BALLOON_CONNECTED, |
| content::NotificationService::AllSources()); |
| } |
| } |
| |
| GetAllNotificationsObserver::~GetAllNotificationsObserver() {} |
| |
| void GetAllNotificationsObserver::Observe( |
| int type, |
| const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| if (!automation_.get()) { |
| delete this; |
| return; |
| } |
| if (AreActiveNotificationProcessesReady()) |
| SendMessage(); |
| } |
| |
| base::DictionaryValue* GetAllNotificationsObserver::NotificationToJson( |
| const Notification* note) { |
| DictionaryValue* dict = new base::DictionaryValue(); |
| dict->SetString("content_url", note->content_url().spec()); |
| dict->SetString("origin_url", note->origin_url().spec()); |
| dict->SetString("display_source", note->display_source()); |
| dict->SetString("id", note->notification_id()); |
| return dict; |
| } |
| |
| void GetAllNotificationsObserver::SendMessage() { |
| BalloonNotificationUIManager* manager = |
| BalloonNotificationUIManager::GetInstanceForTesting(); |
| const BalloonCollection::Balloons& balloons = |
| manager->balloon_collection()->GetActiveBalloons(); |
| DictionaryValue return_value; |
| ListValue* list = new ListValue; |
| return_value.Set("notifications", list); |
| BalloonCollection::Balloons::const_iterator balloon_iter; |
| for (balloon_iter = balloons.begin(); balloon_iter != balloons.end(); |
| ++balloon_iter) { |
| base::DictionaryValue* note = NotificationToJson( |
| &(*balloon_iter)->notification()); |
| BalloonHost* balloon_host = (*balloon_iter)->balloon_view()->GetHost(); |
| if (balloon_host) { |
| int pid = base::GetProcId(balloon_host->web_contents()-> |
| GetRenderViewHost()->GetProcess()->GetHandle()); |
| note->SetInteger("pid", pid); |
| } |
| list->Append(note); |
| } |
| std::vector<const Notification*> queued_notes; |
| manager->GetQueuedNotificationsForTesting(&queued_notes); |
| std::vector<const Notification*>::const_iterator queued_iter; |
| for (queued_iter = queued_notes.begin(); queued_iter != queued_notes.end(); |
| ++queued_iter) { |
| list->Append(NotificationToJson(*queued_iter)); |
| } |
| AutomationJSONReply(automation_.get(), reply_message_.release()) |
| .SendSuccess(&return_value); |
| delete this; |
| } |
| |
| NewNotificationBalloonObserver::NewNotificationBalloonObserver( |
| AutomationProvider* provider, |
| IPC::Message* reply_message) |
| : automation_(provider->AsWeakPtr()), |
| reply_message_(reply_message) { |
| registrar_.Add(this, chrome::NOTIFICATION_NOTIFY_BALLOON_CONNECTED, |
| content::NotificationService::AllSources()); |
| } |
| |
| NewNotificationBalloonObserver::~NewNotificationBalloonObserver() { } |
| |
| void NewNotificationBalloonObserver::Observe( |
| int type, |
| const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| if (automation_.get()) { |
| AutomationJSONReply(automation_.get(), reply_message_.release()) |
| .SendSuccess(NULL); |
| } |
| delete this; |
| } |
| |
| OnNotificationBalloonCountObserver::OnNotificationBalloonCountObserver( |
| AutomationProvider* provider, |
| IPC::Message* reply_message, |
| int count) |
| : automation_(provider->AsWeakPtr()), |
| reply_message_(reply_message), |
| collection_(BalloonNotificationUIManager::GetInstanceForTesting()-> |
| balloon_collection()), |
| count_(count) { |
| registrar_.Add(this, chrome::NOTIFICATION_NOTIFY_BALLOON_CONNECTED, |
| content::NotificationService::AllSources()); |
| collection_->set_on_collection_changed_callback( |
| base::Bind(&OnNotificationBalloonCountObserver::CheckBalloonCount, |
| base::Unretained(this))); |
| CheckBalloonCount(); |
| } |
| |
| OnNotificationBalloonCountObserver::~OnNotificationBalloonCountObserver() { |
| } |
| |
| void OnNotificationBalloonCountObserver::Observe( |
| int type, |
| const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| CheckBalloonCount(); |
| } |
| |
| void OnNotificationBalloonCountObserver::CheckBalloonCount() { |
| bool balloon_count_met = AreActiveNotificationProcessesReady() && |
| static_cast<int>(collection_->GetActiveBalloons().size()) == count_; |
| |
| if (balloon_count_met && automation_.get()) { |
| AutomationJSONReply(automation_.get(), reply_message_.release()) |
| .SendSuccess(NULL); |
| } |
| |
| if (balloon_count_met || !automation_.get()) { |
| collection_->set_on_collection_changed_callback(base::Closure()); |
| delete this; |
| } |
| } |
| |
| RendererProcessClosedObserver::RendererProcessClosedObserver( |
| AutomationProvider* automation, |
| IPC::Message* reply_message) |
| : automation_(automation->AsWeakPtr()), |
| reply_message_(reply_message) { |
| registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, |
| content::NotificationService::AllSources()); |
| } |
| |
| RendererProcessClosedObserver::~RendererProcessClosedObserver() {} |
| |
| void RendererProcessClosedObserver::Observe( |
| int type, |
| const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| if (automation_.get()) { |
| AutomationJSONReply(automation_.get(), reply_message_.release()) |
| .SendSuccess(NULL); |
| } |
| delete this; |
| } |
| |
| InputEventAckNotificationObserver::InputEventAckNotificationObserver( |
| AutomationProvider* automation, |
| IPC::Message* reply_message, |
| int event_type, |
| int count) |
| : automation_(automation->AsWeakPtr()), |
| reply_message_(reply_message), |
| event_type_(event_type), |
| count_(count) { |
| DCHECK(1 <= count); |
| registrar_.Add( |
| this, |
| content::NOTIFICATION_RENDER_WIDGET_HOST_DID_RECEIVE_INPUT_EVENT_ACK, |
| content::NotificationService::AllSources()); |
| registrar_.Add( |
| this, |
| chrome::NOTIFICATION_APP_MODAL_DIALOG_SHOWN, |
| content::NotificationService::AllSources()); |
| } |
| |
| InputEventAckNotificationObserver::~InputEventAckNotificationObserver() {} |
| |
| void InputEventAckNotificationObserver::Observe( |
| int type, |
| const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| if (type == chrome::NOTIFICATION_APP_MODAL_DIALOG_SHOWN) { |
| AutomationJSONReply(automation_.get(), reply_message_.release()) |
| .SendSuccess(NULL); |
| delete this; |
| return; |
| } |
| |
| content::Details<int> request_details(details); |
| // If the event type matches for |count_| times, replies with a JSON message. |
| if (event_type_ == *request_details.ptr()) { |
| if (--count_ == 0 && automation_.get()) { |
| AutomationJSONReply(automation_.get(), reply_message_.release()) |
| .SendSuccess(NULL); |
| delete this; |
| } |
| } else { |
| LOG(WARNING) << "Ignoring unexpected event type: " |
| << *request_details.ptr() << " (expected: " << event_type_ |
| << ")"; |
| } |
| } |
| |
| NewTabObserver::NewTabObserver(AutomationProvider* automation, |
| IPC::Message* reply_message, |
| bool use_json_interface) |
| : automation_(automation->AsWeakPtr()), |
| reply_message_(reply_message), |
| use_json_interface_(use_json_interface) { |
| // Use TAB_PARENTED to detect the new tab. |
| registrar_.Add(this, |
| chrome::NOTIFICATION_TAB_PARENTED, |
| content::NotificationService::AllSources()); |
| } |
| |
| void NewTabObserver::Observe(int type, |
| const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| DCHECK_EQ(chrome::NOTIFICATION_TAB_PARENTED, type); |
| NavigationController* controller = |
| &(content::Source<content::WebContents>(source).ptr()->GetController()); |
| if (automation_.get()) { |
| // TODO(phajdan.jr): Clean up this hack. We write the correct return type |
| // here, but don't send the message. NavigationNotificationObserver |
| // will wait properly for the load to finish, and send the message, |
| // but it will also append its own return value at the end of the reply. |
| if (!use_json_interface_) |
| AutomationMsg_WindowExecuteCommand::WriteReplyParams(reply_message_.get(), |
| true); |
| new NavigationNotificationObserver(controller, |
| automation_.get(), |
| reply_message_.release(), |
| 1, |
| false, |
| use_json_interface_); |
| } |
| delete this; |
| } |
| |
| NewTabObserver::~NewTabObserver() { |
| } |
| |
| WaitForProcessLauncherThreadToGoIdleObserver:: |
| WaitForProcessLauncherThreadToGoIdleObserver( |
| AutomationProvider* automation, IPC::Message* reply_message) |
| : automation_(automation->AsWeakPtr()), |
| reply_message_(reply_message) { |
| // Balanced in RunOnUIThread. |
| AddRef(); |
| BrowserThread::PostTask( |
| BrowserThread::PROCESS_LAUNCHER, FROM_HERE, |
| base::Bind( |
| &WaitForProcessLauncherThreadToGoIdleObserver:: |
| RunOnProcessLauncherThread, |
| this)); |
| } |
| |
| WaitForProcessLauncherThreadToGoIdleObserver:: |
| ~WaitForProcessLauncherThreadToGoIdleObserver() { |
| } |
| |
| void WaitForProcessLauncherThreadToGoIdleObserver:: |
| RunOnProcessLauncherThread() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::PROCESS_LAUNCHER)); |
| BrowserThread::PostTask( |
| BrowserThread::PROCESS_LAUNCHER, FROM_HERE, |
| base::Bind( |
| &WaitForProcessLauncherThreadToGoIdleObserver:: |
| RunOnProcessLauncherThread2, |
| this)); |
| } |
| |
| void WaitForProcessLauncherThreadToGoIdleObserver:: |
| RunOnProcessLauncherThread2() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::PROCESS_LAUNCHER)); |
| BrowserThread::PostTask( |
| BrowserThread::UI, FROM_HERE, |
| base::Bind(&WaitForProcessLauncherThreadToGoIdleObserver::RunOnUIThread, |
| this)); |
| } |
| |
| void WaitForProcessLauncherThreadToGoIdleObserver::RunOnUIThread() { |
| DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| if (automation_.get()) |
| automation_->Send(reply_message_.release()); |
| Release(); |
| } |
| |
| DragTargetDropAckNotificationObserver::DragTargetDropAckNotificationObserver( |
| AutomationProvider* automation, |
| IPC::Message* reply_message) |
| : automation_(automation->AsWeakPtr()), |
| reply_message_(reply_message) { |
| registrar_.Add( |
| this, |
| content::NOTIFICATION_RENDER_VIEW_HOST_DID_RECEIVE_DRAG_TARGET_DROP_ACK, |
| content::NotificationService::AllSources()); |
| registrar_.Add( |
| this, |
| chrome::NOTIFICATION_APP_MODAL_DIALOG_SHOWN, |
| content::NotificationService::AllSources()); |
| } |
| |
| DragTargetDropAckNotificationObserver:: |
| ~DragTargetDropAckNotificationObserver() {} |
| |
| void DragTargetDropAckNotificationObserver::Observe( |
| int type, |
| const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| if (automation_.get()) { |
| AutomationJSONReply(automation_.get(), reply_message_.release()) |
| .SendSuccess(NULL); |
| } |
| delete this; |
| } |
| |
| ProcessInfoObserver::ProcessInfoObserver( |
| AutomationProvider* automation, |
| IPC::Message* reply_message) |
| : automation_(automation->AsWeakPtr()), |
| reply_message_(reply_message) {} |
| |
| ProcessInfoObserver::~ProcessInfoObserver() {} |
| |
| void ProcessInfoObserver::OnDetailsAvailable() { |
| scoped_ptr<DictionaryValue> return_value(new DictionaryValue); |
| ListValue* browser_proc_list = new ListValue(); |
| const std::vector<ProcessData>& all_processes = processes(); |
| for (size_t index = 0; index < all_processes.size(); ++index) { |
| DictionaryValue* browser_data = new DictionaryValue(); |
| browser_data->SetString("name", all_processes[index].name); |
| browser_data->SetString("process_name", all_processes[index].process_name); |
| |
| ListValue* proc_list = new ListValue(); |
| for (ProcessMemoryInformationList::const_iterator iterator = |
| all_processes[index].processes.begin(); |
| iterator != all_processes[index].processes.end(); ++iterator) { |
| DictionaryValue* proc_data = new DictionaryValue(); |
| |
| proc_data->SetInteger("pid", iterator->pid); |
| |
| // Working set (resident) memory usage, in KBytes. |
| DictionaryValue* working_set = new DictionaryValue(); |
| working_set->SetInteger("priv", iterator->working_set.priv); |
| working_set->SetInteger("shareable", iterator->working_set.shareable); |
| working_set->SetInteger("shared", iterator->working_set.shared); |
| proc_data->Set("working_set_mem", working_set); |
| |
| // Committed (resident + paged) memory usage, in KBytes. |
| DictionaryValue* committed = new DictionaryValue(); |
| committed->SetInteger("priv", iterator->committed.priv); |
| committed->SetInteger("mapped", iterator->committed.mapped); |
| committed->SetInteger("image", iterator->committed.image); |
| proc_data->Set("committed_mem", committed); |
| |
| proc_data->SetString("version", iterator->version); |
| proc_data->SetString("product_name", iterator->product_name); |
| proc_data->SetInteger("num_processes", iterator->num_processes); |
| proc_data->SetBoolean("is_diagnostics", iterator->is_diagnostics); |
| |
| // Process type, if this is a child process of Chrome (e.g., 'plugin'). |
| std::string process_type = "Unknown"; |
| // The following condition avoids a DCHECK in debug builds when the |
| // process type passed to |GetTypeNameInEnglish| is unknown. |
| if (iterator->process_type != content::PROCESS_TYPE_UNKNOWN) { |
| process_type = |
| content::GetProcessTypeNameInEnglish(iterator->process_type); |
| } |
| proc_data->SetString("child_process_type", process_type); |
| |
| // Renderer type, if this is a renderer process. |
| std::string renderer_type = "Unknown"; |
| if (iterator->renderer_type != |
| ProcessMemoryInformation::RENDERER_UNKNOWN) { |
| renderer_type = ProcessMemoryInformation::GetRendererTypeNameInEnglish( |
| iterator->renderer_type); |
| } |
| proc_data->SetString("renderer_type", renderer_type); |
| |
| // Titles associated with this process. |
| ListValue* titles = new ListValue(); |
| for (size_t title_index = 0; title_index < iterator->titles.size(); |
| ++title_index) |
| titles->Append(Value::CreateStringValue(iterator->titles[title_index])); |
| proc_data->Set("titles", titles); |
| |
| proc_list->Append(proc_data); |
| } |
| browser_data->Set("processes", proc_list); |
| |
| browser_proc_list->Append(browser_data); |
| } |
| return_value->Set("browsers", browser_proc_list); |
| |
| if (automation_.get()) { |
| AutomationJSONReply(automation_.get(), reply_message_.release()) |
| .SendSuccess(return_value.get()); |
| } |
| } |
| |
| V8HeapStatsObserver::V8HeapStatsObserver( |
| AutomationProvider* automation, |
| IPC::Message* reply_message, |
| base::ProcessId renderer_id) |
| : automation_(automation->AsWeakPtr()), |
| reply_message_(reply_message), |
| renderer_id_(renderer_id) { |
| registrar_.Add( |
| this, |
| chrome::NOTIFICATION_RENDERER_V8_HEAP_STATS_COMPUTED, |
| content::NotificationService::AllSources()); |
| } |
| |
| V8HeapStatsObserver::~V8HeapStatsObserver() {} |
| |
| void V8HeapStatsObserver::Observe( |
| int type, |
| const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| DCHECK(type == chrome::NOTIFICATION_RENDERER_V8_HEAP_STATS_COMPUTED); |
| |
| base::ProcessId updated_renderer_id = |
| *(content::Source<base::ProcessId>(source).ptr()); |
| // Only return information for the renderer ID we're interested in. |
| if (renderer_id_ != updated_renderer_id) |
| return; |
| |
| ChromeRenderMessageFilter::V8HeapStatsDetails* v8_heap_details = |
| content::Details<ChromeRenderMessageFilter::V8HeapStatsDetails>(details) |
| .ptr(); |
| scoped_ptr<DictionaryValue> return_value(new DictionaryValue); |
| return_value->SetInteger("renderer_id", updated_renderer_id); |
| return_value->SetInteger("v8_memory_allocated", |
| v8_heap_details->v8_memory_allocated()); |
| return_value->SetInteger("v8_memory_used", |
| v8_heap_details->v8_memory_used()); |
| |
| if (automation_.get()) { |
| AutomationJSONReply(automation_.get(), reply_message_.release()) |
| .SendSuccess(return_value.get()); |
| } |
| delete this; |
| } |
| |
| FPSObserver::FPSObserver( |
| AutomationProvider* automation, |
| IPC::Message* reply_message, |
| base::ProcessId renderer_id, |
| int routing_id) |
| : automation_(automation->AsWeakPtr()), |
| reply_message_(reply_message), |
| renderer_id_(renderer_id), |
| routing_id_(routing_id) { |
| registrar_.Add( |
| this, |
| chrome::NOTIFICATION_RENDERER_FPS_COMPUTED, |
| content::NotificationService::AllSources()); |
| } |
| |
| FPSObserver::~FPSObserver() {} |
| |
| void FPSObserver::Observe( |
| int type, |
| const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| DCHECK(type == chrome::NOTIFICATION_RENDERER_FPS_COMPUTED); |
| |
| base::ProcessId updated_renderer_id = |
| *(content::Source<base::ProcessId>(source).ptr()); |
| // Only return information for the renderer ID we're interested in. |
| if (renderer_id_ != updated_renderer_id) |
| return; |
| |
| ChromeRenderMessageFilter::FPSDetails* fps_details = |
| content::Details<ChromeRenderMessageFilter::FPSDetails>(details).ptr(); |
| // Only return information for the routing id of the host render view we're |
| // interested in. |
| if (routing_id_ != fps_details->routing_id()) |
| return; |
| |
| scoped_ptr<DictionaryValue> return_value(new DictionaryValue); |
| return_value->SetInteger("renderer_id", updated_renderer_id); |
| return_value->SetInteger("routing_id", fps_details->routing_id()); |
| return_value->SetDouble("fps", fps_details->fps()); |
| if (automation_.get()) { |
| AutomationJSONReply(automation_.get(), reply_message_.release()) |
| .SendSuccess(return_value.get()); |
| } |
| delete this; |
| } |
| |
| BrowserOpenedWithNewProfileNotificationObserver:: |
| BrowserOpenedWithNewProfileNotificationObserver( |
| AutomationProvider* automation, |
| IPC::Message* reply_message) |
| : automation_(automation->AsWeakPtr()), |
| reply_message_(reply_message), |
| new_window_id_(extension_misc::kUnknownWindowId) { |
| registrar_.Add(this, chrome::NOTIFICATION_PROFILE_CREATED, |
| content::NotificationService::AllBrowserContextsAndSources()); |
| registrar_.Add(this, chrome::NOTIFICATION_BROWSER_OPENED, |
| content::NotificationService::AllBrowserContextsAndSources()); |
| registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, |
| content::NotificationService::AllBrowserContextsAndSources()); |
| } |
| |
| BrowserOpenedWithNewProfileNotificationObserver:: |
| ~BrowserOpenedWithNewProfileNotificationObserver() { |
| } |
| |
| void BrowserOpenedWithNewProfileNotificationObserver::Observe( |
| int type, |
| const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| if (!automation_.get()) { |
| delete this; |
| return; |
| } |
| |
| if (type == chrome::NOTIFICATION_PROFILE_CREATED) { |
| // As part of multi-profile creation, a new browser window will |
| // automatically be opened. |
| Profile* profile = content::Source<Profile>(source).ptr(); |
| if (!profile) { |
| AutomationJSONReply(automation_.get(), reply_message_.release()) |
| .SendError("Profile could not be created."); |
| return; |
| } |
| } else if (type == chrome::NOTIFICATION_BROWSER_OPENED) { |
| // Store the new browser ID and continue waiting for a new tab within it |
| // to stop loading. |
| new_window_id_ = ExtensionTabUtil::GetWindowId( |
| content::Source<Browser>(source).ptr()); |
| } else { |
| DCHECK_EQ(content::NOTIFICATION_LOAD_STOP, type); |
| // Only send the result if the loaded tab is in the new window. |
| NavigationController* controller = |
| content::Source<NavigationController>(source).ptr(); |
| SessionTabHelper* session_tab_helper = |
| SessionTabHelper::FromWebContents(controller->GetWebContents()); |
| int window_id = session_tab_helper ? session_tab_helper->window_id().id() |
| : -1; |
| if (window_id == new_window_id_) { |
| if (automation_.get()) { |
| AutomationJSONReply(automation_.get(), reply_message_.release()) |
| .SendSuccess(NULL); |
| } |
| delete this; |
| } |
| } |
| } |
| |
| ExtensionPopupObserver::ExtensionPopupObserver( |
| AutomationProvider* automation, |
| IPC::Message* reply_message, |
| const std::string& extension_id) |
| : automation_(automation->AsWeakPtr()), |
| reply_message_(reply_message), |
| extension_id_(extension_id) { |
| registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING, |
| content::NotificationService::AllSources()); |
| } |
| |
| ExtensionPopupObserver::~ExtensionPopupObserver() { |
| } |
| |
| void ExtensionPopupObserver::Observe( |
| int type, |
| const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| if (!automation_.get()) { |
| delete this; |
| return; |
| } |
| |
| extensions::ExtensionHost* host = |
| content::Details<extensions::ExtensionHost>(details).ptr(); |
| if (host->extension_id() == extension_id_ && |
| host->extension_host_type() == extensions::VIEW_TYPE_EXTENSION_POPUP) { |
| AutomationJSONReply(automation_.get(), reply_message_.release()) |
| .SendSuccess(NULL); |
| delete this; |
| } |
| } |
| |
| #if defined(OS_LINUX) |
| WindowMaximizedObserver::WindowMaximizedObserver( |
| AutomationProvider* automation, |
| IPC::Message* reply_message) |
| : automation_(automation->AsWeakPtr()), |
| reply_message_(reply_message) { |
| registrar_.Add(this, chrome::NOTIFICATION_BROWSER_WINDOW_MAXIMIZED, |
| content::NotificationService::AllSources()); |
| } |
| |
| WindowMaximizedObserver::~WindowMaximizedObserver() {} |
| |
| void WindowMaximizedObserver::Observe( |
| int type, |
| const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| DCHECK_EQ(chrome::NOTIFICATION_BROWSER_WINDOW_MAXIMIZED, type); |
| |
| if (automation_.get()) { |
| AutomationJSONReply(automation_.get(), reply_message_.release()) |
| .SendSuccess(NULL); |
| } |
| delete this; |
| } |
| #endif // defined(OS_LINUX) |
| |
| BrowserOpenedWithExistingProfileNotificationObserver:: |
| BrowserOpenedWithExistingProfileNotificationObserver( |
| AutomationProvider* automation, |
| IPC::Message* reply_message, |
| int num_loads) |
| : automation_(automation->AsWeakPtr()), |
| reply_message_(reply_message), |
| new_window_id_(extension_misc::kUnknownWindowId), |
| num_loads_(num_loads) { |
| registrar_.Add(this, chrome::NOTIFICATION_BROWSER_OPENED, |
| content::NotificationService::AllBrowserContextsAndSources()); |
| registrar_.Add(this, content::NOTIFICATION_LOAD_STOP, |
| content::NotificationService::AllBrowserContextsAndSources()); |
| } |
| |
| BrowserOpenedWithExistingProfileNotificationObserver:: |
| ~BrowserOpenedWithExistingProfileNotificationObserver() { |
| } |
| |
| void BrowserOpenedWithExistingProfileNotificationObserver::Observe( |
| int type, |
| const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| if (!automation_.get()) { |
| delete this; |
| return; |
| } |
| |
| if (type == chrome::NOTIFICATION_BROWSER_OPENED) { |
| // Store the new browser ID and continue waiting for NOTIFICATION_LOAD_STOP. |
| new_window_id_ = ExtensionTabUtil::GetWindowId( |
| content::Source<Browser>(source).ptr()); |
| } else if (type == content::NOTIFICATION_LOAD_STOP) { |
| // Only consider if the loaded tab is in the new window. |
| NavigationController* controller = |
| content::Source<NavigationController>(source).ptr(); |
| SessionTabHelper* session_tab_helper = |
| SessionTabHelper::FromWebContents(controller->GetWebContents()); |
| int window_id = session_tab_helper ? session_tab_helper->window_id().id() |
| : -1; |
| if (window_id == new_window_id_ && --num_loads_ == 0) { |
| if (automation_.get()) { |
| AutomationJSONReply(automation_.get(), reply_message_.release()) |
| .SendSuccess(NULL); |
| } |
| delete this; |
| } |
| } else { |
| NOTREACHED(); |
| } |
| } |