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