Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(166)

Side by Side Diff: chrome/browser/notifications/notification_ui_manager_android.cc

Issue 839533004: Store serialized notification data as an Intent extra on Android. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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 "chrome/browser/notifications/notification_ui_manager_android.h" 5 #include "chrome/browser/notifications/notification_ui_manager_android.h"
6 6
7 #include "base/android/jni_array.h"
7 #include "base/android/jni_string.h" 8 #include "base/android/jni_string.h"
8 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/pickle.h"
9 #include "base/strings/string16.h" 11 #include "base/strings/string16.h"
10 #include "chrome/browser/browser_process.h" 12 #include "chrome/browser/browser_process.h"
13 #include "chrome/browser/notifications/persistent_notification_delegate.h"
14 #include "chrome/browser/notifications/platform_notification_service_impl.h"
11 #include "chrome/browser/notifications/profile_notification.h" 15 #include "chrome/browser/notifications/profile_notification.h"
16 #include "chrome/browser/profiles/profile_manager.h"
17 #include "content/public/common/persistent_notification_status.h"
18 #include "content/public/common/platform_notification_data.h"
12 #include "jni/NotificationUIManager_jni.h" 19 #include "jni/NotificationUIManager_jni.h"
13 #include "ui/gfx/android/java_bitmap.h" 20 #include "ui/gfx/android/java_bitmap.h"
14 #include "ui/gfx/image/image.h" 21 #include "ui/gfx/image/image.h"
15 22
16 using base::android::AttachCurrentThread; 23 using base::android::AttachCurrentThread;
17 using base::android::ConvertJavaStringToUTF8; 24 using base::android::ConvertJavaStringToUTF8;
18 using base::android::ConvertUTF16ToJavaString; 25 using base::android::ConvertUTF16ToJavaString;
19 using base::android::ConvertUTF8ToJavaString; 26 using base::android::ConvertUTF8ToJavaString;
20 27
28 namespace {
29
30 // Persistent notifications are likely to outlive the browser process they were
31 // created by on Android. In order to be able to re-surface the notification
32 // when the user interacts with them, all relevant notification data needs to
33 // be serialized with the notification itself.
34 //
35 // In the near future, as more features get added to Chrome's notification
36 // implementation, this will be done by storing the persistent notification data
37 // in a database. However, to support launching Chrome for Android from a
38 // notification event until that exists, serialize the data in the Intent.
Miguel Garcia 2015/01/07 11:07:40 Is there a size limit we should be enforcing here?
Peter Beverloo 2015/01/07 15:16:30 The reason that we eventually need a database is e
39 //
40 // TODO(peter): Move towards storing notification data in a database rather than
41 // as a serialized Intent extra.
42
43 scoped_ptr<Pickle> SerializePersistentNotification(
44 const content::PlatformNotificationData& notification_data,
45 const GURL& origin,
46 int64 service_worker_registration_id) {
47 scoped_ptr<Pickle> pickle(new Pickle);
48
49 // content::PlatformNotificationData
50 pickle->WriteString16(notification_data.title);
51 pickle->WriteInt(static_cast<int>(notification_data.direction));
52 pickle->WriteString(notification_data.lang);
53 pickle->WriteString16(notification_data.body);
54 pickle->WriteString16(notification_data.tag);
55 pickle->WriteString(notification_data.icon.spec());
56
57 // The origin which is displaying the notification.
58 pickle->WriteString(origin.spec());
59
60 // The Service Worker registration this notification is associated with.
61 pickle->WriteInt64(service_worker_registration_id);
62
63 return pickle.Pass();
64 }
65
66 bool UnserializePersistentNotification(
67 const Pickle& pickle,
68 content::PlatformNotificationData* notification_data,
69 GURL* origin,
70 int64* service_worker_registration_id) {
71 DCHECK(notification_data && origin && service_worker_registration_id);
72 PickleIterator iterator(pickle);
73
74 std::string icon_url, origin_url;
75 int direction_value;
76
77 // Unpack content::PlatformNotificationData.
78 if (!iterator.ReadString16(&notification_data->title) ||
79 !iterator.ReadInt(&direction_value) ||
80 !iterator.ReadString(&notification_data->lang) ||
81 !iterator.ReadString16(&notification_data->body) ||
82 !iterator.ReadString16(&notification_data->tag) ||
83 !iterator.ReadString(&icon_url))
Michael van Ouwerkerk 2015/01/07 13:39:10 Add curly braces when the condition is wrapped.
Peter Beverloo 2015/01/07 15:16:30 Done.
84 return false;
85
86 notification_data->direction =
87 static_cast<content::PlatformNotificationData::NotificationDirection>(
88 direction_value);
89 notification_data->icon = GURL(icon_url);
90
91 // Unpack the origin which displayed this notification.
92 if (!iterator.ReadString(&origin_url))
93 return false;
94
95 *origin = GURL(origin_url);
96
97 // Unpack the Service Worker registration id.
98 if (!iterator.ReadInt64(service_worker_registration_id))
99 return false;
100
101 return true;
102 }
103
104 // Called when the "notificationclick" event in the Service Worker has finished
105 // executing for a notification that was created in a previous instance of the
106 // browser.
107 void OnEventDispatchComplete(content::PersistentNotificationStatus status) {
108 // TODO(peter): Add UMA statistics based on |status|.
109 // TODO(peter): Decide if we want to forcefully shut down the browser process
110 // if we're confident it was created for delivering this event.
111 }
112
113 } // namespace
114
21 // Called by the Java side when a notification event has been received, but the 115 // Called by the Java side when a notification event has been received, but the
22 // NotificationUIManager has not been initialized yet. Enforce initialization of 116 // NotificationUIManager has not been initialized yet. Enforce initialization of
23 // the class. 117 // the class.
24 static void InitializeNotificationUIManager(JNIEnv* env, jclass clazz) { 118 static void InitializeNotificationUIManager(JNIEnv* env, jclass clazz) {
25 g_browser_process->notification_ui_manager(); 119 g_browser_process->notification_ui_manager();
26 } 120 }
27 121
28 // static 122 // static
29 NotificationUIManager* NotificationUIManager::Create(PrefService* local_state) { 123 NotificationUIManager* NotificationUIManager::Create(PrefService* local_state) {
30 return new NotificationUIManagerAndroid(); 124 return new NotificationUIManagerAndroid();
31 } 125 }
32 126
33 NotificationUIManagerAndroid::NotificationUIManagerAndroid() { 127 NotificationUIManagerAndroid::NotificationUIManagerAndroid() {
34 java_object_.Reset( 128 java_object_.Reset(
35 Java_NotificationUIManager_create( 129 Java_NotificationUIManager_create(
36 AttachCurrentThread(), 130 AttachCurrentThread(),
37 reinterpret_cast<intptr_t>(this), 131 reinterpret_cast<intptr_t>(this),
38 base::android::GetApplicationContext())); 132 base::android::GetApplicationContext()));
39 133
40 // TODO(peter): Synchronize notifications with the Java side. 134 // TODO(peter): Synchronize notifications with the Java side.
41 } 135 }
42 136
43 NotificationUIManagerAndroid::~NotificationUIManagerAndroid() { 137 NotificationUIManagerAndroid::~NotificationUIManagerAndroid() {
44 Java_NotificationUIManager_destroy(AttachCurrentThread(), 138 Java_NotificationUIManager_destroy(AttachCurrentThread(),
45 java_object_.obj()); 139 java_object_.obj());
46 } 140 }
47 141
48 bool NotificationUIManagerAndroid::OnNotificationClicked( 142 bool NotificationUIManagerAndroid::OnNotificationClicked(
49 JNIEnv* env, jobject java_object, jstring notification_id) { 143 JNIEnv* env,
144 jobject java_object,
145 jstring notification_id,
146 jbyteArray serialized_notification_data) {
50 std::string id = ConvertJavaStringToUTF8(env, notification_id); 147 std::string id = ConvertJavaStringToUTF8(env, notification_id);
51 148
52 auto iter = profile_notifications_.find(id); 149 auto iter = profile_notifications_.find(id);
53 if (iter == profile_notifications_.end()) { 150 if (iter != profile_notifications_.end()) {
Miguel Garcia 2015/01/07 11:07:40 Now that you have everything nicely stored in the
Peter Beverloo 2015/01/07 15:16:30 No. We will still use the delegates in the situati
54 // TODO(peter): Handle the "click" event for notifications which have 151 const Notification& notification = iter->second->notification();
55 // outlived the browser process that created them. 152 notification.delegate()->Click();
153
154 return true;
155 }
156
157 // If the Notification were not found, it may be a persistent notification
158 // that was outlived the Chrome browser process. In this case, try to
Michael van Ouwerkerk 2015/01/07 13:39:10 s/was/has/ or just delete it
Peter Beverloo 2015/01/07 15:16:30 Done.
159 // unserialize the notification's serialized data and trigger the click
160 // event manually.
161
162 std::vector<uint8> bytes;
163 base::android::JavaByteArrayToByteVector(env, serialized_notification_data,
164 &bytes);
165 if (!bytes.size())
166 return false;
167
168 content::PlatformNotificationData notification_data;
169 GURL origin;
170 int64 service_worker_registration_id;
171
172 Pickle pickle(reinterpret_cast<const char*>(&bytes[0]), bytes.size());
173 if (!UnserializePersistentNotification(pickle, &notification_data, &origin,
174 &service_worker_registration_id)) {
56 return false; 175 return false;
57 } 176 }
58 177
59 const Notification& notification = iter->second->notification(); 178 PlatformNotificationServiceImpl* service =
60 notification.delegate()->Click(); 179 PlatformNotificationServiceImpl::GetInstance();
180
181 // TODO(peter): Rather than assuming that the last used profile is the
182 // appropriate one for this notification, the used profile should be
183 // stored as part of the notification's data. See https://crbug.com/437574.
184 service->OnPersistentNotificationClick(
185 ProfileManager::GetLastUsedProfile(),
186 service_worker_registration_id,
187 id,
188 origin,
189 notification_data,
190 base::Bind(&OnEventDispatchComplete));
191
61 return true; 192 return true;
62 } 193 }
63 194
64 bool NotificationUIManagerAndroid::OnNotificationClosed( 195 bool NotificationUIManagerAndroid::OnNotificationClosed(
65 JNIEnv* env, jobject java_object, jstring notification_id) { 196 JNIEnv* env, jobject java_object, jstring notification_id) {
66 std::string id = ConvertJavaStringToUTF8(env, notification_id); 197 std::string id = ConvertJavaStringToUTF8(env, notification_id);
67 198
68 auto iter = profile_notifications_.find(id); 199 auto iter = profile_notifications_.find(id);
69 if (iter == profile_notifications_.end()) 200 if (iter == profile_notifications_.end())
70 return false; 201 return false;
(...skipping 24 matching lines...) Expand all
95 env, notification.message()); 226 env, notification.message());
96 ScopedJavaLocalRef<jstring> origin = ConvertUTF8ToJavaString( 227 ScopedJavaLocalRef<jstring> origin = ConvertUTF8ToJavaString(
97 env, notification.origin_url().GetOrigin().spec()); 228 env, notification.origin_url().GetOrigin().spec());
98 229
99 ScopedJavaLocalRef<jobject> icon; 230 ScopedJavaLocalRef<jobject> icon;
100 231
101 SkBitmap icon_bitmap = notification.icon().AsBitmap(); 232 SkBitmap icon_bitmap = notification.icon().AsBitmap();
102 if (!icon_bitmap.isNull()) 233 if (!icon_bitmap.isNull())
103 icon = gfx::ConvertToJavaBitmap(&icon_bitmap); 234 icon = gfx::ConvertToJavaBitmap(&icon_bitmap);
104 235
236 ScopedJavaLocalRef<jbyteArray> notification_data;
237 if (true /** is_persistent_notification **/) {
238 PersistentNotificationDelegate* delegate =
239 static_cast<PersistentNotificationDelegate*>(notification.delegate());
240 scoped_ptr<Pickle> pickle = SerializePersistentNotification(
241 delegate->notification_data(),
242 notification.origin_url(),
243 delegate->service_worker_registration_id());
244
245 notification_data = base::android::ToJavaByteArray(
246 env, static_cast<const uint8*>(pickle->data()), pickle->size());
247 }
248
105 int platform_id = Java_NotificationUIManager_displayNotification( 249 int platform_id = Java_NotificationUIManager_displayNotification(
106 env, java_object_.obj(), id.obj(), title.obj(), body.obj(), icon.obj(), 250 env, java_object_.obj(), id.obj(), title.obj(), body.obj(), icon.obj(),
107 origin.obj()); 251 origin.obj(), notification_data.obj());
108 252
109 std::string notification_id = profile_notification->notification().id(); 253 std::string notification_id = profile_notification->notification().id();
110 platform_notifications_[notification_id] = platform_id; 254 platform_notifications_[notification_id] = platform_id;
111 255
112 notification.delegate()->Display(); 256 notification.delegate()->Display();
113 } 257 }
114 258
115 bool NotificationUIManagerAndroid::Update(const Notification& notification, 259 bool NotificationUIManagerAndroid::Update(const Notification& notification,
116 Profile* profile) { 260 Profile* profile) {
117 const base::string16& replace_id = notification.replace_id(); 261 const base::string16& replace_id = notification.replace_id();
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after
272 416
273 ProfileNotification* NotificationUIManagerAndroid::FindProfileNotification( 417 ProfileNotification* NotificationUIManagerAndroid::FindProfileNotification(
274 const std::string& id) const { 418 const std::string& id) const {
275 auto iter = profile_notifications_.find(id); 419 auto iter = profile_notifications_.find(id);
276 if (iter == profile_notifications_.end()) 420 if (iter == profile_notifications_.end())
277 return nullptr; 421 return nullptr;
278 422
279 return iter->second; 423 return iter->second;
280 } 424 }
281 425
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698