OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/arc/notification/arc_notification_item.h" | 5 #include "ui/arc/notification/arc_notification_item.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <vector> | 8 #include <vector> |
9 | 9 |
| 10 #include "base/memory/ptr_util.h" |
10 #include "base/strings/string16.h" | 11 #include "base/strings/string16.h" |
11 #include "base/strings/utf_string_conversions.h" | 12 #include "base/strings/utf_string_conversions.h" |
12 #include "base/task_runner.h" | 13 #include "base/task_runner.h" |
13 #include "base/task_runner_util.h" | 14 #include "base/task_runner_util.h" |
14 #include "base/threading/worker_pool.h" | 15 #include "base/threading/worker_pool.h" |
15 #include "components/arc/bitmap/bitmap_type_converters.h" | 16 #include "components/arc/bitmap/bitmap_type_converters.h" |
16 #include "third_party/skia/include/core/SkCanvas.h" | 17 #include "third_party/skia/include/core/SkCanvas.h" |
17 #include "third_party/skia/include/core/SkPaint.h" | 18 #include "third_party/skia/include/core/SkPaint.h" |
18 #include "ui/gfx/codec/png_codec.h" | 19 #include "ui/gfx/codec/png_codec.h" |
19 #include "ui/gfx/geometry/size.h" | 20 #include "ui/gfx/geometry/size.h" |
20 #include "ui/gfx/image/image.h" | 21 #include "ui/gfx/image/image.h" |
21 #include "ui/gfx/text_elider.h" | 22 #include "ui/gfx/text_elider.h" |
22 #include "ui/message_center/message_center_style.h" | 23 #include "ui/message_center/message_center_style.h" |
23 #include "ui/message_center/notification.h" | 24 #include "ui/message_center/notification.h" |
24 #include "ui/message_center/notification_types.h" | 25 #include "ui/message_center/notification_types.h" |
25 #include "ui/message_center/notifier_settings.h" | 26 #include "ui/message_center/notifier_settings.h" |
26 | 27 |
27 namespace arc { | 28 namespace arc { |
28 | 29 |
29 namespace { | 30 namespace { |
30 | 31 |
31 static const char kNotifierId[] = "ARC_NOTIFICATION"; | 32 constexpr char kNotifierId[] = "ARC_NOTIFICATION"; |
32 | 33 constexpr char kNotificationIdPrefix[] = "ARC_NOTIFICATION_"; |
33 static const char kNotificationIdPrefix[] = "ARC_NOTIFICATION_"; | |
34 | 34 |
35 SkBitmap DecodeImage(const std::vector<uint8_t>& data) { | 35 SkBitmap DecodeImage(const std::vector<uint8_t>& data) { |
36 DCHECK(base::WorkerPool::RunsTasksOnCurrentThread()); | 36 DCHECK(base::WorkerPool::RunsTasksOnCurrentThread()); |
37 DCHECK(!data.empty()); // empty string should be handled in caller. | 37 DCHECK(!data.empty()); // empty string should be handled in caller. |
38 | 38 |
39 // We may decode an image in the browser process since it has been generated | 39 // We may decode an image in the browser process since it has been generated |
40 // in NotificationListerService in Android and should be safe. | 40 // in NotificationListerService in Android and should be safe. |
41 SkBitmap bitmap; | 41 SkBitmap bitmap; |
42 gfx::PNGCodec::Decode(&data[0], data.size(), &bitmap); | 42 gfx::PNGCodec::Decode(&data[0], data.size(), &bitmap); |
43 return bitmap; | 43 return bitmap; |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
79 SkPaint paint; | 79 SkPaint paint; |
80 paint.setFilterQuality(kHigh_SkFilterQuality); | 80 paint.setFilterQuality(kHigh_SkFilterQuality); |
81 SkCanvas container_image(container_bitmap); | 81 SkCanvas container_image(container_bitmap); |
82 container_image.drawColor(message_center::kImageBackgroundColor); | 82 container_image.drawColor(message_center::kImageBackgroundColor); |
83 container_image.drawBitmapRect( | 83 container_image.drawBitmapRect( |
84 original_bitmap, source_rect, SkRect::MakeSize(container_size), &paint); | 84 original_bitmap, source_rect, SkRect::MakeSize(container_size), &paint); |
85 | 85 |
86 return container_bitmap; | 86 return container_bitmap; |
87 } | 87 } |
88 | 88 |
89 // Converts from Android notification priority to Chrome notification priority. | |
90 // On Android, PRIORITY_DEFAULT does not pop up, so this maps PRIORITY_DEFAULT | |
91 // to Chrome's -1 to adapt that behavior. Also, this maps PRIORITY_LOW and _HIGH | |
92 // to -2 and 0 respectively to adjust the value with keeping the order among | |
93 // _LOW, _DEFAULT and _HIGH. | |
94 int convertAndroidPriority(const int android_priority) { | |
95 switch (android_priority) { | |
96 case -2: // PRIORITY_MIN | |
97 case -1: // PRIORITY_LOW | |
98 return -2; | |
99 case 0: // PRIORITY_DEFAULT | |
100 return -1; | |
101 case 1: // PRIORITY_HIGH | |
102 return 0; | |
103 case 2: // PRIORITY_MAX | |
104 return 2; | |
105 default: | |
106 NOTREACHED() << "Invalid Priority: " << android_priority; | |
107 return 0; | |
108 } | |
109 } | |
110 | |
111 class ArcNotificationDelegate : public message_center::NotificationDelegate { | 89 class ArcNotificationDelegate : public message_center::NotificationDelegate { |
112 public: | 90 public: |
113 explicit ArcNotificationDelegate(base::WeakPtr<ArcNotificationItem> item) | 91 explicit ArcNotificationDelegate(base::WeakPtr<ArcNotificationItem> item) |
114 : item_(item) {} | 92 : item_(item) {} |
115 | 93 |
116 void Close(bool by_user) override { | 94 void Close(bool by_user) override { |
117 if (item_) | 95 if (item_) |
118 item_->Close(by_user); | 96 item_->Close(by_user); |
119 } | 97 } |
120 | 98 |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
159 | 137 |
160 void ArcNotificationItem::UpdateWithArcNotificationData( | 138 void ArcNotificationItem::UpdateWithArcNotificationData( |
161 const mojom::ArcNotificationData& data) { | 139 const mojom::ArcNotificationData& data) { |
162 DCHECK(thread_checker_.CalledOnValidThread()); | 140 DCHECK(thread_checker_.CalledOnValidThread()); |
163 DCHECK(notification_key_ == data.key); | 141 DCHECK(notification_key_ == data.key); |
164 | 142 |
165 // Check if a decode task is on-going or not. If |notification_| is non-null, | 143 // Check if a decode task is on-going or not. If |notification_| is non-null, |
166 // a decode task is on-going asynchronously. Otherwise, there is no task. | 144 // a decode task is on-going asynchronously. Otherwise, there is no task. |
167 // TODO(yoshiki): Refactor and remove this check by omitting image decoding | 145 // TODO(yoshiki): Refactor and remove this check by omitting image decoding |
168 // from here. | 146 // from here. |
169 if (notification_) { | 147 if (CacheArcNotificationData(data)) |
170 // Store the latest data to the |newer_data_| property and returns, if the | |
171 // previous decode is still in progress. | |
172 // If old |newer_data_| has been stored, discard the old one. | |
173 newer_data_ = data.Clone(); | |
174 return; | 148 return; |
175 } | |
176 | 149 |
177 message_center::RichNotificationData rich_data; | 150 message_center::RichNotificationData rich_data; |
178 message_center::NotificationType type; | 151 message_center::NotificationType type; |
179 | 152 |
180 switch (data.type) { | 153 switch (data.type) { |
181 case mojom::ArcNotificationType::BASIC: | 154 case mojom::ArcNotificationType::BASIC: |
182 type = message_center::NOTIFICATION_TYPE_BASE_FORMAT; | 155 type = message_center::NOTIFICATION_TYPE_BASE_FORMAT; |
183 break; | 156 break; |
184 case mojom::ArcNotificationType::LIST: | 157 case mojom::ArcNotificationType::LIST: |
185 type = message_center::NOTIFICATION_TYPE_MULTIPLE; | 158 type = message_center::NOTIFICATION_TYPE_MULTIPLE; |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
229 | 202 |
230 for (size_t i = 0; i < data.buttons.size(); i++) { | 203 for (size_t i = 0; i < data.buttons.size(); i++) { |
231 rich_data.buttons.emplace_back( | 204 rich_data.buttons.emplace_back( |
232 base::UTF8ToUTF16(data.buttons.at(i)->label.get())); | 205 base::UTF8ToUTF16(data.buttons.at(i)->label.get())); |
233 } | 206 } |
234 | 207 |
235 // If the client is old (version < 1), both |no_clear| and |ongoing_event| | 208 // If the client is old (version < 1), both |no_clear| and |ongoing_event| |
236 // are false. | 209 // are false. |
237 rich_data.pinned = (data.no_clear || data.ongoing_event); | 210 rich_data.pinned = (data.no_clear || data.ongoing_event); |
238 | 211 |
239 rich_data.priority = convertAndroidPriority(data.priority); | 212 rich_data.priority = ConvertAndroidPriority(data.priority); |
240 | 213 |
241 // The identifier of the notifier, which is used to distinguish the notifiers | 214 // The identifier of the notifier, which is used to distinguish the notifiers |
242 // in the message center. | 215 // in the message center. |
243 message_center::NotifierId notifier_id( | 216 message_center::NotifierId notifier_id( |
244 message_center::NotifierId::SYSTEM_COMPONENT, kNotifierId); | 217 message_center::NotifierId::SYSTEM_COMPONENT, kNotifierId); |
245 notifier_id.profile_id = profile_id_.GetUserEmail(); | 218 notifier_id.profile_id = profile_id_.GetUserEmail(); |
246 | 219 |
247 DCHECK(!data.title.is_null()); | 220 DCHECK(!data.title.is_null()); |
248 DCHECK(!data.message.is_null()); | 221 DCHECK(!data.message.is_null()); |
249 notification_.reset(new message_center::Notification( | 222 SetNotification(base::WrapUnique(new message_center::Notification( |
250 type, notification_id_, base::UTF8ToUTF16(data.title.get()), | 223 type, notification_id_, base::UTF8ToUTF16(data.title.get()), |
251 base::UTF8ToUTF16(data.message.get()), | 224 base::UTF8ToUTF16(data.message.get()), |
252 gfx::Image(), // icon image: Will be overriden later. | 225 gfx::Image(), // icon image: Will be overriden later. |
253 base::UTF8ToUTF16("arc"), // display source | 226 base::UTF8ToUTF16("arc"), // display source |
254 GURL(), // empty origin url, for system component | 227 GURL(), // empty origin url, for system component |
255 notifier_id, rich_data, | 228 notifier_id, rich_data, |
256 new ArcNotificationDelegate(weak_ptr_factory_.GetWeakPtr()))); | 229 new ArcNotificationDelegate(weak_ptr_factory_.GetWeakPtr())))); |
257 | 230 |
258 DCHECK(!data.icon_data.is_null()); | 231 DCHECK(!data.icon_data.is_null()); |
259 if (data.icon_data.size() == 0) { | 232 if (data.icon_data.size() == 0) { |
260 OnImageDecoded(SkBitmap()); // Pass an empty bitmap. | 233 OnImageDecoded(SkBitmap()); // Pass an empty bitmap. |
261 return; | 234 return; |
262 } | 235 } |
263 | 236 |
264 // TODO(yoshiki): Remove decoding by passing a bitmap directly from Android. | 237 // TODO(yoshiki): Remove decoding by passing a bitmap directly from Android. |
265 base::PostTaskAndReplyWithResult( | 238 base::PostTaskAndReplyWithResult( |
266 base::WorkerPool::GetTaskRunner(true).get(), FROM_HERE, | 239 base::WorkerPool::GetTaskRunner(true).get(), FROM_HERE, |
(...skipping 23 matching lines...) Expand all Loading... |
290 | 263 |
291 void ArcNotificationItem::Click() { | 264 void ArcNotificationItem::Click() { |
292 manager_->SendNotificationClickedOnChrome(notification_key_); | 265 manager_->SendNotificationClickedOnChrome(notification_key_); |
293 } | 266 } |
294 | 267 |
295 void ArcNotificationItem::ButtonClick(int button_index) { | 268 void ArcNotificationItem::ButtonClick(int button_index) { |
296 manager_->SendNotificationButtonClickedOnChrome( | 269 manager_->SendNotificationButtonClickedOnChrome( |
297 notification_key_, button_index); | 270 notification_key_, button_index); |
298 } | 271 } |
299 | 272 |
300 void ArcNotificationItem::OnImageDecoded(const SkBitmap& bitmap) { | 273 // Converts from Android notification priority to Chrome notification priority. |
301 DCHECK(thread_checker_.CalledOnValidThread()); | 274 // On Android, PRIORITY_DEFAULT does not pop up, so this maps PRIORITY_DEFAULT |
| 275 // to Chrome's -1 to adapt that behavior. Also, this maps PRIORITY_LOW and _HIGH |
| 276 // to -2 and 0 respectively to adjust the value with keeping the order among |
| 277 // _LOW, _DEFAULT and _HIGH. |
| 278 // static |
| 279 int ArcNotificationItem::ConvertAndroidPriority(int android_priority) { |
| 280 switch (android_priority) { |
| 281 case -2: // PRIORITY_MIN |
| 282 case -1: // PRIORITY_LOW |
| 283 return -2; |
| 284 case 0: // PRIORITY_DEFAULT |
| 285 return -1; |
| 286 case 1: // PRIORITY_HIGH |
| 287 return 0; |
| 288 case 2: // PRIORITY_MAX |
| 289 return 2; |
| 290 default: |
| 291 NOTREACHED() << "Invalid Priority: " << android_priority; |
| 292 return 0; |
| 293 } |
| 294 } |
302 | 295 |
303 gfx::Image image = gfx::Image::CreateFrom1xBitmap(bitmap); | 296 bool ArcNotificationItem::CacheArcNotificationData( |
304 notification_->set_icon(image); | 297 const mojom::ArcNotificationData& data) { |
| 298 if (!notification_) |
| 299 return false; |
305 | 300 |
| 301 // Store the latest data to the |newer_data_| property if there is a pending |
| 302 // |notification_|. |
| 303 // If old |newer_data_| has been stored, discard the old one. |
| 304 newer_data_ = data.Clone(); |
| 305 return true; |
| 306 } |
| 307 |
| 308 void ArcNotificationItem::SetNotification( |
| 309 std::unique_ptr<message_center::Notification> notification) { |
| 310 notification_ = std::move(notification); |
| 311 } |
| 312 |
| 313 void ArcNotificationItem::AddToMessageCenter() { |
306 DCHECK(notification_); | 314 DCHECK(notification_); |
307 message_center_->AddNotification(std::move(notification_)); | 315 message_center_->AddNotification(std::move(notification_)); |
308 | 316 |
309 if (newer_data_) { | 317 if (newer_data_) { |
310 // There is the newer data, so updates again. | 318 // There is the newer data, so updates again. |
311 mojom::ArcNotificationDataPtr data(std::move(newer_data_)); | 319 mojom::ArcNotificationDataPtr data(std::move(newer_data_)); |
312 UpdateWithArcNotificationData(*data); | 320 UpdateWithArcNotificationData(*data); |
313 } | 321 } |
314 } | 322 } |
315 | 323 |
| 324 bool ArcNotificationItem::CalledOnValidThread() const { |
| 325 return thread_checker_.CalledOnValidThread(); |
| 326 } |
| 327 |
| 328 void ArcNotificationItem::OnImageDecoded(const SkBitmap& bitmap) { |
| 329 DCHECK(thread_checker_.CalledOnValidThread()); |
| 330 |
| 331 gfx::Image image = gfx::Image::CreateFrom1xBitmap(bitmap); |
| 332 notification_->set_icon(image); |
| 333 AddToMessageCenter(); |
| 334 } |
| 335 |
316 } // namespace arc | 336 } // namespace arc |
OLD | NEW |