| // 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<int>(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()); |
| } |