1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/extensions/api/tabs/ash_panel_contents.h"
7 #include "base/values.h"
8 #include "chrome/browser/chrome_notification_types.h"
9 #include "chrome/browser/extensions/api/tabs/tabs_constants.h"
10 #include "chrome/browser/extensions/api/tabs/tabs_windows_api.h"
11 #include "chrome/browser/extensions/api/tabs/windows_event_router.h"
12 #include "chrome/browser/extensions/extension_tab_util.h"
13 #include "chrome/browser/extensions/window_controller_list.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/sessions/session_tab_helper.h"
16 #include "content/public/browser/browser_context.h"
17 #include "content/public/browser/site_instance.h"
18 #include "content/public/browser/web_contents.h"
19 #include "extensions/browser/app_window/native_app_window.h"
20 #include "extensions/common/extension.h"
21 #include "extensions/common/extension_messages.h"
22 #include "ui/gfx/image/image.h"
24 using extensions::AppWindow;
25 using extensions::NativeAppWindow;
27 // AshPanelWindowController ----------------------------------------------------
29 // This class enables an AppWindow instance to be accessed (to a limited
30 // extent) via the chrome.windows and chrome.tabs API. This is a temporary
31 // bridge to support instantiating AppWindows from v1 apps, specifically
32 // for creating Panels in Ash. See crbug.com/160645.
33 class AshPanelWindowController : public extensions::WindowController {
35 AshPanelWindowController(AppWindow* window, Profile* profile);
36 ~AshPanelWindowController() override;
38 void NativeWindowChanged();
40 // Overridden from extensions::WindowController.
41 int GetWindowId() const override;
42 std::string GetWindowTypeText() const override;
43 base::DictionaryValue* CreateWindowValueWithTabs(
44 const extensions::Extension* extension) const override;
45 base::DictionaryValue* CreateTabValue(const extensions::Extension* extension,
46 int tab_index) const override;
47 bool CanClose(Reason* reason) const override;
48 void SetFullscreenMode(bool is_fullscreen,
49 const GURL& extension_url) const override;
50 bool IsVisibleToExtension(
51 const extensions::Extension* extension) const override;
54 AppWindow* app_window_; // Weak pointer; this is owned by app_window_
57 DISALLOW_COPY_AND_ASSIGN(AshPanelWindowController);
60 AshPanelWindowController::AshPanelWindowController(AppWindow* app_window,
62 : extensions::WindowController(app_window->GetBaseWindow(), profile),
63 app_window_(app_window),
64 is_active_(app_window->GetBaseWindow()->IsActive()) {
65 extensions::WindowControllerList::GetInstance()->AddExtensionWindow(this);
68 AshPanelWindowController::~AshPanelWindowController() {
69 extensions::WindowControllerList::GetInstance()->RemoveExtensionWindow(this);
72 int AshPanelWindowController::GetWindowId() const {
73 return static_cast<int>(app_window_->session_id().id());
76 std::string AshPanelWindowController::GetWindowTypeText() const {
77 return extensions::tabs_constants::kWindowTypeValuePanel;
80 base::DictionaryValue* AshPanelWindowController::CreateWindowValueWithTabs(
81 const extensions::Extension* extension) const {
82 DCHECK(IsVisibleToExtension(extension));
83 base::DictionaryValue* result = CreateWindowValue();
84 base::DictionaryValue* tab_value = CreateTabValue(extension, 0);
86 base::ListValue* tab_list = new base::ListValue();
87 tab_list->Append(tab_value);
88 result->Set(extensions::tabs_constants::kTabsKey, tab_list);
93 base::DictionaryValue* AshPanelWindowController::CreateTabValue(
94 const extensions::Extension* extension, int tab_index) const {
95 if ((extension && !IsVisibleToExtension(extension)) ||
99 content::WebContents* web_contents = app_window_->web_contents();
103 base::DictionaryValue* tab_value = new base::DictionaryValue();
104 tab_value->SetInteger(extensions::tabs_constants::kIdKey,
105 SessionTabHelper::IdForTab(web_contents));
106 tab_value->SetInteger(extensions::tabs_constants::kIndexKey, 0);
107 const int window_id = GetWindowId();
108 tab_value->SetInteger(extensions::tabs_constants::kWindowIdKey, window_id);
109 tab_value->SetString(
110 extensions::tabs_constants::kUrlKey, web_contents->GetURL().spec());
111 tab_value->SetString(
112 extensions::tabs_constants::kStatusKey,
113 extensions::ExtensionTabUtil::GetTabStatusText(
114 web_contents->IsLoading()));
115 tab_value->SetBoolean(extensions::tabs_constants::kActiveKey,
116 app_window_->GetBaseWindow()->IsActive());
117 // AppWindow only ever contains one tab, so that tab is always effectively
118 // selcted and highlighted (for purposes of the chrome.tabs API).
119 tab_value->SetInteger(extensions::tabs_constants::kWindowIdKey, window_id);
120 tab_value->SetInteger(extensions::tabs_constants::kIdKey, window_id);
121 tab_value->SetBoolean(extensions::tabs_constants::kSelectedKey, true);
122 tab_value->SetBoolean(extensions::tabs_constants::kHighlightedKey, true);
123 tab_value->SetBoolean(extensions::tabs_constants::kPinnedKey, false);
124 tab_value->SetString(
125 extensions::tabs_constants::kTitleKey, web_contents->GetTitle());
126 tab_value->SetBoolean(
127 extensions::tabs_constants::kIncognitoKey,
128 web_contents->GetBrowserContext()->IsOffTheRecord());
132 bool AshPanelWindowController::CanClose(Reason* reason) const {
136 void AshPanelWindowController::SetFullscreenMode(
137 bool is_fullscreen, const GURL& extension_url) const {
138 // Do nothing. Panels cannot be fullscreen.
141 bool AshPanelWindowController::IsVisibleToExtension(
142 const extensions::Extension* extension) const {
143 return extension->id() == app_window_->extension_id();
146 void AshPanelWindowController::NativeWindowChanged() {
147 bool active = app_window_->GetBaseWindow()->IsActive();
148 if (active == is_active_)
151 // Let the extension API know that the active window changed.
152 extensions::TabsWindowsAPI* tabs_windows_api =
153 extensions::TabsWindowsAPI::Get(profile());
154 if (!tabs_windows_api)
156 tabs_windows_api->windows_event_router()->OnActiveWindowChanged(
157 active ? this : NULL);
160 // AshPanelContents -----------------------------------------------------
162 AshPanelContents::AshPanelContents(AppWindow* host) : host_(host) {}
164 AshPanelContents::~AshPanelContents() {
167 void AshPanelContents::Initialize(content::BrowserContext* context,
171 extension_function_dispatcher_.reset(
172 new extensions::ExtensionFunctionDispatcher(context, this));
175 content::WebContents::Create(content::WebContents::CreateParams(
176 context, content::SiteInstance::CreateForURL(context, url_))));
178 // Needed to give the web contents a Window ID. Extension APIs expect web
179 // contents to have a Window ID. Also required for FaviconTabHelper to
180 // correctly set the window icon and title.
181 SessionTabHelper::CreateForWebContents(web_contents_.get());
182 SessionTabHelper::FromWebContents(web_contents_.get())->SetWindowID(
183 host_->session_id());
185 // Responsible for loading favicons for the Launcher, which uses different
186 // logic than the FaviconTabHelper associated with web_contents_
187 // (instantiated in AppWindow::Init())
188 launcher_favicon_loader_.reset(
189 new LauncherFaviconLoader(this, web_contents_.get()));
191 content::WebContentsObserver::Observe(web_contents_.get());
194 void AshPanelContents::LoadContents(int32 creator_process_id) {
195 // This must be created after the native window has been created.
196 window_controller_.reset(new AshPanelWindowController(
197 host_, Profile::FromBrowserContext(host_->browser_context())));
199 web_contents_->GetController().LoadURL(
200 url_, content::Referrer(), ui::PAGE_TRANSITION_LINK,
204 void AshPanelContents::NativeWindowChanged(NativeAppWindow* native_app_window) {
205 if (window_controller_)
206 window_controller_->NativeWindowChanged();
209 void AshPanelContents::NativeWindowClosed() {
212 void AshPanelContents::DispatchWindowShownForTests() const {
215 content::WebContents* AshPanelContents::GetWebContents() const {
216 return web_contents_.get();
219 void AshPanelContents::FaviconUpdated() {
220 gfx::Image new_image = gfx::Image::CreateFrom1xBitmap(
221 launcher_favicon_loader_->GetFavicon());
222 host_->UpdateAppIcon(new_image);
225 bool AshPanelContents::OnMessageReceived(const IPC::Message& message) {
227 IPC_BEGIN_MESSAGE_MAP(AshPanelContents, message)
228 IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest)
229 IPC_MESSAGE_UNHANDLED(handled = false)
230 IPC_END_MESSAGE_MAP()
234 extensions::WindowController*
235 AshPanelContents::GetExtensionWindowController() const {
236 return window_controller_.get();
239 content::WebContents* AshPanelContents::GetAssociatedWebContents() const {
240 return web_contents_.get();
243 void AshPanelContents::OnRequest(
244 const ExtensionHostMsg_Request_Params& params) {
245 extension_function_dispatcher_->Dispatch(
246 params, web_contents_->GetRenderViewHost());