1// Copyright (c) 2011 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/extension_tab_helper.h"
6
7#include "chrome/browser/extensions/extension_service.h"
8#include "chrome/browser/profiles/profile.h"
9#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
10#include "chrome/browser/ui/tab_contents/tab_contents_wrapper_delegate.h"
11#include "chrome/common/extensions/extension_action.h"
12#include "chrome/common/extensions/extension_icon_set.h"
13#include "chrome/common/extensions/extension_messages.h"
14#include "chrome/common/extensions/extension_resource.h"
15#include "content/browser/tab_contents/tab_contents.h"
16#include "content/browser/tab_contents/navigation_controller.h"
17#include "content/common/notification_service.h"
18
19ExtensionTabHelper::ExtensionTabHelper(TabContentsWrapper* wrapper)
20    : TabContentsObserver(wrapper->tab_contents()),
21      extension_app_(NULL),
22      wrapper_(wrapper) {
23}
24
25ExtensionTabHelper::~ExtensionTabHelper() {
26}
27
28void ExtensionTabHelper::CopyStateFrom(const ExtensionTabHelper& source) {
29  SetExtensionApp(source.extension_app());
30  extension_app_icon_ = source.extension_app_icon_;
31}
32
33void ExtensionTabHelper::PageActionStateChanged() {
34  tab_contents()->NotifyNavigationStateChanged(
35      TabContents::INVALIDATE_PAGE_ACTIONS);
36}
37
38void ExtensionTabHelper::GetApplicationInfo(int32 page_id) {
39  Send(new ExtensionMsg_GetApplicationInfo(routing_id(), page_id));
40}
41
42void ExtensionTabHelper::SetExtensionApp(const Extension* extension) {
43  DCHECK(!extension || extension->GetFullLaunchURL().is_valid());
44  extension_app_ = extension;
45
46  UpdateExtensionAppIcon(extension_app_);
47
48  NotificationService::current()->Notify(
49      NotificationType::TAB_CONTENTS_APPLICATION_EXTENSION_CHANGED,
50      Source<ExtensionTabHelper>(this),
51      NotificationService::NoDetails());
52}
53
54void ExtensionTabHelper::SetExtensionAppById(
55    const std::string& extension_app_id) {
56  if (extension_app_id.empty())
57    return;
58
59  ExtensionService* extension_service =
60      tab_contents()->profile()->GetExtensionService();
61  if (!extension_service || !extension_service->is_ready())
62    return;
63
64  const Extension* extension =
65      extension_service->GetExtensionById(extension_app_id, false);
66  if (extension)
67    SetExtensionApp(extension);
68}
69
70SkBitmap* ExtensionTabHelper::GetExtensionAppIcon() {
71  if (extension_app_icon_.empty())
72    return NULL;
73
74  return &extension_app_icon_;
75}
76
77void ExtensionTabHelper::DidNavigateMainFramePostCommit(
78    const NavigationController::LoadCommittedDetails& details,
79    const ViewHostMsg_FrameNavigate_Params& params) {
80  if (details.is_in_page)
81    return;
82
83  ExtensionService* service = tab_contents()->profile()->GetExtensionService();
84  if (!service)
85    return;
86
87  for (size_t i = 0; i < service->extensions()->size(); ++i) {
88    ExtensionAction* browser_action =
89        service->extensions()->at(i)->browser_action();
90    if (browser_action) {
91      browser_action->ClearAllValuesForTab(
92          tab_contents()->controller().session_id().id());
93      NotificationService::current()->Notify(
94          NotificationType::EXTENSION_BROWSER_ACTION_UPDATED,
95          Source<ExtensionAction>(browser_action),
96          NotificationService::NoDetails());
97    }
98
99    ExtensionAction* page_action =
100        service->extensions()->at(i)->page_action();
101    if (page_action) {
102      page_action->ClearAllValuesForTab(
103          tab_contents()->controller().session_id().id());
104      PageActionStateChanged();
105    }
106  }
107}
108
109bool ExtensionTabHelper::OnMessageReceived(const IPC::Message& message) {
110  bool handled = true;
111  IPC_BEGIN_MESSAGE_MAP(ExtensionTabHelper, message)
112    IPC_MESSAGE_HANDLER(ExtensionHostMsg_DidGetApplicationInfo,
113                        OnDidGetApplicationInfo)
114    IPC_MESSAGE_HANDLER(ExtensionHostMsg_InstallApplication,
115                        OnInstallApplication)
116    IPC_MESSAGE_UNHANDLED(handled = false)
117  IPC_END_MESSAGE_MAP()
118  return handled;
119}
120
121void ExtensionTabHelper::OnDidGetApplicationInfo(
122    int32 page_id, const WebApplicationInfo& info) {
123  web_app_info_ = info;
124
125  if (wrapper_->delegate())
126    wrapper_->delegate()->OnDidGetApplicationInfo(wrapper_, page_id);
127}
128
129void ExtensionTabHelper::OnInstallApplication(const WebApplicationInfo& info) {
130  if (wrapper_->delegate())
131    wrapper_->delegate()->OnInstallApplication(wrapper_, info);
132}
133
134void ExtensionTabHelper::UpdateExtensionAppIcon(const Extension* extension) {
135  extension_app_icon_.reset();
136
137  if (extension) {
138    extension_app_image_loader_.reset(new ImageLoadingTracker(this));
139    extension_app_image_loader_->LoadImage(
140        extension,
141        extension->GetIconResource(Extension::EXTENSION_ICON_SMALLISH,
142                                   ExtensionIconSet::MATCH_EXACTLY),
143        gfx::Size(Extension::EXTENSION_ICON_SMALLISH,
144                  Extension::EXTENSION_ICON_SMALLISH),
145        ImageLoadingTracker::CACHE);
146  } else {
147    extension_app_image_loader_.reset(NULL);
148  }
149}
150
151void ExtensionTabHelper::SetAppIcon(const SkBitmap& app_icon) {
152  extension_app_icon_ = app_icon;
153  tab_contents()->NotifyNavigationStateChanged(TabContents::INVALIDATE_TITLE);
154}
155
156void ExtensionTabHelper::OnImageLoaded(SkBitmap* image,
157                                       const ExtensionResource& resource,
158                                       int index) {
159  if (image) {
160    extension_app_icon_ = *image;
161    tab_contents()->NotifyNavigationStateChanged(TabContents::INVALIDATE_TAB);
162  }
163}
164