OLD | NEW |
| (Empty) |
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/ui/views/ash/balloon_view_ash.h" | |
6 | |
7 #include "ash/shell.h" | |
8 #include "ash/system/web_notification/web_notification_tray.h" | |
9 #include "base/logging.h" | |
10 #include "base/memory/weak_ptr.h" | |
11 #include "base/values.h" | |
12 #include "chrome/browser/favicon/favicon_util.h" | |
13 #include "chrome/browser/notifications/balloon_collection.h" | |
14 #include "chrome/browser/notifications/notification.h" | |
15 #include "content/public/browser/render_process_host.h" | |
16 #include "content/public/browser/render_view_host.h" | |
17 #include "content/public/browser/site_instance.h" | |
18 #include "content/public/browser/web_contents.h" | |
19 #include "content/public/browser/web_contents_delegate.h" | |
20 #include "content/public/browser/web_contents_observer.h" | |
21 #include "ipc/ipc_message.h" | |
22 #include "ipc/ipc_message_macros.h" | |
23 #include "third_party/skia/include/core/SkBitmap.h" | |
24 #include "ui/gfx/image/image.h" | |
25 #include "ui/message_center/message_center.h" | |
26 #include "ui/message_center/message_center_constants.h" | |
27 #include "ui/message_center/notification_types.h" | |
28 #include "webkit/glue/image_resource_fetcher.h" | |
29 | |
30 namespace { | |
31 | |
32 typedef base::Callback<void(const gfx::Image&)> SetImageCallback; | |
33 | |
34 const int kPrimaryIconImageSize = 64; | |
35 const int kSecondaryIconImageSize = 15; | |
36 | |
37 // static | |
38 message_center::MessageCenter* GetMessageCenter() { | |
39 return ash::Shell::GetInstance()->GetWebNotificationTray()->message_center(); | |
40 } | |
41 | |
42 } // namespace | |
43 | |
44 // TODO(dharcourt): Delay showing the notification until all images are | |
45 // downloaded, and return an error to the notification creator/API caller | |
46 // instead of showing a partial notification if any image download fails. | |
47 class BalloonViewAsh::ImageDownload | |
48 : public base::SupportsWeakPtr<ImageDownload> { | |
49 public: | |
50 // Note that the setter callback passed in will not be called if the image | |
51 // download fails for any reason. | |
52 ImageDownload(const Notification& notification, | |
53 const GURL& url, | |
54 int size, | |
55 const SetImageCallback& callback); | |
56 virtual ~ImageDownload(); | |
57 | |
58 private: | |
59 // FaviconHelper callback. | |
60 virtual void Downloaded(int download_id, | |
61 const GURL& image_url, | |
62 int requested_size, | |
63 const std::vector<SkBitmap>& bitmaps); | |
64 | |
65 const GURL& url_; | |
66 int size_; | |
67 SetImageCallback callback_; | |
68 | |
69 DISALLOW_COPY_AND_ASSIGN(ImageDownload); | |
70 }; | |
71 | |
72 BalloonViewAsh::ImageDownload::ImageDownload(const Notification& notification, | |
73 const GURL& url, | |
74 int size, | |
75 const SetImageCallback& callback) | |
76 : url_(url), | |
77 size_(size), | |
78 callback_(callback) { | |
79 content::RenderViewHost* host = notification.GetRenderViewHost(); | |
80 if (!host) { | |
81 LOG(WARNING) << "Notification needs an image but has no RenderViewHost"; | |
82 return; | |
83 } | |
84 | |
85 content::WebContents* contents = | |
86 content::WebContents::FromRenderViewHost(host); | |
87 if (!contents) { | |
88 LOG(WARNING) << "Notification needs an image but has no WebContents"; | |
89 return; | |
90 } | |
91 | |
92 contents->DownloadImage(url_, | |
93 false, | |
94 size_, | |
95 base::Bind(&ImageDownload::Downloaded,AsWeakPtr())); | |
96 } | |
97 | |
98 | |
99 BalloonViewAsh::ImageDownload::~ImageDownload() { | |
100 } | |
101 | |
102 void BalloonViewAsh::ImageDownload::Downloaded( | |
103 int download_id, | |
104 const GURL& image_url, | |
105 int requested_size, | |
106 const std::vector<SkBitmap>& bitmaps) { | |
107 if (bitmaps.empty()) | |
108 return; | |
109 gfx::Image image = gfx::Image::CreateFrom1xBitmap(bitmaps[0]); | |
110 callback_.Run(image); | |
111 } | |
112 | |
113 BalloonViewAsh::BalloonViewAsh(BalloonCollection* collection) | |
114 : collection_(collection), | |
115 balloon_(NULL) { | |
116 } | |
117 | |
118 BalloonViewAsh::~BalloonViewAsh() { | |
119 } | |
120 | |
121 // BalloonView interface. | |
122 void BalloonViewAsh::Show(Balloon* balloon) { | |
123 balloon_ = balloon; | |
124 const Notification& notification = balloon_->notification(); | |
125 notification_id_ = notification.notification_id(); | |
126 GetMessageCenter()->AddNotification(notification.type(), | |
127 notification_id_, | |
128 notification.title(), | |
129 notification.body(), | |
130 notification.display_source(), | |
131 balloon->GetExtensionId(), | |
132 notification.optional_fields()); | |
133 DownloadImages(notification); | |
134 } | |
135 | |
136 void BalloonViewAsh::Update() { | |
137 std::string previous_notification_id = notification_id_; | |
138 const Notification& notification = balloon_->notification(); | |
139 notification_id_ = notification.notification_id(); | |
140 GetMessageCenter()->UpdateNotification(previous_notification_id, | |
141 notification_id_, | |
142 notification.title(), | |
143 notification.body(), | |
144 notification.optional_fields()); | |
145 DownloadImages(notification); | |
146 } | |
147 | |
148 void BalloonViewAsh::RepositionToBalloon() { | |
149 } | |
150 | |
151 void BalloonViewAsh::Close(bool by_user) { | |
152 Notification notification(balloon_->notification()); | |
153 collection_->OnBalloonClosed(balloon_); // Deletes balloon. | |
154 notification.Close(by_user); | |
155 GetMessageCenter()->RemoveNotification(notification.notification_id()); | |
156 } | |
157 | |
158 gfx::Size BalloonViewAsh::GetSize() const { | |
159 return gfx::Size(); | |
160 } | |
161 | |
162 BalloonHost* BalloonViewAsh::GetHost() const { | |
163 return NULL; | |
164 } | |
165 | |
166 void BalloonViewAsh::SetNotificationIcon(const std::string& notification_id, | |
167 const gfx::Image& image) { | |
168 GetMessageCenter()->SetNotificationIcon(notification_id, image); | |
169 } | |
170 | |
171 void BalloonViewAsh::SetNotificationImage(const std::string& notification_id, | |
172 const gfx::Image& image) { | |
173 GetMessageCenter()->SetNotificationImage(notification_id, image); | |
174 } | |
175 | |
176 void BalloonViewAsh::SetNotificationButtonIcon( | |
177 const std::string& notification_id, | |
178 int button_index, | |
179 const gfx::Image& image) { | |
180 GetMessageCenter()->SetNotificationButtonIcon(notification_id, button_index, | |
181 image); | |
182 } | |
183 | |
184 void BalloonViewAsh::DownloadImages(const Notification& notification) { | |
185 // Cancel any previous downloads. | |
186 downloads_.clear(); | |
187 | |
188 // Set the notification's primary icon, or start a download for it. | |
189 if (!notification.icon().IsEmpty()) { | |
190 SetNotificationIcon(notification_id_, notification.icon()); | |
191 } else if (!notification.icon_url().is_empty()) { | |
192 downloads_.push_back(linked_ptr<ImageDownload>(new ImageDownload( | |
193 notification, notification.icon_url(), | |
194 message_center::kNotificationIconSize, | |
195 base::Bind(&BalloonViewAsh::SetNotificationIcon, | |
196 base::Unretained(this), notification.notification_id())))); | |
197 } | |
198 | |
199 const base::DictionaryValue* optional_fields = notification.optional_fields(); | |
200 if (optional_fields) { | |
201 // Start a download for the notification's image if appropriate. | |
202 if (optional_fields->HasKey(message_center::kImageUrlKey)) { | |
203 string16 url; | |
204 optional_fields->GetString(message_center::kImageUrlKey, &url); | |
205 if (!url.empty()) { | |
206 downloads_.push_back(linked_ptr<ImageDownload>(new ImageDownload( | |
207 notification, | |
208 GURL(url), | |
209 message_center::kNotificationPreferredImageSize, | |
210 base::Bind(&BalloonViewAsh::SetNotificationImage, | |
211 base::Unretained(this), | |
212 notification.notification_id())))); | |
213 } | |
214 } | |
215 | |
216 // Start a download for the notification's button icons if appropriate. | |
217 const char* kButtonIconKeys[] = { message_center::kButtonOneIconUrlKey, | |
218 message_center::kButtonTwoIconUrlKey }; | |
219 for (size_t i = 0; i < arraysize(kButtonIconKeys); ++i) { | |
220 if (optional_fields->HasKey(kButtonIconKeys[i])) { | |
221 string16 url; | |
222 optional_fields->GetString(kButtonIconKeys[i], &url); | |
223 if (!url.empty()) { | |
224 downloads_.push_back(linked_ptr<ImageDownload>(new ImageDownload( | |
225 notification, | |
226 GURL(url), | |
227 message_center::kNotificationButtonIconSize, | |
228 base::Bind(&BalloonViewAsh::SetNotificationButtonIcon, | |
229 base::Unretained(this), | |
230 notification.notification_id(), | |
231 i)))); | |
232 } | |
233 } | |
234 } | |
235 } | |
236 } | |
OLD | NEW |