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/task_manager/notification_resource_provider.h"
6
7#include "base/strings/string16.h"
8#include "chrome/browser/browser_process.h"
9#include "chrome/browser/chrome_notification_types.h"
10#include "chrome/browser/devtools/devtools_window.h"
11#include "chrome/browser/notifications/balloon_host.h"
12#include "chrome/browser/notifications/balloon_notification_ui_manager.h"
13#include "chrome/browser/task_manager/task_manager.h"
14#include "content/public/browser/notification_service.h"
15#include "content/public/browser/render_process_host.h"
16#include "content/public/browser/web_contents.h"
17#include "grit/generated_resources.h"
18#include "grit/theme_resources.h"
19#include "ui/base/l10n/l10n_util.h"
20#include "ui/base/resource/resource_bundle.h"
21#include "ui/gfx/image/image_skia.h"
22
23namespace task_manager {
24
25class NotificationResource : public Resource {
26 public:
27  explicit NotificationResource(BalloonHost* balloon_host);
28  virtual ~NotificationResource();
29
30  // Resource interface
31  virtual base::string16 GetTitle() const OVERRIDE;
32  virtual base::string16 GetProfileName() const OVERRIDE;
33  virtual gfx::ImageSkia GetIcon() const OVERRIDE;
34  virtual base::ProcessHandle GetProcess() const OVERRIDE;
35  virtual int GetUniqueChildProcessId() const OVERRIDE;
36  virtual Type GetType() const OVERRIDE;
37  virtual bool CanInspect() const OVERRIDE;
38  virtual void Inspect() const OVERRIDE;
39  virtual bool SupportNetworkUsage() const OVERRIDE;
40  virtual void SetSupportNetworkUsage() OVERRIDE { }
41
42 private:
43  // The icon painted for notifications.       .
44  static gfx::ImageSkia* default_icon_;
45
46  // Non-owned pointer to the balloon host.
47  BalloonHost* balloon_host_;
48
49  // Cached data about the balloon host.
50  base::ProcessHandle process_handle_;
51  int pid_;
52  int unique_process_id_;
53  base::string16 title_;
54
55  DISALLOW_COPY_AND_ASSIGN(NotificationResource);
56};
57
58gfx::ImageSkia* NotificationResource::default_icon_ = NULL;
59
60NotificationResource::NotificationResource(BalloonHost* balloon_host)
61    : balloon_host_(balloon_host) {
62  if (!default_icon_) {
63    ResourceBundle& rb = ResourceBundle::GetSharedInstance();
64    default_icon_ = rb.GetImageSkiaNamed(IDR_PLUGINS_FAVICON);
65  }
66  process_handle_ =
67      balloon_host_->web_contents()->GetRenderProcessHost()->GetHandle();
68  unique_process_id_ =
69      balloon_host_->web_contents()->GetRenderProcessHost()->GetID();
70  pid_ = base::GetProcId(process_handle_);
71  title_ = l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_NOTIFICATION_PREFIX,
72                                      balloon_host_->GetSource());
73}
74
75NotificationResource::~NotificationResource() {
76}
77
78base::string16 NotificationResource::GetTitle() const {
79  return title_;
80}
81
82base::string16 NotificationResource::GetProfileName() const {
83  return base::string16();
84}
85
86gfx::ImageSkia NotificationResource::GetIcon() const {
87  return *default_icon_;
88}
89
90base::ProcessHandle NotificationResource::GetProcess() const {
91  return process_handle_;
92}
93
94int NotificationResource::GetUniqueChildProcessId() const {
95  return unique_process_id_;
96}
97
98Resource::Type NotificationResource::GetType() const {
99  return NOTIFICATION;
100}
101
102bool NotificationResource::CanInspect() const {
103  return true;
104}
105
106void NotificationResource::Inspect() const {
107  DevToolsWindow::OpenDevToolsWindow(
108      balloon_host_->web_contents()->GetRenderViewHost());
109}
110
111bool NotificationResource::SupportNetworkUsage() const {
112  return false;
113}
114
115////////////////////////////////////////////////////////////////////////////////
116// NotificationResourceProvider class
117////////////////////////////////////////////////////////////////////////////////
118
119// static
120NotificationResourceProvider*
121NotificationResourceProvider::Create(TaskManager* task_manager) {
122  return new NotificationResourceProvider(task_manager);
123}
124
125NotificationResourceProvider::
126    NotificationResourceProvider(TaskManager* task_manager)
127    : task_manager_(task_manager),
128      updating_(false) {
129}
130
131NotificationResourceProvider::~NotificationResourceProvider() {
132}
133
134Resource* NotificationResourceProvider::GetResource(
135    int origin_pid,
136    int render_process_host_id,
137    int routing_id) {
138  // TODO(johnnyg): provide resources by pid if necessary.
139  return NULL;
140}
141
142void NotificationResourceProvider::StartUpdating() {
143  // MessageCenter does not use Balloons.
144  if (NotificationUIManager::DelegatesToMessageCenter())
145    return;
146
147  DCHECK(!updating_);
148  updating_ = true;
149
150  // Add all the existing BalloonHosts.
151  BalloonNotificationUIManager* balloon_manager =
152      static_cast<BalloonNotificationUIManager*>(
153          g_browser_process->notification_ui_manager());
154  BalloonCollection* collection = balloon_manager->balloon_collection();
155  const BalloonCollection::Balloons& balloons =
156      collection->GetActiveBalloons();
157  for (BalloonCollection::Balloons::const_iterator it = balloons.begin();
158       it != balloons.end(); ++it) {
159    BalloonHost* balloon_host = (*it)->balloon_view()->GetHost();
160    if (balloon_host)
161      AddToTaskManager(balloon_host);
162  }
163  // Register for notifications about extension process changes.
164  registrar_.Add(this, chrome::NOTIFICATION_NOTIFY_BALLOON_CONNECTED,
165                 content::NotificationService::AllSources());
166  registrar_.Add(this, chrome::NOTIFICATION_NOTIFY_BALLOON_DISCONNECTED,
167                 content::NotificationService::AllSources());
168}
169
170void NotificationResourceProvider::StopUpdating() {
171  // MessageCenter does not use Balloons.
172  if (NotificationUIManager::DelegatesToMessageCenter())
173    return;
174
175  DCHECK(updating_);
176  updating_ = false;
177
178  // Unregister for notifications about extension process changes.
179  registrar_.Remove(this, chrome::NOTIFICATION_NOTIFY_BALLOON_CONNECTED,
180                    content::NotificationService::AllSources());
181  registrar_.Remove(this, chrome::NOTIFICATION_NOTIFY_BALLOON_DISCONNECTED,
182                    content::NotificationService::AllSources());
183
184  // Delete all the resources.
185  STLDeleteContainerPairSecondPointers(resources_.begin(), resources_.end());
186  resources_.clear();
187}
188
189void NotificationResourceProvider::Observe(
190    int type,
191    const content::NotificationSource& source,
192    const content::NotificationDetails& details) {
193  switch (type) {
194    case chrome::NOTIFICATION_NOTIFY_BALLOON_CONNECTED:
195      AddToTaskManager(content::Source<BalloonHost>(source).ptr());
196      break;
197    case chrome::NOTIFICATION_NOTIFY_BALLOON_DISCONNECTED:
198      RemoveFromTaskManager(content::Source<BalloonHost>(source).ptr());
199      break;
200    default:
201      NOTREACHED() << "Unexpected notification.";
202      return;
203  }
204}
205
206void NotificationResourceProvider::AddToTaskManager(
207    BalloonHost* balloon_host) {
208  NotificationResource* resource = new NotificationResource(balloon_host);
209  DCHECK(resources_.find(balloon_host) == resources_.end());
210  resources_[balloon_host] = resource;
211  task_manager_->AddResource(resource);
212}
213
214void NotificationResourceProvider::RemoveFromTaskManager(
215    BalloonHost* balloon_host) {
216  if (!updating_)
217    return;
218  std::map<BalloonHost*, NotificationResource*>::iterator iter =
219      resources_.find(balloon_host);
220  if (iter == resources_.end())
221    return;
222
223  // Remove the resource from the Task Manager.
224  NotificationResource* resource = iter->second;
225  task_manager_->RemoveResource(resource);
226
227  // Remove it from the map.
228  resources_.erase(iter);
229
230  // Finally, delete the resource.
231  delete resource;
232}
233
234}  // namespace task_manager
235