OLD | NEW |
---|---|
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 <utility> | 7 #include <utility> |
8 | 8 |
9 #include "base/android/jni_array.h" | 9 #include "base/android/jni_array.h" |
10 #include "base/android/jni_string.h" | 10 #include "base/android/jni_string.h" |
11 #include "base/logging.h" | 11 #include "base/logging.h" |
12 #include "base/strings/string_number_conversions.h" | 12 #include "base/strings/string_number_conversions.h" |
13 #include "chrome/browser/browser_process.h" | 13 #include "chrome/browser/browser_process.h" |
14 #include "chrome/browser/notifications/notification.h" | 14 #include "chrome/browser/notifications/notification.h" |
15 #include "chrome/browser/notifications/persistent_notification_delegate.h" | 15 #include "chrome/browser/notifications/persistent_notification_delegate.h" |
16 #include "chrome/browser/notifications/platform_notification_service_impl.h" | 16 #include "chrome/browser/notifications/platform_notification_service_impl.h" |
17 #include "chrome/browser/notifications/profile_notification.h" | |
18 #include "chrome/browser/profiles/profile_manager.h" | 17 #include "chrome/browser/profiles/profile_manager.h" |
19 #include "content/public/common/persistent_notification_status.h" | 18 #include "content/public/common/persistent_notification_status.h" |
20 #include "content/public/common/platform_notification_data.h" | 19 #include "content/public/common/platform_notification_data.h" |
21 #include "jni/NotificationUIManager_jni.h" | 20 #include "jni/NotificationUIManager_jni.h" |
22 #include "ui/gfx/android/java_bitmap.h" | 21 #include "ui/gfx/android/java_bitmap.h" |
23 #include "ui/gfx/image/image.h" | 22 #include "ui/gfx/image/image.h" |
24 | 23 |
25 using base::android::AttachCurrentThread; | 24 using base::android::AttachCurrentThread; |
26 using base::android::ConvertJavaStringToUTF8; | 25 using base::android::ConvertJavaStringToUTF8; |
27 using base::android::ConvertUTF16ToJavaString; | 26 using base::android::ConvertUTF16ToJavaString; |
28 using base::android::ConvertUTF8ToJavaString; | 27 using base::android::ConvertUTF8ToJavaString; |
29 | 28 |
30 namespace { | |
31 | |
32 // Called when the "notificationclick" event in the Service Worker has finished | |
33 // executing for a notification that was created in a previous instance of the | |
34 // browser. | |
35 void OnEventDispatchComplete(content::PersistentNotificationStatus status) { | |
36 // TODO(peter): Add UMA statistics based on |status|. | |
37 // TODO(peter): Decide if we want to forcefully shut down the browser process | |
38 // if we're confident it was created for delivering this event. | |
39 } | |
40 | |
41 } // namespace | |
42 | |
43 // Called by the Java side when a notification event has been received, but the | 29 // Called by the Java side when a notification event has been received, but the |
44 // NotificationUIManager has not been initialized yet. Enforce initialization of | 30 // NotificationUIManager has not been initialized yet. Enforce initialization of |
45 // the class. | 31 // the class. |
46 static void InitializeNotificationUIManager(JNIEnv* env, jclass clazz) { | 32 static void InitializeNotificationUIManager(JNIEnv* env, jclass clazz) { |
47 g_browser_process->notification_ui_manager(); | 33 g_browser_process->notification_ui_manager(); |
48 } | 34 } |
49 | 35 |
50 // static | 36 // static |
51 NotificationUIManager* NotificationUIManager::Create(PrefService* local_state) { | 37 NotificationUIManager* NotificationUIManager::Create(PrefService* local_state) { |
52 return new NotificationUIManagerAndroid(); | 38 return new NotificationUIManagerAndroid(); |
(...skipping 23 matching lines...) Expand all Loading... | |
76 | 62 |
77 regenerated_notification_infos_[persistent_notification_id] = | 63 regenerated_notification_infos_[persistent_notification_id] = |
78 std::make_pair(origin.spec(), tag); | 64 std::make_pair(origin.spec(), tag); |
79 | 65 |
80 // TODO(peter): Rather than assuming that the last used profile is the | 66 // TODO(peter): Rather than assuming that the last used profile is the |
81 // appropriate one for this notification, the used profile should be | 67 // appropriate one for this notification, the used profile should be |
82 // stored as part of the notification's data. See https://crbug.com/437574. | 68 // stored as part of the notification's data. See https://crbug.com/437574. |
83 PlatformNotificationServiceImpl::GetInstance()->OnPersistentNotificationClick( | 69 PlatformNotificationServiceImpl::GetInstance()->OnPersistentNotificationClick( |
84 ProfileManager::GetLastUsedProfile(), | 70 ProfileManager::GetLastUsedProfile(), |
85 persistent_notification_id, | 71 persistent_notification_id, |
86 origin, | 72 origin); |
87 base::Bind(&OnEventDispatchComplete)); | |
88 | 73 |
89 return true; | 74 return true; |
90 } | 75 } |
91 | 76 |
92 bool NotificationUIManagerAndroid::OnNotificationClosed( | 77 bool NotificationUIManagerAndroid::OnNotificationClosed( |
93 JNIEnv* env, | 78 JNIEnv* env, |
94 jobject java_object, | 79 jobject java_object, |
95 jlong persistent_notification_id, | 80 jlong persistent_notification_id, |
96 jstring java_origin, | 81 jstring java_origin, |
97 jstring java_tag) { | 82 jstring java_tag) { |
98 // TODO(peter): Implement handling when a notification has been closed. The | 83 // TODO(peter): Implement handling when a notification has been closed. The |
99 // notification database has to reflect this in its own state. | 84 // notification database has to reflect this in its own state. |
100 return true; | 85 return true; |
101 } | 86 } |
102 | 87 |
103 void NotificationUIManagerAndroid::Add(const Notification& notification, | 88 void NotificationUIManagerAndroid::Add(const Notification& notification, |
104 Profile* profile) { | 89 Profile* profile) { |
105 // If the given notification is replacing an older one, drop its associated | |
106 // profile notification object without closing the platform notification. | |
107 // We'll use the native Android system to perform a smoother replacement. | |
108 ProfileNotification* notification_to_replace = | |
109 FindNotificationToReplace(notification, profile); | |
110 if (notification_to_replace) | |
111 RemoveProfileNotification(notification_to_replace, false /* close */); | |
112 | |
113 ProfileNotification* profile_notification = | |
114 new ProfileNotification(profile, notification); | |
115 | |
116 // Takes ownership of |profile_notification|. | |
117 AddProfileNotification(profile_notification); | |
118 | |
119 JNIEnv* env = AttachCurrentThread(); | 90 JNIEnv* env = AttachCurrentThread(); |
120 | 91 |
92 // The Android notification UI manager only supports Web Notifications, which | |
93 // have a PersistentNotificationDelegate. The persistent id of the | |
94 // notification is exposed through it's interface. | |
95 // | |
96 // TODO(peter): When content/ passes a message_center::Notification to the | |
97 // chrome/ layer, the persistent notification id should be captured as a | |
98 // property on that object instead, making this cast unnecessary. | |
121 PersistentNotificationDelegate* delegate = | 99 PersistentNotificationDelegate* delegate = |
122 static_cast<PersistentNotificationDelegate*>(notification.delegate()); | 100 static_cast<PersistentNotificationDelegate*>(notification.delegate()); |
123 DCHECK(delegate); | 101 DCHECK(delegate); |
124 | 102 |
125 int64_t persistent_notification_id = delegate->persistent_notification_id(); | 103 int64_t persistent_notification_id = delegate->persistent_notification_id(); |
126 GURL origin_url(notification.origin_url().GetOrigin()); | 104 GURL origin_url(notification.origin_url().GetOrigin()); |
127 | 105 |
128 ScopedJavaLocalRef<jstring> origin = ConvertUTF8ToJavaString( | 106 ScopedJavaLocalRef<jstring> origin = ConvertUTF8ToJavaString( |
129 env, origin_url.spec()); | 107 env, origin_url.spec()); |
130 ScopedJavaLocalRef<jstring> tag = | 108 ScopedJavaLocalRef<jstring> tag = |
(...skipping 21 matching lines...) Expand all Loading... | |
152 notification.silent()); | 130 notification.silent()); |
153 | 131 |
154 regenerated_notification_infos_[persistent_notification_id] = | 132 regenerated_notification_infos_[persistent_notification_id] = |
155 std::make_pair(origin_url.spec(), notification.tag()); | 133 std::make_pair(origin_url.spec(), notification.tag()); |
156 | 134 |
157 notification.delegate()->Display(); | 135 notification.delegate()->Display(); |
158 } | 136 } |
159 | 137 |
160 bool NotificationUIManagerAndroid::Update(const Notification& notification, | 138 bool NotificationUIManagerAndroid::Update(const Notification& notification, |
161 Profile* profile) { | 139 Profile* profile) { |
162 // This method is currently only called from extensions and local discovery, | |
163 // both of which are not supported on Android. | |
164 NOTIMPLEMENTED(); | 140 NOTIMPLEMENTED(); |
165 return false; | 141 return false; |
166 } | 142 } |
167 | 143 |
168 const Notification* NotificationUIManagerAndroid::FindById( | 144 const Notification* NotificationUIManagerAndroid::FindById( |
169 const std::string& delegate_id, | 145 const std::string& delegate_id, |
170 ProfileID profile_id) const { | 146 ProfileID profile_id) const { |
171 std::string profile_notification_id = | 147 NOTIMPLEMENTED(); |
172 ProfileNotification::GetProfileNotificationId(delegate_id, profile_id); | 148 return nullptr; |
173 ProfileNotification* profile_notification = | |
174 FindProfileNotification(profile_notification_id); | |
175 if (!profile_notification) | |
176 return 0; | |
177 | |
178 return &profile_notification->notification(); | |
179 } | 149 } |
180 | 150 |
181 bool NotificationUIManagerAndroid::CancelById(const std::string& delegate_id, | 151 bool NotificationUIManagerAndroid::CancelById(const std::string& delegate_id, |
182 ProfileID profile_id) { | 152 ProfileID profile_id) { |
183 std::string profile_notification_id = | 153 int64_t persistent_notification_id = 0; |
184 ProfileNotification::GetProfileNotificationId(delegate_id, profile_id); | |
185 ProfileNotification* profile_notification = | |
186 FindProfileNotification(profile_notification_id); | |
187 if (profile_notification) { | |
188 RemoveProfileNotification(profile_notification, true /* close */); | |
189 return true; | |
190 } | |
191 | 154 |
192 // On Android, it's still possible that the notification can be closed in case | 155 // TODO(peter): Use the |delegate_id| directly when notification ids are being |
193 // the platform Id is known, even if no delegate exists. This happens when the | 156 // generated by content/ instead of us. |
194 // browser process is started because of interaction with a Notification. | 157 if (!base::StringToInt64(delegate_id, &persistent_notification_id)) |
195 PlatformCloseNotification(delegate_id); | 158 return false; |
196 return true; | |
197 } | |
198 | |
199 std::set<std::string> | |
200 NotificationUIManagerAndroid::GetAllIdsByProfileAndSourceOrigin( | |
201 Profile* profile, | |
202 const GURL& source) { | |
203 // |profile| may be invalid, so no calls must be made based on the instance. | |
204 std::set<std::string> delegate_ids; | |
205 | |
206 for (auto iterator : profile_notifications_) { | |
207 ProfileNotification* profile_notification = iterator.second; | |
208 if (profile_notification->notification().origin_url() == source && | |
209 profile_notification->profile() == profile) | |
210 delegate_ids.insert(profile_notification->notification().id()); | |
211 } | |
212 | |
213 return delegate_ids; | |
214 } | |
215 | |
216 bool NotificationUIManagerAndroid::CancelAllBySourceOrigin( | |
217 const GURL& source_origin) { | |
218 bool removed = true; | |
219 | |
220 for (auto iterator = profile_notifications_.begin(); | |
221 iterator != profile_notifications_.end();) { | |
222 auto current_iterator = iterator++; | |
223 | |
224 ProfileNotification* profile_notification = current_iterator->second; | |
225 if (profile_notification->notification().origin_url() == source_origin) { | |
226 RemoveProfileNotification(profile_notification, true /* close */); | |
227 removed = true; | |
228 } | |
229 } | |
230 | |
231 return removed; | |
232 } | |
233 | |
234 bool NotificationUIManagerAndroid::CancelAllByProfile(ProfileID profile_id) { | |
235 bool removed = true; | |
236 | |
237 for (auto iterator = profile_notifications_.begin(); | |
238 iterator != profile_notifications_.end();) { | |
239 auto current_iterator = iterator++; | |
240 | |
241 ProfileNotification* profile_notification = current_iterator->second; | |
242 ProfileID current_profile_id = | |
243 NotificationUIManager::GetProfileID(profile_notification->profile()); | |
244 if (current_profile_id == profile_id) { | |
245 RemoveProfileNotification(profile_notification, true /* close */); | |
246 removed = true; | |
247 } | |
248 } | |
249 | |
250 return removed; | |
251 } | |
252 | |
253 void NotificationUIManagerAndroid::CancelAll() { | |
254 for (auto iterator : profile_notifications_) { | |
255 ProfileNotification* profile_notification = iterator.second; | |
256 | |
257 PlatformCloseNotification(profile_notification->notification().id()); | |
258 delete profile_notification; | |
259 } | |
260 | |
261 profile_notifications_.clear(); | |
262 } | |
263 | |
264 bool NotificationUIManagerAndroid::RegisterNotificationUIManager(JNIEnv* env) { | |
265 return RegisterNativesImpl(env); | |
266 } | |
267 | |
268 void NotificationUIManagerAndroid::PlatformCloseNotification( | |
269 const std::string& notification_id) { | |
270 int64_t persistent_notification_id = 0; | |
271 if (!base::StringToInt64(notification_id, &persistent_notification_id)) | |
272 return; | |
273 | 159 |
274 const auto iterator = | 160 const auto iterator = |
275 regenerated_notification_infos_.find(persistent_notification_id); | 161 regenerated_notification_infos_.find(persistent_notification_id); |
276 if (iterator == regenerated_notification_infos_.end()) | 162 if (iterator == regenerated_notification_infos_.end()) |
277 return; | 163 return false; |
278 | 164 |
279 RegeneratedNotificationInfo notification_info = iterator->second; | 165 const RegeneratedNotificationInfo& notification_info = iterator->second; |
166 | |
280 JNIEnv* env = AttachCurrentThread(); | 167 JNIEnv* env = AttachCurrentThread(); |
281 | 168 |
282 ScopedJavaLocalRef<jstring> origin = | 169 ScopedJavaLocalRef<jstring> origin = |
283 ConvertUTF8ToJavaString(env, notification_info.first); | 170 ConvertUTF8ToJavaString(env, notification_info.first); |
284 ScopedJavaLocalRef<jstring> tag = | 171 ScopedJavaLocalRef<jstring> tag = |
285 ConvertUTF8ToJavaString(env, notification_info.second); | 172 ConvertUTF8ToJavaString(env, notification_info.second); |
286 | 173 |
287 regenerated_notification_infos_.erase(iterator); | 174 regenerated_notification_infos_.erase(iterator); |
288 | 175 |
289 Java_NotificationUIManager_closeNotification(env, | 176 Java_NotificationUIManager_closeNotification(env, |
290 java_object_.obj(), | 177 java_object_.obj(), |
291 persistent_notification_id, | 178 persistent_notification_id, |
292 origin.obj(), | 179 origin.obj(), |
293 tag.obj()); | 180 tag.obj()); |
181 return true; | |
294 } | 182 } |
295 | 183 |
296 void NotificationUIManagerAndroid::AddProfileNotification( | 184 std::set<std::string> |
297 ProfileNotification* profile_notification) { | 185 NotificationUIManagerAndroid::GetAllIdsByProfileAndSourceOrigin( |
298 std::string id = profile_notification->notification().id(); | 186 Profile* profile, |
299 | 187 const GURL& source) { |
300 // Notification ids should be unique. | 188 NOTIMPLEMENTED(); |
dewittj
2015/04/10 17:06:59
I wonder if we should be harsher about these metho
Peter Beverloo
2015/04/14 17:53:40
That sounds good to me. Changed them to NOTREACHED
| |
301 DCHECK(profile_notifications_.find(id) == profile_notifications_.end()); | 189 return std::set<std::string>(); |
302 | |
303 profile_notifications_[id] = profile_notification; | |
304 } | 190 } |
305 | 191 |
306 void NotificationUIManagerAndroid::RemoveProfileNotification( | 192 bool NotificationUIManagerAndroid::CancelAllBySourceOrigin( |
307 ProfileNotification* profile_notification, bool close) { | 193 const GURL& source_origin) { |
308 std::string notification_id = profile_notification->notification().id(); | 194 NOTIMPLEMENTED(); |
309 if (close) | 195 return false; |
310 PlatformCloseNotification(notification_id); | |
311 | |
312 profile_notifications_.erase(notification_id); | |
313 delete profile_notification; | |
314 } | 196 } |
315 | 197 |
316 ProfileNotification* NotificationUIManagerAndroid::FindProfileNotification( | 198 bool NotificationUIManagerAndroid::CancelAllByProfile(ProfileID profile_id) { |
317 const std::string& id) const { | 199 NOTIMPLEMENTED(); |
318 auto iter = profile_notifications_.find(id); | 200 return false; |
319 if (iter == profile_notifications_.end()) | |
320 return nullptr; | |
321 | |
322 return iter->second; | |
323 } | 201 } |
324 | 202 |
325 ProfileNotification* NotificationUIManagerAndroid::FindNotificationToReplace( | 203 void NotificationUIManagerAndroid::CancelAll() { |
326 const Notification& notification, Profile* profile) const { | 204 NOTIMPLEMENTED(); |
327 const std::string& tag = notification.tag(); | 205 } |
328 if (tag.empty()) | |
329 return nullptr; | |
330 | 206 |
331 const GURL origin_url = notification.origin_url(); | 207 bool NotificationUIManagerAndroid::RegisterNotificationUIManager(JNIEnv* env) { |
332 DCHECK(origin_url.is_valid()); | 208 return RegisterNativesImpl(env); |
333 | |
334 for (const auto& iterator : profile_notifications_) { | |
335 ProfileNotification* profile_notification = iterator.second; | |
336 if (profile_notification->notification().tag() == tag || | |
337 profile_notification->notification().origin_url() == origin_url || | |
338 profile_notification->profile() == profile) { | |
339 return profile_notification; | |
340 } | |
341 } | |
342 return nullptr; | |
343 } | 209 } |
OLD | NEW |