1 // Copyright (c) 2012 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/tab_helper.h"
6
7 #include "base/command_line.h"
8 #include "base/logging.h"
9 #include "base/strings/string_util.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "chrome/browser/chrome_notification_types.h"
12 #include "chrome/browser/extensions/active_script_controller.h"
13 #include "chrome/browser/extensions/activity_log/activity_log.h"
14 #include "chrome/browser/extensions/api/declarative/rules_registry_service.h"
15 #include "chrome/browser/extensions/api/declarative_content/content_rules_registry.h"
16 #include "chrome/browser/extensions/api/webstore/webstore_api.h"
17 #include "chrome/browser/extensions/bookmark_app_helper.h"
18 #include "chrome/browser/extensions/error_console/error_console.h"
19 #include "chrome/browser/extensions/extension_action.h"
20 #include "chrome/browser/extensions/extension_action_manager.h"
21 #include "chrome/browser/extensions/extension_service.h"
22 #include "chrome/browser/extensions/extension_tab_util.h"
23 #include "chrome/browser/extensions/location_bar_controller.h"
24 #include "chrome/browser/extensions/script_executor.h"
25 #include "chrome/browser/extensions/webstore_inline_installer.h"
26 #include "chrome/browser/extensions/webstore_inline_installer_factory.h"
27 #include "chrome/browser/profiles/profile.h"
28 #include "chrome/browser/sessions/session_id.h"
29 #include "chrome/browser/sessions/session_tab_helper.h"
30 #include "chrome/browser/shell_integration.h"
31 #include "chrome/browser/ui/browser_commands.h"
32 #include "chrome/browser/ui/browser_dialogs.h"
33 #include "chrome/browser/ui/browser_finder.h"
34 #include "chrome/browser/ui/browser_window.h"
35 #include "chrome/browser/ui/host_desktop.h"
36 #include "chrome/browser/web_applications/web_app.h"
37 #include "chrome/common/chrome_switches.h"
38 #include "chrome/common/extensions/chrome_extension_messages.h"
39 #include "chrome/common/extensions/extension_constants.h"
40 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
41 #include "chrome/common/render_messages.h"
42 #include "chrome/common/url_constants.h"
43 #include "content/public/browser/invalidate_type.h"
44 #include "content/public/browser/navigation_controller.h"
45 #include "content/public/browser/navigation_details.h"
46 #include "content/public/browser/navigation_entry.h"
47 #include "content/public/browser/notification_service.h"
48 #include "content/public/browser/notification_source.h"
49 #include "content/public/browser/notification_types.h"
50 #include "content/public/browser/render_process_host.h"
51 #include "content/public/browser/render_view_host.h"
52 #include "content/public/browser/render_widget_host_view.h"
53 #include "content/public/browser/web_contents.h"
54 #include "content/public/common/frame_navigate_params.h"
55 #include "extensions/browser/extension_error.h"
56 #include "extensions/browser/extension_registry.h"
57 #include "extensions/browser/extension_system.h"
58 #include "extensions/browser/image_loader.h"
59 #include "extensions/common/constants.h"
60 #include "extensions/common/extension.h"
61 #include "extensions/common/extension_icon_set.h"
62 #include "extensions/common/extension_messages.h"
63 #include "extensions/common/extension_resource.h"
64 #include "extensions/common/extension_urls.h"
65 #include "extensions/common/feature_switch.h"
66 #include "extensions/common/manifest_handlers/icons_handler.h"
67
68 #if defined(OS_CHROMEOS)
69 #include "chrome/browser/ui/ash/launcher/chrome_launcher_controller.h"
70 #endif
71
72 #if defined(OS_WIN)
73 #include "chrome/browser/web_applications/web_app_win.h"
74 #endif
75
76 using content::NavigationController;
77 using content::NavigationEntry;
78 using content::RenderViewHost;
79 using content::WebContents;
80
81 DEFINE_WEB_CONTENTS_USER_DATA_KEY(extensions::TabHelper);
82
83 namespace extensions {
84
ScriptExecutionObserver(TabHelper * tab_helper)85 TabHelper::ScriptExecutionObserver::ScriptExecutionObserver(
86 TabHelper* tab_helper)
87 : tab_helper_(tab_helper) {
88 tab_helper_->AddScriptExecutionObserver(this);
89 }
90
ScriptExecutionObserver()91 TabHelper::ScriptExecutionObserver::ScriptExecutionObserver()
92 : tab_helper_(NULL) {
93 }
94
~ScriptExecutionObserver()95 TabHelper::ScriptExecutionObserver::~ScriptExecutionObserver() {
96 if (tab_helper_)
97 tab_helper_->RemoveScriptExecutionObserver(this);
98 }
99
TabHelper(content::WebContents * web_contents)100 TabHelper::TabHelper(content::WebContents* web_contents)
101 : content::WebContentsObserver(web_contents),
102 extension_app_(NULL),
103 extension_function_dispatcher_(
104 Profile::FromBrowserContext(web_contents->GetBrowserContext()), this),
105 pending_web_app_action_(NONE),
106 script_executor_(new ScriptExecutor(web_contents,
107 &script_execution_observers_)),
108 location_bar_controller_(new LocationBarController(web_contents)),
109 image_loader_ptr_factory_(this),
110 webstore_inline_installer_factory_(new WebstoreInlineInstallerFactory()) {
111 // The ActiveTabPermissionManager requires a session ID; ensure this
112 // WebContents has one.
113 SessionTabHelper::CreateForWebContents(web_contents);
114 if (web_contents->GetRenderViewHost())
115 SetTabId(web_contents->GetRenderViewHost());
116 active_tab_permission_granter_.reset(new ActiveTabPermissionGranter(
117 web_contents,
118 SessionID::IdForTab(web_contents),
119 Profile::FromBrowserContext(web_contents->GetBrowserContext())));
120
121 // If more classes need to listen to global content script activity, then
122 // a separate routing class with an observer interface should be written.
123 profile_ = Profile::FromBrowserContext(web_contents->GetBrowserContext());
124
125 #if defined(ENABLE_EXTENSIONS)
126 AddScriptExecutionObserver(ActivityLog::GetInstance(profile_));
127 #endif
128
129 registrar_.Add(this,
130 content::NOTIFICATION_LOAD_STOP,
131 content::Source<NavigationController>(
132 &web_contents->GetController()));
133 }
134
~TabHelper()135 TabHelper::~TabHelper() {
136 #if defined(ENABLE_EXTENSIONS)
137 RemoveScriptExecutionObserver(ActivityLog::GetInstance(profile_));
138 #endif
139 }
140
CreateApplicationShortcuts()141 void TabHelper::CreateApplicationShortcuts() {
142 DCHECK(CanCreateApplicationShortcuts());
143 NavigationEntry* entry =
144 web_contents()->GetController().GetLastCommittedEntry();
145 if (!entry)
146 return;
147
148 pending_web_app_action_ = CREATE_SHORTCUT;
149
150 // Start fetching web app info for CreateApplicationShortcut dialog and show
151 // the dialog when the data is available in OnDidGetApplicationInfo.
152 GetApplicationInfo(entry->GetPageID());
153 }
154
CreateHostedAppFromWebContents()155 void TabHelper::CreateHostedAppFromWebContents() {
156 DCHECK(CanCreateBookmarkApp());
157 NavigationEntry* entry =
158 web_contents()->GetController().GetLastCommittedEntry();
159 if (!entry)
160 return;
161
162 pending_web_app_action_ = CREATE_HOSTED_APP;
163
164 // Start fetching web app info for CreateApplicationShortcut dialog and show
165 // the dialog when the data is available in OnDidGetApplicationInfo.
166 GetApplicationInfo(entry->GetPageID());
167 }
168
CanCreateApplicationShortcuts() const169 bool TabHelper::CanCreateApplicationShortcuts() const {
170 #if defined(OS_MACOSX)
171 return false;
172 #else
173 return web_app::IsValidUrl(web_contents()->GetURL()) &&
174 pending_web_app_action_ == NONE;
175 #endif
176 }
177
CanCreateBookmarkApp() const178 bool TabHelper::CanCreateBookmarkApp() const {
179 #if defined(OS_MACOSX)
180 return false;
181 #else
182 return IsValidBookmarkAppUrl(web_contents()->GetURL()) &&
183 pending_web_app_action_ == NONE;
184 #endif
185 }
186
SetExtensionApp(const Extension * extension)187 void TabHelper::SetExtensionApp(const Extension* extension) {
188 DCHECK(!extension || AppLaunchInfo::GetFullLaunchURL(extension).is_valid());
189 if (extension_app_ == extension)
190 return;
191
192 extension_app_ = extension;
193
194 UpdateExtensionAppIcon(extension_app_);
195
196 content::NotificationService::current()->Notify(
197 chrome::NOTIFICATION_TAB_CONTENTS_APPLICATION_EXTENSION_CHANGED,
198 content::Source<TabHelper>(this),
199 content::NotificationService::NoDetails());
200 }
201
SetExtensionAppById(const std::string & extension_app_id)202 void TabHelper::SetExtensionAppById(const std::string& extension_app_id) {
203 const Extension* extension = GetExtension(extension_app_id);
204 if (extension)
205 SetExtensionApp(extension);
206 }
207
SetExtensionAppIconById(const std::string & extension_app_id)208 void TabHelper::SetExtensionAppIconById(const std::string& extension_app_id) {
209 const Extension* extension = GetExtension(extension_app_id);
210 if (extension)
211 UpdateExtensionAppIcon(extension);
212 }
213
GetExtensionAppIcon()214 SkBitmap* TabHelper::GetExtensionAppIcon() {
215 if (extension_app_icon_.empty())
216 return NULL;
217
218 return &extension_app_icon_;
219 }
220
FinishCreateBookmarkApp(const extensions::Extension * extension,const WebApplicationInfo & web_app_info)221 void TabHelper::FinishCreateBookmarkApp(
222 const extensions::Extension* extension,
223 const WebApplicationInfo& web_app_info) {
224 pending_web_app_action_ = NONE;
225
226 // There was an error with downloading the icons or installing the app.
227 if (!extension)
228 return;
229
230 #if defined(OS_CHROMEOS)
231 ChromeLauncherController::instance()->PinAppWithID(extension->id());
232 #endif
233
234 // Android does not implement browser_finder.cc.
235 #if !defined(OS_ANDROID)
236 Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
237 if (browser) {
238 browser->window()->ShowBookmarkAppBubble(web_app_info, extension->id());
239 }
240 #endif
241 }
242
RenderViewCreated(RenderViewHost * render_view_host)243 void TabHelper::RenderViewCreated(RenderViewHost* render_view_host) {
244 SetTabId(render_view_host);
245 }
246
DidNavigateMainFrame(const content::LoadCommittedDetails & details,const content::FrameNavigateParams & params)247 void TabHelper::DidNavigateMainFrame(
248 const content::LoadCommittedDetails& details,
249 const content::FrameNavigateParams& params) {
250 #if defined(ENABLE_EXTENSIONS)
251 if (ExtensionSystem::Get(profile_)->extension_service() &&
252 RulesRegistryService::Get(profile_)) {
253 RulesRegistryService::Get(profile_)->content_rules_registry()->
254 DidNavigateMainFrame(web_contents(), details, params);
255 }
256 #endif // defined(ENABLE_EXTENSIONS)
257
258 content::BrowserContext* context = web_contents()->GetBrowserContext();
259 ExtensionRegistry* registry = ExtensionRegistry::Get(context);
260 const ExtensionSet& enabled_extensions = registry->enabled_extensions();
261
262 if (CommandLine::ForCurrentProcess()->HasSwitch(
263 switches::kEnableStreamlinedHostedApps)) {
264 #if !defined(OS_ANDROID)
265 Browser* browser = chrome::FindBrowserWithWebContents(web_contents());
266 if (browser && browser->is_app()) {
267 SetExtensionApp(registry->GetExtensionById(
268 web_app::GetExtensionIdFromApplicationName(browser->app_name()),
269 ExtensionRegistry::EVERYTHING));
270 } else {
271 UpdateExtensionAppIcon(
272 enabled_extensions.GetExtensionOrAppByURL(params.url));
273 }
274 #endif
275 } else {
276 UpdateExtensionAppIcon(
277 enabled_extensions.GetExtensionOrAppByURL(params.url));
278 }
279
280 if (details.is_in_page)
281 return;
282
283 ExtensionActionManager* extension_action_manager =
284 ExtensionActionManager::Get(Profile::FromBrowserContext(context));
285 for (ExtensionSet::const_iterator it = enabled_extensions.begin();
286 it != enabled_extensions.end();
287 ++it) {
288 ExtensionAction* browser_action =
289 extension_action_manager->GetBrowserAction(*it->get());
290 if (browser_action) {
291 browser_action->ClearAllValuesForTab(SessionID::IdForTab(web_contents()));
292 content::NotificationService::current()->Notify(
293 chrome::NOTIFICATION_EXTENSION_BROWSER_ACTION_UPDATED,
294 content::Source<ExtensionAction>(browser_action),
295 content::NotificationService::NoDetails());
296 }
297 }
298 }
299
OnMessageReceived(const IPC::Message & message)300 bool TabHelper::OnMessageReceived(const IPC::Message& message) {
301 bool handled = true;
302 IPC_BEGIN_MESSAGE_MAP(TabHelper, message)
303 IPC_MESSAGE_HANDLER(ChromeExtensionHostMsg_DidGetApplicationInfo,
304 OnDidGetApplicationInfo)
305 IPC_MESSAGE_HANDLER(ExtensionHostMsg_InlineWebstoreInstall,
306 OnInlineWebstoreInstall)
307 IPC_MESSAGE_HANDLER(ExtensionHostMsg_GetAppInstallState,
308 OnGetAppInstallState);
309 IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest)
310 IPC_MESSAGE_HANDLER(ExtensionHostMsg_ContentScriptsExecuting,
311 OnContentScriptsExecuting)
312 IPC_MESSAGE_HANDLER(ExtensionHostMsg_OnWatchedPageChange,
313 OnWatchedPageChange)
314 IPC_MESSAGE_UNHANDLED(handled = false)
315 IPC_END_MESSAGE_MAP()
316 return handled;
317 }
318
OnMessageReceived(const IPC::Message & message,content::RenderFrameHost * render_frame_host)319 bool TabHelper::OnMessageReceived(const IPC::Message& message,
320 content::RenderFrameHost* render_frame_host) {
321 #if defined(ENABLE_EXTENSIONS)
322 bool handled = true;
323 IPC_BEGIN_MESSAGE_MAP(TabHelper, message)
324 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_DetailedConsoleMessageAdded,
325 OnDetailedConsoleMessageAdded)
326 IPC_MESSAGE_UNHANDLED(handled = false)
327 IPC_END_MESSAGE_MAP()
328 #else
329 bool handled = false;
330 #endif
331 return handled;
332 }
333
DidCloneToNewWebContents(WebContents * old_web_contents,WebContents * new_web_contents)334 void TabHelper::DidCloneToNewWebContents(WebContents* old_web_contents,
335 WebContents* new_web_contents) {
336 // When the WebContents that this is attached to is cloned, give the new clone
337 // a TabHelper and copy state over.
338 CreateForWebContents(new_web_contents);
339 TabHelper* new_helper = FromWebContents(new_web_contents);
340
341 new_helper->SetExtensionApp(extension_app());
342 new_helper->extension_app_icon_ = extension_app_icon_;
343 }
344
OnDidGetApplicationInfo(int32 page_id,const WebApplicationInfo & info)345 void TabHelper::OnDidGetApplicationInfo(int32 page_id,
346 const WebApplicationInfo& info) {
347 // Android does not implement BrowserWindow.
348 #if !defined(OS_MACOSX) && !defined(OS_ANDROID)
349 web_app_info_ = info;
350
351 NavigationEntry* entry =
352 web_contents()->GetController().GetLastCommittedEntry();
353 if (!entry || (entry->GetPageID() != page_id))
354 return;
355
356 switch (pending_web_app_action_) {
357 case CREATE_SHORTCUT: {
358 chrome::ShowCreateWebAppShortcutsDialog(
359 web_contents()->GetTopLevelNativeWindow(),
360 web_contents());
361 break;
362 }
363 case CREATE_HOSTED_APP: {
364 if (web_app_info_.app_url.is_empty())
365 web_app_info_.app_url = web_contents()->GetURL();
366
367 if (web_app_info_.title.empty())
368 web_app_info_.title = web_contents()->GetTitle();
369 if (web_app_info_.title.empty())
370 web_app_info_.title = base::UTF8ToUTF16(web_app_info_.app_url.spec());
371
372 bookmark_app_helper_.reset(new BookmarkAppHelper(
373 profile_->GetExtensionService(), web_app_info_, web_contents()));
374 bookmark_app_helper_->Create(base::Bind(
375 &TabHelper::FinishCreateBookmarkApp, base::Unretained(this)));
376 break;
377 }
378 case UPDATE_SHORTCUT: {
379 web_app::UpdateShortcutForTabContents(web_contents());
380 break;
381 }
382 default:
383 NOTREACHED();
384 break;
385 }
386
387 // The hosted app action will be cleared once the installation completes or
388 // fails.
389 if (pending_web_app_action_ != CREATE_HOSTED_APP)
390 pending_web_app_action_ = NONE;
391 #endif
392 }
393
OnInlineWebstoreInstall(int install_id,int return_route_id,const std::string & webstore_item_id,const GURL & requestor_url,int listeners_mask)394 void TabHelper::OnInlineWebstoreInstall(int install_id,
395 int return_route_id,
396 const std::string& webstore_item_id,
397 const GURL& requestor_url,
398 int listeners_mask) {
399 #if defined(ENABLE_EXTENSIONS)
400 // Check that the listener is reasonable. We should never get anything other
401 // than an install stage listener, a download listener, or both.
402 if ((listeners_mask & ~(api::webstore::INSTALL_STAGE_LISTENER |
403 api::webstore::DOWNLOAD_PROGRESS_LISTENER)) != 0) {
404 NOTREACHED();
405 return;
406 }
407 // Inform the Webstore API that an inline install is happening, in case the
408 // page requested status updates.
409 Profile* profile =
410 Profile::FromBrowserContext(web_contents()->GetBrowserContext());
411 WebstoreAPI::Get(profile)->OnInlineInstallStart(
412 return_route_id, this, webstore_item_id, listeners_mask);
413 #endif
414
415 WebstoreStandaloneInstaller::Callback callback =
416 base::Bind(&TabHelper::OnInlineInstallComplete, base::Unretained(this),
417 install_id, return_route_id);
418 scoped_refptr<WebstoreInlineInstaller> installer(
419 webstore_inline_installer_factory_->CreateInstaller(
420 web_contents(),
421 webstore_item_id,
422 requestor_url,
423 callback));
424 installer->BeginInstall();
425 }
426
OnGetAppInstallState(const GURL & requestor_url,int return_route_id,int callback_id)427 void TabHelper::OnGetAppInstallState(const GURL& requestor_url,
428 int return_route_id,
429 int callback_id) {
430 ExtensionRegistry* registry =
431 ExtensionRegistry::Get(web_contents()->GetBrowserContext());
432 const ExtensionSet& extensions = registry->enabled_extensions();
433 const ExtensionSet& disabled_extensions = registry->disabled_extensions();
434
435 std::string state;
436 if (extensions.GetHostedAppByURL(requestor_url))
437 state = extension_misc::kAppStateInstalled;
438 else if (disabled_extensions.GetHostedAppByURL(requestor_url))
439 state = extension_misc::kAppStateDisabled;
440 else
441 state = extension_misc::kAppStateNotInstalled;
442
443 Send(new ExtensionMsg_GetAppInstallStateResponse(
444 return_route_id, state, callback_id));
445 }
446
OnRequest(const ExtensionHostMsg_Request_Params & request)447 void TabHelper::OnRequest(const ExtensionHostMsg_Request_Params& request) {
448 extension_function_dispatcher_.Dispatch(request,
449 web_contents()->GetRenderViewHost());
450 }
451
OnContentScriptsExecuting(const ScriptExecutionObserver::ExecutingScriptsMap & executing_scripts_map,int32 on_page_id,const GURL & on_url)452 void TabHelper::OnContentScriptsExecuting(
453 const ScriptExecutionObserver::ExecutingScriptsMap& executing_scripts_map,
454 int32 on_page_id,
455 const GURL& on_url) {
456 FOR_EACH_OBSERVER(ScriptExecutionObserver, script_execution_observers_,
457 OnScriptsExecuted(web_contents(),
458 executing_scripts_map,
459 on_page_id,
460 on_url));
461 }
462
OnWatchedPageChange(const std::vector<std::string> & css_selectors)463 void TabHelper::OnWatchedPageChange(
464 const std::vector<std::string>& css_selectors) {
465 #if defined(ENABLE_EXTENSIONS)
466 if (ExtensionSystem::Get(profile_)->extension_service() &&
467 RulesRegistryService::Get(profile_)) {
468 RulesRegistryService::Get(profile_)->content_rules_registry()->Apply(
469 web_contents(), css_selectors);
470 }
471 #endif // defined(ENABLE_EXTENSIONS)
472 }
473
OnDetailedConsoleMessageAdded(const base::string16 & message,const base::string16 & source,const StackTrace & stack_trace,int32 severity_level)474 void TabHelper::OnDetailedConsoleMessageAdded(
475 const base::string16& message,
476 const base::string16& source,
477 const StackTrace& stack_trace,
478 int32 severity_level) {
479 #if defined(ENABLE_EXTENSIONS)
480 if (IsSourceFromAnExtension(source)) {
481 content::RenderViewHost* rvh = web_contents()->GetRenderViewHost();
482 ErrorConsole::Get(profile_)->ReportError(
483 scoped_ptr<ExtensionError>(new RuntimeError(
484 extension_app_ ? extension_app_->id() : std::string(),
485 profile_->IsOffTheRecord(),
486 source,
487 message,
488 stack_trace,
489 web_contents() ?
490 web_contents()->GetLastCommittedURL() : GURL::EmptyGURL(),
491 static_cast<logging::LogSeverity>(severity_level),
492 rvh->GetRoutingID(),
493 rvh->GetProcess()->GetID())));
494 }
495 #endif
496 }
497
GetExtension(const std::string & extension_app_id)498 const Extension* TabHelper::GetExtension(const std::string& extension_app_id) {
499 if (extension_app_id.empty())
500 return NULL;
501
502 Profile* profile =
503 Profile::FromBrowserContext(web_contents()->GetBrowserContext());
504 ExtensionService* extension_service = profile->GetExtensionService();
505 if (!extension_service || !extension_service->is_ready())
506 return NULL;
507
508 const Extension* extension =
509 extension_service->GetExtensionById(extension_app_id, false);
510 return extension;
511 }
512
UpdateExtensionAppIcon(const Extension * extension)513 void TabHelper::UpdateExtensionAppIcon(const Extension* extension) {
514 extension_app_icon_.reset();
515 // Ensure previously enqueued callbacks are ignored.
516 image_loader_ptr_factory_.InvalidateWeakPtrs();
517
518 // Enqueue OnImageLoaded callback.
519 if (extension) {
520 Profile* profile =
521 Profile::FromBrowserContext(web_contents()->GetBrowserContext());
522 extensions::ImageLoader* loader = extensions::ImageLoader::Get(profile);
523 loader->LoadImageAsync(
524 extension,
525 IconsInfo::GetIconResource(extension,
526 extension_misc::EXTENSION_ICON_SMALL,
527 ExtensionIconSet::MATCH_BIGGER),
528 gfx::Size(extension_misc::EXTENSION_ICON_SMALL,
529 extension_misc::EXTENSION_ICON_SMALL),
530 base::Bind(&TabHelper::OnImageLoaded,
531 image_loader_ptr_factory_.GetWeakPtr()));
532 }
533 }
534
SetAppIcon(const SkBitmap & app_icon)535 void TabHelper::SetAppIcon(const SkBitmap& app_icon) {
536 extension_app_icon_ = app_icon;
537 web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TITLE);
538 }
539
SetWebstoreInlineInstallerFactoryForTests(WebstoreInlineInstallerFactory * factory)540 void TabHelper::SetWebstoreInlineInstallerFactoryForTests(
541 WebstoreInlineInstallerFactory* factory) {
542 webstore_inline_installer_factory_.reset(factory);
543 }
544
OnImageLoaded(const gfx::Image & image)545 void TabHelper::OnImageLoaded(const gfx::Image& image) {
546 if (!image.IsEmpty()) {
547 extension_app_icon_ = *image.ToSkBitmap();
548 web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_TAB);
549 }
550 }
551
GetExtensionWindowController() const552 WindowController* TabHelper::GetExtensionWindowController() const {
553 return ExtensionTabUtil::GetWindowControllerOfTab(web_contents());
554 }
555
OnInlineInstallComplete(int install_id,int return_route_id,bool success,const std::string & error)556 void TabHelper::OnInlineInstallComplete(int install_id,
557 int return_route_id,
558 bool success,
559 const std::string& error) {
560 Send(new ExtensionMsg_InlineWebstoreInstallResponse(
561 return_route_id, install_id, success, success ? std::string() : error));
562 }
563
GetAssociatedWebContents() const564 WebContents* TabHelper::GetAssociatedWebContents() const {
565 return web_contents();
566 }
567
GetApplicationInfo(int32 page_id)568 void TabHelper::GetApplicationInfo(int32 page_id) {
569 Send(new ChromeExtensionMsg_GetApplicationInfo(routing_id(), page_id));
570 }
571
Observe(int type,const content::NotificationSource & source,const content::NotificationDetails & details)572 void TabHelper::Observe(int type,
573 const content::NotificationSource& source,
574 const content::NotificationDetails& details) {
575 switch (type) {
576 case content::NOTIFICATION_LOAD_STOP: {
577 const NavigationController& controller =
578 *content::Source<NavigationController>(source).ptr();
579 DCHECK_EQ(controller.GetWebContents(), web_contents());
580
581 if (pending_web_app_action_ == UPDATE_SHORTCUT) {
582 // Schedule a shortcut update when web application info is available if
583 // last committed entry is not NULL. Last committed entry could be NULL
584 // when an interstitial page is injected (e.g. bad https certificate,
585 // malware site etc). When this happens, we abort the shortcut update.
586 NavigationEntry* entry = controller.GetLastCommittedEntry();
587 if (entry)
588 GetApplicationInfo(entry->GetPageID());
589 else
590 pending_web_app_action_ = NONE;
591 }
592 break;
593 }
594 }
595 }
596
SetTabId(RenderViewHost * render_view_host)597 void TabHelper::SetTabId(RenderViewHost* render_view_host) {
598 render_view_host->Send(
599 new ExtensionMsg_SetTabId(render_view_host->GetRoutingID(),
600 SessionID::IdForTab(web_contents())));
601 }
602
603 } // namespace extensions
604