blob: badceb59aa95d85a6d262c0350609d95142e4014 [file] [log] [blame]
Avi Drissman4e1b7bc32022-09-15 14:03:501// Copyright 2015 The Chromium Authors
peter05cb4db2015-03-13 14:33:382// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Richard Knoll2e136ef2019-03-07 09:45:115#include "content/browser/notifications/notification_database_conversions.h"
peter05cb4db2015-03-13 14:33:386
avib7348942015-12-25 20:57:107#include <stddef.h>
8
mostynbea64f7c2016-04-03 16:03:449#include <memory>
Arthur Sonzognic686e8f2024-01-11 08:36:3710#include <optional>
mostynbea64f7c2016-04-03 16:03:4411
Hans Wennborg0917de892020-04-28 20:21:1512#include "base/check.h"
Avi Drissman02553b82024-10-16 16:14:1613#include "base/containers/span.h"
Hans Wennborg0917de892020-04-28 20:21:1514#include "base/notreached.h"
peter05cb4db2015-03-13 14:33:3815#include "base/strings/utf_string_conversions.h"
Richard Knoll2e136ef2019-03-07 09:45:1116#include "base/threading/thread_restrictions.h"
peterb8afbbe2016-02-01 14:01:1117#include "base/time/time.h"
peter05cb4db2015-03-13 14:33:3818#include "content/browser/notifications/notification_database_data.pb.h"
Richard Knoll2e136ef2019-03-07 09:45:1119#include "content/browser/notifications/notification_database_resources.pb.h"
peter7b79a192015-03-17 22:14:0520#include "content/public/browser/notification_database_data.h"
Richard Knoll2e136ef2019-03-07 09:45:1121#include "third_party/blink/public/common/notifications/notification_resources.h"
Gyuyoung Kim74e4058a2019-09-19 08:06:3122#include "third_party/blink/public/mojom/notifications/notification.mojom.h"
Richard Knoll2e136ef2019-03-07 09:45:1123#include "third_party/skia/include/core/SkBitmap.h"
24#include "ui/gfx/codec/png_codec.h"
peter05cb4db2015-03-13 14:33:3825
26namespace content {
27
Richard Knoll2e136ef2019-03-07 09:45:1128namespace {
29
30// static
31SkBitmap DeserializeImage(const std::string& image_data) {
32 base::AssertLongCPUWorkAllowed();
Avi Drissman02553b82024-10-16 16:14:1633 return gfx::PNGCodec::Decode(base::as_byte_span(image_data));
Richard Knoll2e136ef2019-03-07 09:45:1134}
35
36// static
37std::vector<unsigned char> SerializeImage(const SkBitmap& image) {
38 base::AssertLongCPUWorkAllowed();
Avi Drissman02553b82024-10-16 16:14:1639 std::optional<std::vector<uint8_t>> image_data =
40 gfx::PNGCodec::EncodeBGRASkBitmap(image, /*discard_transparency=*/false);
41 return image_data.value_or(std::vector<uint8_t>());
Richard Knoll2e136ef2019-03-07 09:45:1142}
43
44} // namespace
45
peter7b79a192015-03-17 22:14:0546bool DeserializeNotificationDatabaseData(const std::string& input,
47 NotificationDatabaseData* output) {
48 DCHECK(output);
peter05cb4db2015-03-13 14:33:3849
peter05cb4db2015-03-13 14:33:3850 NotificationDatabaseDataProto message;
51 if (!message.ParseFromString(input))
52 return false;
53
peter7b79a192015-03-17 22:14:0554 output->notification_id = message.notification_id();
55 output->origin = GURL(message.origin());
56 output->service_worker_registration_id =
57 message.service_worker_registration_id();
Sharon Yangd8174692018-05-18 16:49:0558 output->replaced_existing_notification =
59 message.replaced_existing_notification();
60 output->num_clicks = message.num_clicks();
61 output->num_action_button_clicks = message.num_action_button_clicks();
62 output->creation_time_millis = base::Time::FromDeltaSinceWindowsEpoch(
Peter Kastinge5a38ed2021-10-02 03:06:3563 base::Microseconds(message.creation_time_millis()));
Sharon Yangd0ad8062018-08-01 10:31:4964
65 if (message.has_time_until_close_millis()) {
66 output->time_until_close_millis =
Peter Kastinge5a38ed2021-10-02 03:06:3567 base::Milliseconds(message.time_until_close_millis());
Richard Knoll2e136ef2019-03-07 09:45:1168 } else {
Arthur Sonzognic686e8f2024-01-11 08:36:3769 output->time_until_close_millis = std::nullopt;
Sharon Yangd0ad8062018-08-01 10:31:4970 }
71 if (message.has_time_until_first_click_millis()) {
Peter Kastinge5a38ed2021-10-02 03:06:3572 output->time_until_first_click_millis =
73 base::Milliseconds(message.time_until_first_click_millis());
Richard Knoll2e136ef2019-03-07 09:45:1174 } else {
Arthur Sonzognic686e8f2024-01-11 08:36:3775 output->time_until_first_click_millis = std::nullopt;
Sharon Yangd0ad8062018-08-01 10:31:4976 }
77 if (message.has_time_until_last_click_millis()) {
Peter Kastinge5a38ed2021-10-02 03:06:3578 output->time_until_last_click_millis =
79 base::Milliseconds(message.time_until_last_click_millis());
Richard Knoll2e136ef2019-03-07 09:45:1180 } else {
Arthur Sonzognic686e8f2024-01-11 08:36:3781 output->time_until_last_click_millis = std::nullopt;
Sharon Yangd0ad8062018-08-01 10:31:4982 }
Sharon Yangd8174692018-05-18 16:49:0583
84 switch (message.closed_reason()) {
85 case NotificationDatabaseDataProto::USER:
86 output->closed_reason = NotificationDatabaseData::ClosedReason::USER;
87 break;
88 case NotificationDatabaseDataProto::DEVELOPER:
89 output->closed_reason = NotificationDatabaseData::ClosedReason::DEVELOPER;
90 break;
91 case NotificationDatabaseDataProto::UNKNOWN:
92 output->closed_reason = NotificationDatabaseData::ClosedReason::UNKNOWN;
93 break;
94 }
peter05cb4db2015-03-13 14:33:3895
Han Leon96d6b6e8c22018-09-06 06:21:0696 blink::PlatformNotificationData* notification_data =
97 &output->notification_data;
peter05cb4db2015-03-13 14:33:3898 const NotificationDatabaseDataProto::NotificationData& payload =
99 message.notification_data();
100
peter7b79a192015-03-17 22:14:05101 notification_data->title = base::UTF8ToUTF16(payload.title());
peteraaa9ca532015-08-04 14:53:24102
103 switch (payload.direction()) {
104 case NotificationDatabaseDataProto::NotificationData::LEFT_TO_RIGHT:
105 notification_data->direction =
Amos Lim3dce63b772019-02-21 16:56:34106 blink::mojom::NotificationDirection::LEFT_TO_RIGHT;
peteraaa9ca532015-08-04 14:53:24107 break;
108 case NotificationDatabaseDataProto::NotificationData::RIGHT_TO_LEFT:
109 notification_data->direction =
Amos Lim3dce63b772019-02-21 16:56:34110 blink::mojom::NotificationDirection::RIGHT_TO_LEFT;
peteraaa9ca532015-08-04 14:53:24111 break;
112 case NotificationDatabaseDataProto::NotificationData::AUTO:
Amos Lim3dce63b772019-02-21 16:56:34113 notification_data->direction = blink::mojom::NotificationDirection::AUTO;
peteraaa9ca532015-08-04 14:53:24114 break;
115 }
116
peter7b79a192015-03-17 22:14:05117 notification_data->lang = payload.lang();
118 notification_data->body = base::UTF8ToUTF16(payload.body());
119 notification_data->tag = payload.tag();
johnme578c5cc82016-08-24 22:38:54120 notification_data->image = GURL(payload.image());
peter7b79a192015-03-17 22:14:05121 notification_data->icon = GURL(payload.icon());
mvanouwerkerk2dc02002016-03-18 10:21:45122 notification_data->badge = GURL(payload.badge());
sh919.park1593bf82015-05-10 21:30:08123
124 if (payload.vibration_pattern().size() > 0) {
125 notification_data->vibration_pattern.assign(
peter372525c2015-11-20 16:07:17126 payload.vibration_pattern().begin(), payload.vibration_pattern().end());
Peter Beverloo9ea53072018-06-22 14:20:59127 } else {
128 notification_data->vibration_pattern.clear();
sh919.park1593bf82015-05-10 21:30:08129 }
130
Richard Knoll2e136ef2019-03-07 09:45:11131 notification_data->timestamp = base::Time::FromDeltaSinceWindowsEpoch(
Peter Kastinge5a38ed2021-10-02 03:06:35132 base::Microseconds(payload.timestamp()));
Richard Knoll2e136ef2019-03-07 09:45:11133
harkness39c49fe2016-02-10 20:15:27134 notification_data->renotify = payload.renotify();
peter7b79a192015-03-17 22:14:05135 notification_data->silent = payload.silent();
johnme046341a2015-09-01 14:40:02136 notification_data->require_interaction = payload.require_interaction();
peter05cb4db2015-03-13 14:33:38137
Bartosz Fabianowski85a823812015-04-16 10:27:51138 if (payload.data().length()) {
139 notification_data->data.assign(payload.data().begin(),
140 payload.data().end());
Peter Beverloo9ea53072018-06-22 14:20:59141 } else {
142 notification_data->data.clear();
Bartosz Fabianowski85a823812015-04-16 10:27:51143 }
144
Peter Beverloo9ea53072018-06-22 14:20:59145 notification_data->actions.clear();
146
John Mellor5f170b92015-08-05 10:33:50147 for (const auto& payload_action : payload.actions()) {
Gyuyoung Kim109ae2d32021-02-26 08:40:56148 auto action = blink::mojom::NotificationAction::New();
nsatragnod1c3e8402016-04-07 12:32:20149
150 switch (payload_action.type()) {
151 case NotificationDatabaseDataProto::NotificationAction::BUTTON:
Gyuyoung Kim109ae2d32021-02-26 08:40:56152 action->type = blink::mojom::NotificationActionType::BUTTON;
nsatragnod1c3e8402016-04-07 12:32:20153 break;
154 case NotificationDatabaseDataProto::NotificationAction::TEXT:
Gyuyoung Kim109ae2d32021-02-26 08:40:56155 action->type = blink::mojom::NotificationActionType::TEXT;
nsatragnod1c3e8402016-04-07 12:32:20156 break;
157 default:
Peter Boströmfc7ddc182024-10-31 19:37:21158 NOTREACHED();
nsatragnod1c3e8402016-04-07 12:32:20159 }
160
Gyuyoung Kim109ae2d32021-02-26 08:40:56161 action->action = payload_action.action();
162 action->title = base::UTF8ToUTF16(payload_action.title());
163 action->icon = GURL(payload_action.icon());
nsatragnod1c3e8402016-04-07 12:32:20164 if (payload_action.has_placeholder()) {
Gyuyoung Kim109ae2d32021-02-26 08:40:56165 action->placeholder = base::UTF8ToUTF16(payload_action.placeholder());
nsatragnod1c3e8402016-04-07 12:32:20166 }
Gyuyoung Kim109ae2d32021-02-26 08:40:56167 notification_data->actions.push_back(std::move(action));
John Mellor5f170b92015-08-05 10:33:50168 }
169
Richard Knoll2e136ef2019-03-07 09:45:11170 if (payload.has_show_trigger_timestamp()) {
171 notification_data->show_trigger_timestamp =
172 base::Time::FromDeltaSinceWindowsEpoch(
Peter Kastinge5a38ed2021-10-02 03:06:35173 base::Microseconds(payload.show_trigger_timestamp()));
Richard Knoll2e136ef2019-03-07 09:45:11174 } else {
Arthur Sonzognic686e8f2024-01-11 08:36:37175 notification_data->show_trigger_timestamp = std::nullopt;
Richard Knoll2e136ef2019-03-07 09:45:11176 }
177
178 output->has_triggered = message.has_triggered();
179
Richard Knoll5dcde8862021-07-16 14:38:56180 output->is_shown_by_browser = message.is_shown_by_browser();
181
Arthur Sonzognic686e8f2024-01-11 08:36:37182 output->notification_resources = std::nullopt;
Richard Knoll2e136ef2019-03-07 09:45:11183
Sarah Krakowiak Criele7e3aac2025-04-10 15:38:27184 output->serialized_metadata =
185 std::map<std::string, std::string>(message.serialized_metadata().begin(),
186 message.serialized_metadata().end());
187
peter05cb4db2015-03-13 14:33:38188 return true;
189}
190
peter7b79a192015-03-17 22:14:05191bool SerializeNotificationDatabaseData(const NotificationDatabaseData& input,
192 std::string* output) {
peter05cb4db2015-03-13 14:33:38193 DCHECK(output);
194
Richard Knoll2e136ef2019-03-07 09:45:11195 auto payload =
196 std::make_unique<NotificationDatabaseDataProto::NotificationData>();
peter7b79a192015-03-17 22:14:05197
Han Leon96d6b6e8c22018-09-06 06:21:06198 const blink::PlatformNotificationData& notification_data =
199 input.notification_data;
peter7b79a192015-03-17 22:14:05200
peter05cb4db2015-03-13 14:33:38201 payload->set_title(base::UTF16ToUTF8(notification_data.title));
peteraaa9ca532015-08-04 14:53:24202
203 switch (notification_data.direction) {
Amos Lim3dce63b772019-02-21 16:56:34204 case blink::mojom::NotificationDirection::LEFT_TO_RIGHT:
peteraaa9ca532015-08-04 14:53:24205 payload->set_direction(
206 NotificationDatabaseDataProto::NotificationData::LEFT_TO_RIGHT);
207 break;
Amos Lim3dce63b772019-02-21 16:56:34208 case blink::mojom::NotificationDirection::RIGHT_TO_LEFT:
peteraaa9ca532015-08-04 14:53:24209 payload->set_direction(
210 NotificationDatabaseDataProto::NotificationData::RIGHT_TO_LEFT);
211 break;
Amos Lim3dce63b772019-02-21 16:56:34212 case blink::mojom::NotificationDirection::AUTO:
peteraaa9ca532015-08-04 14:53:24213 payload->set_direction(
214 NotificationDatabaseDataProto::NotificationData::AUTO);
215 break;
216 }
217
peter05cb4db2015-03-13 14:33:38218 payload->set_lang(notification_data.lang);
219 payload->set_body(base::UTF16ToUTF8(notification_data.body));
220 payload->set_tag(notification_data.tag);
johnme578c5cc82016-08-24 22:38:54221 payload->set_image(notification_data.image.spec());
peter05cb4db2015-03-13 14:33:38222 payload->set_icon(notification_data.icon.spec());
mvanouwerkerk2dc02002016-03-18 10:21:45223 payload->set_badge(notification_data.badge.spec());
sh919.park1593bf82015-05-10 21:30:08224
225 for (size_t i = 0; i < notification_data.vibration_pattern.size(); ++i)
226 payload->add_vibration_pattern(notification_data.vibration_pattern[i]);
227
Richard Knoll2e136ef2019-03-07 09:45:11228 payload->set_timestamp(
229 notification_data.timestamp.ToDeltaSinceWindowsEpoch().InMicroseconds());
harkness39c49fe2016-02-10 20:15:27230 payload->set_renotify(notification_data.renotify);
peter05cb4db2015-03-13 14:33:38231 payload->set_silent(notification_data.silent);
johnme046341a2015-09-01 14:40:02232 payload->set_require_interaction(notification_data.require_interaction);
peter05cb4db2015-03-13 14:33:38233
Bartosz Fabianowski85a823812015-04-16 10:27:51234 if (notification_data.data.size()) {
235 payload->set_data(&notification_data.data.front(),
236 notification_data.data.size());
237 }
238
Gyuyoung Kim109ae2d32021-02-26 08:40:56239 for (const auto& action : notification_data.actions) {
John Mellor5f170b92015-08-05 10:33:50240 NotificationDatabaseDataProto::NotificationAction* payload_action =
241 payload->add_actions();
nsatragnod1c3e8402016-04-07 12:32:20242
Gyuyoung Kim109ae2d32021-02-26 08:40:56243 switch (action->type) {
Gyuyoung Kim3fd1c302020-10-27 07:57:15244 case blink::mojom::NotificationActionType::BUTTON:
nsatragnod1c3e8402016-04-07 12:32:20245 payload_action->set_type(
246 NotificationDatabaseDataProto::NotificationAction::BUTTON);
247 break;
Gyuyoung Kim3fd1c302020-10-27 07:57:15248 case blink::mojom::NotificationActionType::TEXT:
nsatragnod1c3e8402016-04-07 12:32:20249 payload_action->set_type(
250 NotificationDatabaseDataProto::NotificationAction::TEXT);
251 break;
252 default:
Peter Boströmfc7ddc182024-10-31 19:37:21253 NOTREACHED() << "Unknown action type: " << action->type;
nsatragnod1c3e8402016-04-07 12:32:20254 }
255
Gyuyoung Kim109ae2d32021-02-26 08:40:56256 payload_action->set_action(action->action);
257 payload_action->set_title(base::UTF16ToUTF8(action->title));
258 payload_action->set_icon(action->icon.spec());
nsatragnod1c3e8402016-04-07 12:32:20259
Gyuyoung Kim109ae2d32021-02-26 08:40:56260 if (action->placeholder) {
261 payload_action->set_placeholder(base::UTF16ToUTF8(*action->placeholder));
nsatragnod1c3e8402016-04-07 12:32:20262 }
John Mellor5f170b92015-08-05 10:33:50263 }
264
Richard Knoll2e136ef2019-03-07 09:45:11265 if (notification_data.show_trigger_timestamp.has_value()) {
266 payload->set_show_trigger_timestamp(
267 notification_data.show_trigger_timestamp.value()
268 .ToDeltaSinceWindowsEpoch()
269 .InMicroseconds());
270 }
271
peter05cb4db2015-03-13 14:33:38272 NotificationDatabaseDataProto message;
peter7b79a192015-03-17 22:14:05273 message.set_notification_id(input.notification_id);
274 message.set_origin(input.origin.spec());
peter05cb4db2015-03-13 14:33:38275 message.set_service_worker_registration_id(
peter7b79a192015-03-17 22:14:05276 input.service_worker_registration_id);
peter05cb4db2015-03-13 14:33:38277 message.set_allocated_notification_data(payload.release());
Sharon Yangd8174692018-05-18 16:49:05278 message.set_replaced_existing_notification(
279 input.replaced_existing_notification);
280 message.set_num_clicks(input.num_clicks);
281 message.set_num_action_button_clicks(input.num_action_button_clicks);
282 message.set_creation_time_millis(
283 input.creation_time_millis.ToDeltaSinceWindowsEpoch().InMicroseconds());
Sharon Yang71bfb2be2018-06-04 16:04:40284 if (input.time_until_first_click_millis.has_value()) {
285 message.set_time_until_first_click_millis(
286 input.time_until_first_click_millis.value().InMilliseconds());
287 }
288 if (input.time_until_last_click_millis.has_value()) {
289 message.set_time_until_last_click_millis(
290 input.time_until_last_click_millis.value().InMilliseconds());
291 }
292 if (input.time_until_close_millis.has_value()) {
293 message.set_time_until_close_millis(
294 input.time_until_close_millis.value().InMilliseconds());
295 }
Sharon Yangd8174692018-05-18 16:49:05296
297 switch (input.closed_reason) {
298 case NotificationDatabaseData::ClosedReason::USER:
299 message.set_closed_reason(NotificationDatabaseDataProto::USER);
300 break;
301 case NotificationDatabaseData::ClosedReason::DEVELOPER:
302 message.set_closed_reason(NotificationDatabaseDataProto::DEVELOPER);
303 break;
304 case NotificationDatabaseData::ClosedReason::UNKNOWN:
305 message.set_closed_reason(NotificationDatabaseDataProto::UNKNOWN);
306 break;
307 }
peter05cb4db2015-03-13 14:33:38308
Richard Knoll2e136ef2019-03-07 09:45:11309 message.set_has_triggered(input.has_triggered);
310
Richard Knoll5dcde8862021-07-16 14:38:56311 message.set_is_shown_by_browser(input.is_shown_by_browser);
312
Sarah Krakowiak Criele7e3aac2025-04-10 15:38:27313 message.mutable_serialized_metadata()->insert(
314 input.serialized_metadata.begin(), input.serialized_metadata.end());
315
peter05cb4db2015-03-13 14:33:38316 return message.SerializeToString(output);
317}
318
Richard Knoll2e136ef2019-03-07 09:45:11319bool DeserializeNotificationDatabaseResources(
320 const std::string& serialized_resources,
321 blink::NotificationResources* output) {
322 DCHECK(output);
323
324 NotificationDatabaseResourcesProto message;
325 if (!message.ParseFromString(serialized_resources))
326 return false;
327
328 if (message.has_image())
329 output->image = DeserializeImage(message.image());
330 else
331 output->image = SkBitmap();
332
333 if (message.has_notification_icon())
334 output->notification_icon = DeserializeImage(message.notification_icon());
335 else
336 output->notification_icon = SkBitmap();
337
338 if (message.has_badge())
339 output->badge = DeserializeImage(message.badge());
340 else
341 output->badge = SkBitmap();
342
343 output->action_icons.clear();
344 for (int i = 0; i < message.action_icons_size(); ++i)
345 output->action_icons.push_back(DeserializeImage(message.action_icons(i)));
346
347 return true;
348}
349
350bool SerializeNotificationDatabaseResources(
351 const blink::NotificationResources& input,
352 std::string* serialized_resources) {
353 DCHECK(serialized_resources);
354
355 NotificationDatabaseResourcesProto message;
356
357 if (!input.image.isNull()) {
358 auto image_data = SerializeImage(input.image);
359 message.set_image(image_data.data(), image_data.size());
360 }
361 if (!input.notification_icon.isNull()) {
362 auto image_data = SerializeImage(input.notification_icon);
363 message.set_notification_icon(image_data.data(), image_data.size());
364 }
365 if (!input.badge.isNull()) {
366 auto image_data = SerializeImage(input.badge);
367 message.set_badge(image_data.data(), image_data.size());
368 }
369 for (const auto& image : input.action_icons) {
370 if (!image.isNull()) {
371 auto image_data = SerializeImage(image);
372 message.add_action_icons(image_data.data(), image_data.size());
373 } else {
374 message.add_action_icons();
375 }
376 }
377
378 return message.SerializeToString(serialized_resources);
379}
380
peter05cb4db2015-03-13 14:33:38381} // namespace content