• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "chrome/browser/extensions/api/tabs/ash_panel_contents.h"
6 
7 #include "apps/ui/native_app_window.h"
8 #include "base/values.h"
9 #include "chrome/browser/chrome_notification_types.h"
10 #include "chrome/browser/extensions/api/tabs/tabs_constants.h"
11 #include "chrome/browser/extensions/api/tabs/tabs_windows_api.h"
12 #include "chrome/browser/extensions/api/tabs/windows_event_router.h"
13 #include "chrome/browser/extensions/extension_tab_util.h"
14 #include "chrome/browser/extensions/window_controller_list.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/browser/sessions/session_tab_helper.h"
17 #include "chrome/common/extensions/extension_messages.h"
18 #include "content/public/browser/site_instance.h"
19 #include "content/public/browser/web_contents.h"
20 #include "extensions/common/extension.h"
21 #include "ui/gfx/image/image.h"
22 
23 using apps::ShellWindow;
24 using apps::NativeAppWindow;
25 
26 // AshPanelWindowController ----------------------------------------------------
27 
28 // This class enables a ShellWindow instance to be accessed (to a limited
29 // extent) via the chrome.windows and chrome.tabs API. This is a temporary
30 // bridge to support instantiating ShellWindows from v1 apps, specifically
31 // for creating Panels in Ash. See crbug.com/160645.
32 class AshPanelWindowController : public extensions::WindowController {
33  public:
34   AshPanelWindowController(ShellWindow* window, Profile* profile);
35   virtual ~AshPanelWindowController();
36 
37   void NativeWindowChanged();
38 
39   // Overridden from extensions::WindowController.
40   virtual int GetWindowId() const OVERRIDE;
41   virtual std::string GetWindowTypeText() const OVERRIDE;
42   virtual base::DictionaryValue* CreateWindowValueWithTabs(
43       const extensions::Extension* extension) const OVERRIDE;
44   virtual base::DictionaryValue* CreateTabValue(
45       const extensions::Extension* extension, int tab_index) const OVERRIDE;
46   virtual bool CanClose(Reason* reason) const OVERRIDE;
47   virtual void SetFullscreenMode(bool is_fullscreen,
48                                  const GURL& extension_url) const OVERRIDE;
49   virtual bool IsVisibleToExtension(
50       const extensions::Extension* extension) const OVERRIDE;
51 
52  private:
53   ShellWindow* shell_window_;  // Weak pointer; this is owned by shell_window_
54   bool is_active_;
55 
56   DISALLOW_COPY_AND_ASSIGN(AshPanelWindowController);
57 };
58 
AshPanelWindowController(ShellWindow * shell_window,Profile * profile)59 AshPanelWindowController::AshPanelWindowController(
60     ShellWindow* shell_window, Profile* profile)
61     : extensions::WindowController(shell_window->GetBaseWindow(), profile),
62       shell_window_(shell_window),
63       is_active_(shell_window->GetBaseWindow()->IsActive()) {
64   extensions::WindowControllerList::GetInstance()->AddExtensionWindow(this);
65 }
66 
~AshPanelWindowController()67 AshPanelWindowController::~AshPanelWindowController() {
68   extensions::WindowControllerList::GetInstance()->RemoveExtensionWindow(this);
69 }
70 
GetWindowId() const71 int AshPanelWindowController::GetWindowId() const {
72   return static_cast<int>(shell_window_->session_id().id());
73 }
74 
GetWindowTypeText() const75 std::string AshPanelWindowController::GetWindowTypeText() const {
76   return extensions::tabs_constants::kWindowTypeValuePanel;
77 }
78 
CreateWindowValueWithTabs(const extensions::Extension * extension) const79 base::DictionaryValue* AshPanelWindowController::CreateWindowValueWithTabs(
80     const extensions::Extension* extension) const {
81   DCHECK(IsVisibleToExtension(extension));
82   base::DictionaryValue* result = CreateWindowValue();
83   base::DictionaryValue* tab_value = CreateTabValue(extension, 0);
84   if (tab_value) {
85     base::ListValue* tab_list = new base::ListValue();
86     tab_list->Append(tab_value);
87     result->Set(extensions::tabs_constants::kTabsKey, tab_list);
88   }
89   return result;
90 }
91 
CreateTabValue(const extensions::Extension * extension,int tab_index) const92 base::DictionaryValue* AshPanelWindowController::CreateTabValue(
93     const extensions::Extension* extension, int tab_index) const {
94   if ((extension && !IsVisibleToExtension(extension)) ||
95       (tab_index > 0)) {
96     return NULL;
97   }
98   content::WebContents* web_contents = shell_window_->web_contents();
99   if (!web_contents)
100     return NULL;
101 
102   base::DictionaryValue* tab_value = new base::DictionaryValue();
103   tab_value->SetInteger(extensions::tabs_constants::kIdKey,
104                         SessionID::IdForTab(web_contents));
105   tab_value->SetInteger(extensions::tabs_constants::kIndexKey, 0);
106   const int window_id = GetWindowId();
107   tab_value->SetInteger(extensions::tabs_constants::kWindowIdKey, window_id);
108   tab_value->SetString(
109       extensions::tabs_constants::kUrlKey, web_contents->GetURL().spec());
110   tab_value->SetString(
111       extensions::tabs_constants::kStatusKey,
112       extensions::ExtensionTabUtil::GetTabStatusText(
113           web_contents->IsLoading()));
114   tab_value->SetBoolean(
115       extensions::tabs_constants::kActiveKey,
116       shell_window_->GetBaseWindow()->IsActive());
117   // ShellWindow 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());
129   return tab_value;
130 }
131 
CanClose(Reason * reason) const132 bool AshPanelWindowController::CanClose(Reason* reason) const {
133   return true;
134 }
135 
SetFullscreenMode(bool is_fullscreen,const GURL & extension_url) const136 void AshPanelWindowController::SetFullscreenMode(
137     bool is_fullscreen, const GURL& extension_url) const {
138   // Do nothing. Panels cannot be fullscreen.
139 }
140 
IsVisibleToExtension(const extensions::Extension * extension) const141 bool AshPanelWindowController::IsVisibleToExtension(
142     const extensions::Extension* extension) const {
143   return shell_window_->extension() &&
144       extension->id() == shell_window_->extension()->id();
145 }
146 
NativeWindowChanged()147 void AshPanelWindowController::NativeWindowChanged() {
148   bool active = shell_window_->GetBaseWindow()->IsActive();
149   if (active == is_active_)
150     return;
151   is_active_ = active;
152   // Let the extension API know that the active window changed.
153   extensions::TabsWindowsAPI* tabs_windows_api =
154       extensions::TabsWindowsAPI::Get(profile());
155   if (!tabs_windows_api)
156     return;
157   tabs_windows_api->windows_event_router()->OnActiveWindowChanged(
158       active ? this : NULL);
159 }
160 
161 // AshPanelContents -----------------------------------------------------
162 
AshPanelContents(ShellWindow * host)163 AshPanelContents::AshPanelContents(ShellWindow* host)
164     : host_(host) {
165 }
166 
~AshPanelContents()167 AshPanelContents::~AshPanelContents() {
168 }
169 
Initialize(Profile * profile,const GURL & url)170 void AshPanelContents::Initialize(Profile* profile, const GURL& url) {
171   url_ = url;
172 
173   extension_function_dispatcher_.reset(
174       new ExtensionFunctionDispatcher(profile, this));
175 
176   web_contents_.reset(content::WebContents::Create(
177       content::WebContents::CreateParams(
178           profile, content::SiteInstance::CreateForURL(profile, url_))));
179 
180   // Needed to give the web contents a Window ID. Extension APIs expect web
181   // contents to have a Window ID. Also required for FaviconTabHelper to
182   // correctly set the window icon and title.
183   SessionTabHelper::CreateForWebContents(web_contents_.get());
184   SessionTabHelper::FromWebContents(web_contents_.get())->SetWindowID(
185       host_->session_id());
186 
187   // Responsible for loading favicons for the Launcher, which uses different
188   // logic than the FaviconTabHelper associated with web_contents_
189   // (instantiated in ShellWindow::Init())
190   launcher_favicon_loader_.reset(
191       new LauncherFaviconLoader(this, web_contents_.get()));
192 
193   content::WebContentsObserver::Observe(web_contents_.get());
194 }
195 
LoadContents(int32 creator_process_id)196 void AshPanelContents::LoadContents(int32 creator_process_id) {
197   // This must be created after the native window has been created.
198   window_controller_.reset(
199       new AshPanelWindowController(host_, host_->profile()));
200 
201   web_contents_->GetController().LoadURL(
202       url_, content::Referrer(), content::PAGE_TRANSITION_LINK,
203       std::string());
204 }
205 
NativeWindowChanged(NativeAppWindow * native_app_window)206 void AshPanelContents::NativeWindowChanged(NativeAppWindow* native_app_window) {
207   if (window_controller_)
208     window_controller_->NativeWindowChanged();
209 }
210 
NativeWindowClosed()211 void AshPanelContents::NativeWindowClosed() {
212 }
213 
GetWebContents() const214 content::WebContents* AshPanelContents::GetWebContents() const {
215   return web_contents_.get();
216 }
217 
FaviconUpdated()218 void AshPanelContents::FaviconUpdated() {
219   gfx::Image new_image = gfx::Image::CreateFrom1xBitmap(
220       launcher_favicon_loader_->GetFavicon());
221   host_->UpdateAppIcon(new_image);
222 }
223 
OnMessageReceived(const IPC::Message & message)224 bool AshPanelContents::OnMessageReceived(const IPC::Message& message) {
225   bool handled = true;
226   IPC_BEGIN_MESSAGE_MAP(AshPanelContents, message)
227     IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest)
228     IPC_MESSAGE_UNHANDLED(handled = false)
229   IPC_END_MESSAGE_MAP()
230   return handled;
231 }
232 
233 extensions::WindowController*
GetExtensionWindowController() const234 AshPanelContents::GetExtensionWindowController() const {
235   return window_controller_.get();
236 }
237 
GetAssociatedWebContents() const238 content::WebContents* AshPanelContents::GetAssociatedWebContents() const {
239   return web_contents_.get();
240 }
241 
OnRequest(const ExtensionHostMsg_Request_Params & params)242 void AshPanelContents::OnRequest(
243     const ExtensionHostMsg_Request_Params& params) {
244   extension_function_dispatcher_->Dispatch(
245       params, web_contents_->GetRenderViewHost());
246 }
247