// Copyright 2013 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/api/tabs/ash_panel_contents.h" #include "base/values.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/extensions/api/tabs/tabs_constants.h" #include "chrome/browser/extensions/api/tabs/tabs_windows_api.h" #include "chrome/browser/extensions/api/tabs/windows_event_router.h" #include "chrome/browser/extensions/extension_tab_util.h" #include "chrome/browser/extensions/window_controller_list.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/sessions/session_tab_helper.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/site_instance.h" #include "content/public/browser/web_contents.h" #include "extensions/browser/app_window/native_app_window.h" #include "extensions/common/extension.h" #include "extensions/common/extension_messages.h" #include "ui/gfx/image/image.h" using extensions::AppWindow; using extensions::NativeAppWindow; // AshPanelWindowController ---------------------------------------------------- // This class enables an AppWindow instance to be accessed (to a limited // extent) via the chrome.windows and chrome.tabs API. This is a temporary // bridge to support instantiating AppWindows from v1 apps, specifically // for creating Panels in Ash. See crbug.com/160645. class AshPanelWindowController : public extensions::WindowController { public: AshPanelWindowController(AppWindow* window, Profile* profile); virtual ~AshPanelWindowController(); void NativeWindowChanged(); // Overridden from extensions::WindowController. virtual int GetWindowId() const override; virtual std::string GetWindowTypeText() const override; virtual base::DictionaryValue* CreateWindowValueWithTabs( const extensions::Extension* extension) const override; virtual base::DictionaryValue* CreateTabValue( const extensions::Extension* extension, int tab_index) const override; virtual bool CanClose(Reason* reason) const override; virtual void SetFullscreenMode(bool is_fullscreen, const GURL& extension_url) const override; virtual bool IsVisibleToExtension( const extensions::Extension* extension) const override; private: AppWindow* app_window_; // Weak pointer; this is owned by app_window_ bool is_active_; DISALLOW_COPY_AND_ASSIGN(AshPanelWindowController); }; AshPanelWindowController::AshPanelWindowController(AppWindow* app_window, Profile* profile) : extensions::WindowController(app_window->GetBaseWindow(), profile), app_window_(app_window), is_active_(app_window->GetBaseWindow()->IsActive()) { extensions::WindowControllerList::GetInstance()->AddExtensionWindow(this); } AshPanelWindowController::~AshPanelWindowController() { extensions::WindowControllerList::GetInstance()->RemoveExtensionWindow(this); } int AshPanelWindowController::GetWindowId() const { return static_cast(app_window_->session_id().id()); } std::string AshPanelWindowController::GetWindowTypeText() const { return extensions::tabs_constants::kWindowTypeValuePanel; } base::DictionaryValue* AshPanelWindowController::CreateWindowValueWithTabs( const extensions::Extension* extension) const { DCHECK(IsVisibleToExtension(extension)); base::DictionaryValue* result = CreateWindowValue(); base::DictionaryValue* tab_value = CreateTabValue(extension, 0); if (tab_value) { base::ListValue* tab_list = new base::ListValue(); tab_list->Append(tab_value); result->Set(extensions::tabs_constants::kTabsKey, tab_list); } return result; } base::DictionaryValue* AshPanelWindowController::CreateTabValue( const extensions::Extension* extension, int tab_index) const { if ((extension && !IsVisibleToExtension(extension)) || (tab_index > 0)) { return NULL; } content::WebContents* web_contents = app_window_->web_contents(); if (!web_contents) return NULL; base::DictionaryValue* tab_value = new base::DictionaryValue(); tab_value->SetInteger(extensions::tabs_constants::kIdKey, SessionTabHelper::IdForTab(web_contents)); tab_value->SetInteger(extensions::tabs_constants::kIndexKey, 0); const int window_id = GetWindowId(); tab_value->SetInteger(extensions::tabs_constants::kWindowIdKey, window_id); tab_value->SetString( extensions::tabs_constants::kUrlKey, web_contents->GetURL().spec()); tab_value->SetString( extensions::tabs_constants::kStatusKey, extensions::ExtensionTabUtil::GetTabStatusText( web_contents->IsLoading())); tab_value->SetBoolean(extensions::tabs_constants::kActiveKey, app_window_->GetBaseWindow()->IsActive()); // AppWindow only ever contains one tab, so that tab is always effectively // selcted and highlighted (for purposes of the chrome.tabs API). tab_value->SetInteger(extensions::tabs_constants::kWindowIdKey, window_id); tab_value->SetInteger(extensions::tabs_constants::kIdKey, window_id); tab_value->SetBoolean(extensions::tabs_constants::kSelectedKey, true); tab_value->SetBoolean(extensions::tabs_constants::kHighlightedKey, true); tab_value->SetBoolean(extensions::tabs_constants::kPinnedKey, false); tab_value->SetString( extensions::tabs_constants::kTitleKey, web_contents->GetTitle()); tab_value->SetBoolean( extensions::tabs_constants::kIncognitoKey, web_contents->GetBrowserContext()->IsOffTheRecord()); return tab_value; } bool AshPanelWindowController::CanClose(Reason* reason) const { return true; } void AshPanelWindowController::SetFullscreenMode( bool is_fullscreen, const GURL& extension_url) const { // Do nothing. Panels cannot be fullscreen. } bool AshPanelWindowController::IsVisibleToExtension( const extensions::Extension* extension) const { return extension->id() == app_window_->extension_id(); } void AshPanelWindowController::NativeWindowChanged() { bool active = app_window_->GetBaseWindow()->IsActive(); if (active == is_active_) return; is_active_ = active; // Let the extension API know that the active window changed. extensions::TabsWindowsAPI* tabs_windows_api = extensions::TabsWindowsAPI::Get(profile()); if (!tabs_windows_api) return; tabs_windows_api->windows_event_router()->OnActiveWindowChanged( active ? this : NULL); } // AshPanelContents ----------------------------------------------------- AshPanelContents::AshPanelContents(AppWindow* host) : host_(host) {} AshPanelContents::~AshPanelContents() { } void AshPanelContents::Initialize(content::BrowserContext* context, const GURL& url) { url_ = url; extension_function_dispatcher_.reset( new extensions::ExtensionFunctionDispatcher(context, this)); web_contents_.reset( content::WebContents::Create(content::WebContents::CreateParams( context, content::SiteInstance::CreateForURL(context, url_)))); // Needed to give the web contents a Window ID. Extension APIs expect web // contents to have a Window ID. Also required for FaviconTabHelper to // correctly set the window icon and title. SessionTabHelper::CreateForWebContents(web_contents_.get()); SessionTabHelper::FromWebContents(web_contents_.get())->SetWindowID( host_->session_id()); // Responsible for loading favicons for the Launcher, which uses different // logic than the FaviconTabHelper associated with web_contents_ // (instantiated in AppWindow::Init()) launcher_favicon_loader_.reset( new LauncherFaviconLoader(this, web_contents_.get())); content::WebContentsObserver::Observe(web_contents_.get()); } void AshPanelContents::LoadContents(int32 creator_process_id) { // This must be created after the native window has been created. window_controller_.reset(new AshPanelWindowController( host_, Profile::FromBrowserContext(host_->browser_context()))); web_contents_->GetController().LoadURL( url_, content::Referrer(), ui::PAGE_TRANSITION_LINK, std::string()); } void AshPanelContents::NativeWindowChanged(NativeAppWindow* native_app_window) { if (window_controller_) window_controller_->NativeWindowChanged(); } void AshPanelContents::NativeWindowClosed() { } void AshPanelContents::DispatchWindowShownForTests() const { } content::WebContents* AshPanelContents::GetWebContents() const { return web_contents_.get(); } void AshPanelContents::FaviconUpdated() { gfx::Image new_image = gfx::Image::CreateFrom1xBitmap( launcher_favicon_loader_->GetFavicon()); host_->UpdateAppIcon(new_image); } bool AshPanelContents::OnMessageReceived(const IPC::Message& message) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(AshPanelContents, message) IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; } extensions::WindowController* AshPanelContents::GetExtensionWindowController() const { return window_controller_.get(); } content::WebContents* AshPanelContents::GetAssociatedWebContents() const { return web_contents_.get(); } void AshPanelContents::OnRequest( const ExtensionHostMsg_Request_Params& params) { extension_function_dispatcher_->Dispatch( params, web_contents_->GetRenderViewHost()); }