// 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/extensions/extension_tab_helper.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/webstore_inline_installer.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/sessions/restore_tab_helper.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" #include "chrome/common/chrome_notification_types.h" #include "chrome/common/extensions/extension_action.h" #include "chrome/common/extensions/extension_icon_set.h" #include "chrome/common/extensions/extension_messages.h" #include "chrome/common/extensions/extension_resource.h" #include "content/browser/renderer_host/render_view_host.h" #include "content/public/browser/invalidate_type.h" #include "content/public/browser/navigation_details.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_widget_host_view.h" #include "content/public/browser/web_contents.h" using content::WebContents; ExtensionTabHelper::ExtensionTabHelper(TabContentsWrapper* wrapper) : content::WebContentsObserver(wrapper->web_contents()), delegate_(NULL), extension_app_(NULL), ALLOW_THIS_IN_INITIALIZER_LIST( extension_function_dispatcher_(wrapper->profile(), this)), wrapper_(wrapper) { } ExtensionTabHelper::~ExtensionTabHelper() { } void ExtensionTabHelper::CopyStateFrom(const ExtensionTabHelper& source) { SetExtensionApp(source.extension_app()); extension_app_icon_ = source.extension_app_icon_; } void ExtensionTabHelper::PageActionStateChanged() { web_contents()->NotifyNavigationStateChanged( content::INVALIDATE_TYPE_PAGE_ACTIONS); } void ExtensionTabHelper::GetApplicationInfo(int32 page_id) { Send(new ExtensionMsg_GetApplicationInfo(routing_id(), page_id)); } void ExtensionTabHelper::SetExtensionApp(const Extension* extension) { DCHECK(!extension || extension->GetFullLaunchURL().is_valid()); extension_app_ = extension; UpdateExtensionAppIcon(extension_app_); content::NotificationService::current()->Notify( chrome::NOTIFICATION_TAB_CONTENTS_APPLICATION_EXTENSION_CHANGED, content::Source(this), content::NotificationService::NoDetails()); } void ExtensionTabHelper::SetExtensionAppById( const std::string& extension_app_id) { if (extension_app_id.empty()) return; Profile* profile = Profile::FromBrowserContext(web_contents()->GetBrowserContext()); ExtensionService* extension_service = profile->GetExtensionService(); if (!extension_service || !extension_service->is_ready()) return; const Extension* extension = extension_service->GetExtensionById(extension_app_id, false); if (extension) SetExtensionApp(extension); } SkBitmap* ExtensionTabHelper::GetExtensionAppIcon() { if (extension_app_icon_.empty()) return NULL; return &extension_app_icon_; } void ExtensionTabHelper::DidNavigateMainFrame( const content::LoadCommittedDetails& details, const content::FrameNavigateParams& params) { if (details.is_in_page) return; Profile* profile = Profile::FromBrowserContext(web_contents()->GetBrowserContext()); ExtensionService* service = profile->GetExtensionService(); if (!service) return; for (ExtensionSet::const_iterator it = service->extensions()->begin(); it != service->extensions()->end(); ++it) { ExtensionAction* browser_action = (*it)->browser_action(); if (browser_action) { browser_action->ClearAllValuesForTab( wrapper_->restore_tab_helper()->session_id().id()); content::NotificationService::current()->Notify( chrome::NOTIFICATION_EXTENSION_BROWSER_ACTION_UPDATED, content::Source(browser_action), content::NotificationService::NoDetails()); } ExtensionAction* page_action = (*it)->page_action(); if (page_action) { page_action->ClearAllValuesForTab( wrapper_->restore_tab_helper()->session_id().id()); PageActionStateChanged(); } } } bool ExtensionTabHelper::OnMessageReceived(const IPC::Message& message) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(ExtensionTabHelper, message) IPC_MESSAGE_HANDLER(ExtensionHostMsg_DidGetApplicationInfo, OnDidGetApplicationInfo) IPC_MESSAGE_HANDLER(ExtensionHostMsg_InstallApplication, OnInstallApplication) IPC_MESSAGE_HANDLER(ExtensionHostMsg_InlineWebstoreInstall, OnInlineWebstoreInstall) IPC_MESSAGE_HANDLER(ExtensionHostMsg_GetAppNotifyChannel, OnGetAppNotifyChannel) IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; } void ExtensionTabHelper::OnDidGetApplicationInfo( int32 page_id, const WebApplicationInfo& info) { web_app_info_ = info; if (delegate_) delegate_->OnDidGetApplicationInfo(wrapper_, page_id); } void ExtensionTabHelper::OnInstallApplication(const WebApplicationInfo& info) { if (delegate_) delegate_->OnInstallApplication(wrapper_, info); } void ExtensionTabHelper::OnInlineWebstoreInstall( int install_id, int return_route_id, const std::string& webstore_item_id, const GURL& requestor_url) { scoped_refptr installer(new WebstoreInlineInstaller( web_contents(), install_id, return_route_id, webstore_item_id, requestor_url, this)); installer->BeginInstall(); } void ExtensionTabHelper::OnGetAppNotifyChannel( const GURL& requestor_url, const std::string& client_id, int return_route_id, int callback_id) { // Check for permission first. Profile* profile = Profile::FromBrowserContext(web_contents()->GetBrowserContext()); ExtensionService* extension_service = profile->GetExtensionService(); extensions::ProcessMap* process_map = extension_service->process_map(); content::RenderProcessHost* process = tab_contents_wrapper()->web_contents()->GetRenderProcessHost(); const Extension* extension = extension_service->GetInstalledApp(requestor_url); bool allowed = extension && extension->HasAPIPermission( ExtensionAPIPermission::kAppNotifications) && process_map->Contains(extension->id(), process->GetID()); if (!allowed) { Send(new ExtensionMsg_GetAppNotifyChannelResponse( return_route_id, "", "permission_error", callback_id)); return; } AppNotifyChannelUI* ui = new AppNotifyChannelUIImpl( GetBrowser(), tab_contents_wrapper(), extension->name()); scoped_refptr channel_setup( new AppNotifyChannelSetup(profile, extension->id(), client_id, requestor_url, return_route_id, callback_id, ui, this->AsWeakPtr())); channel_setup->Start(); // We'll get called back in AppNotifyChannelSetupComplete. } void ExtensionTabHelper::AppNotifyChannelSetupComplete( const std::string& channel_id, const std::string& error, const AppNotifyChannelSetup* setup) { CHECK(setup); // If the setup was successful, record that fact in ExtensionService. if (!channel_id.empty() && error.empty()) { Profile* profile = Profile::FromBrowserContext(web_contents()->GetBrowserContext()); ExtensionService* service = profile->GetExtensionService(); if (service->GetExtensionById(setup->extension_id(), true)) service->SetAppNotificationSetupDone(setup->extension_id(), setup->client_id()); } Send(new ExtensionMsg_GetAppNotifyChannelResponse( setup->return_route_id(), channel_id, error, setup->callback_id())); } void ExtensionTabHelper::OnRequest( const ExtensionHostMsg_Request_Params& request) { extension_function_dispatcher_.Dispatch(request, web_contents()->GetRenderViewHost()); } void ExtensionTabHelper::UpdateExtensionAppIcon(const Extension* extension) { extension_app_icon_.reset(); if (extension) { extension_app_image_loader_.reset(new ImageLoadingTracker(this)); extension_app_image_loader_->LoadImage( extension, extension->GetIconResource(Extension::EXTENSION_ICON_SMALLISH, ExtensionIconSet::MATCH_EXACTLY), gfx::Size(Extension::EXTENSION_ICON_SMALLISH, Extension::EXTENSION_ICON_SMALLISH), ImageLoadingTracker::CACHE); } else { extension_app_image_loader_.reset(NULL); } } void ExtensionTabHelper::SetAppIcon(const SkBitmap& app_icon) { extension_app_icon_ = app_icon; web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TITLE); } void ExtensionTabHelper::OnImageLoaded(SkBitmap* image, const ExtensionResource& resource, int index) { if (image) { extension_app_icon_ = *image; web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TAB); } } Browser* ExtensionTabHelper::GetBrowser() { content::WebContents* contents = web_contents(); TabContentsIterator tab_iterator; for (; !tab_iterator.done(); ++tab_iterator) { if (contents == (*tab_iterator)->web_contents()) return tab_iterator.browser(); } return NULL; } void ExtensionTabHelper::OnInlineInstallSuccess(int install_id, int return_route_id) { Send(new ExtensionMsg_InlineWebstoreInstallResponse( return_route_id, install_id, true, "")); } void ExtensionTabHelper::OnInlineInstallFailure(int install_id, int return_route_id, const std::string& error) { Send(new ExtensionMsg_InlineWebstoreInstallResponse( return_route_id, install_id, false, error)); } WebContents* ExtensionTabHelper::GetAssociatedWebContents() const { return web_contents(); }