| 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 |