Chromium Code Reviews| 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 | |
|
johnme
2015/04/09 17:00:01
This TODO seems to have gotten lost?
Peter Beverloo
2015/04/09 17:34:42
It's still captured in NotificationService.java:91
| |
| 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 = | |
| 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 | |
| 192 // On Android, it's still possible that the notification can be closed in case | |
| 193 // the platform Id is known, even if no delegate exists. This happens when the | |
| 194 // browser process is started because of interaction with a Notification. | |
| 195 PlatformCloseNotification(delegate_id); | |
| 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; | 153 int64_t persistent_notification_id = 0; |
| 271 if (!base::StringToInt64(notification_id, &persistent_notification_id)) | 154 if (!base::StringToInt64(delegate_id, &persistent_notification_id)) |
|
johnme
2015/04/09 17:00:01
Nit: please add a TODO about changing delegate_ids
Peter Beverloo
2015/04/09 17:34:42
Done.
| |
| 272 return; | 155 return false; |
| 273 | 156 |
| 274 const auto iterator = | 157 const auto iterator = |
| 275 regenerated_notification_infos_.find(persistent_notification_id); | 158 regenerated_notification_infos_.find(persistent_notification_id); |
| 276 if (iterator == regenerated_notification_infos_.end()) | 159 if (iterator == regenerated_notification_infos_.end()) |
| 277 return; | 160 return false; |
| 278 | 161 |
| 279 RegeneratedNotificationInfo notification_info = iterator->second; | 162 const RegeneratedNotificationInfo& notification_info = iterator->second; |
| 163 | |
| 280 JNIEnv* env = AttachCurrentThread(); | 164 JNIEnv* env = AttachCurrentThread(); |
| 281 | 165 |
| 282 ScopedJavaLocalRef<jstring> origin = | 166 ScopedJavaLocalRef<jstring> origin = |
| 283 ConvertUTF8ToJavaString(env, notification_info.first); | 167 ConvertUTF8ToJavaString(env, notification_info.first); |
| 284 ScopedJavaLocalRef<jstring> tag = | 168 ScopedJavaLocalRef<jstring> tag = |
| 285 ConvertUTF8ToJavaString(env, notification_info.second); | 169 ConvertUTF8ToJavaString(env, notification_info.second); |
| 286 | 170 |
| 287 regenerated_notification_infos_.erase(iterator); | 171 regenerated_notification_infos_.erase(iterator); |
| 288 | 172 |
| 289 Java_NotificationUIManager_closeNotification(env, | 173 Java_NotificationUIManager_closeNotification(env, |
| 290 java_object_.obj(), | 174 java_object_.obj(), |
| 291 persistent_notification_id, | 175 persistent_notification_id, |
| 292 origin.obj(), | 176 origin.obj(), |
| 293 tag.obj()); | 177 tag.obj()); |
| 178 return true; | |
| 294 } | 179 } |
| 295 | 180 |
| 296 void NotificationUIManagerAndroid::AddProfileNotification( | 181 std::set<std::string> |
| 297 ProfileNotification* profile_notification) { | 182 NotificationUIManagerAndroid::GetAllIdsByProfileAndSourceOrigin( |
| 298 std::string id = profile_notification->notification().id(); | 183 Profile* profile, |
| 299 | 184 const GURL& source) { |
| 300 // Notification ids should be unique. | 185 NOTIMPLEMENTED(); |
|
johnme
2015/04/09 17:00:01
This is currently used by PushMessagingServiceImpl
Peter Beverloo
2015/04/09 17:34:42
There's already a row for that on the spreadsheet,
johnme
2015/04/10 11:37:47
There's a difference between unreliable-across-res
| |
| 301 DCHECK(profile_notifications_.find(id) == profile_notifications_.end()); | 186 return std::set<std::string>(); |
| 302 | |
| 303 profile_notifications_[id] = profile_notification; | |
| 304 } | 187 } |
| 305 | 188 |
| 306 void NotificationUIManagerAndroid::RemoveProfileNotification( | 189 bool NotificationUIManagerAndroid::CancelAllBySourceOrigin( |
| 307 ProfileNotification* profile_notification, bool close) { | 190 const GURL& source_origin) { |
| 308 std::string notification_id = profile_notification->notification().id(); | 191 NOTIMPLEMENTED(); |
| 309 if (close) | 192 return false; |
| 310 PlatformCloseNotification(notification_id); | |
| 311 | |
| 312 profile_notifications_.erase(notification_id); | |
| 313 delete profile_notification; | |
| 314 } | 193 } |
| 315 | 194 |
| 316 ProfileNotification* NotificationUIManagerAndroid::FindProfileNotification( | 195 bool NotificationUIManagerAndroid::CancelAllByProfile(ProfileID profile_id) { |
| 317 const std::string& id) const { | 196 NOTIMPLEMENTED(); |
|
johnme
2015/04/09 17:00:01
Doesn't not implementing this mean that Notificati
Peter Beverloo
2015/04/09 17:34:42
I'm not sure what our incognito story is right now
johnme
2015/04/10 11:37:47
Ok, we chatted offline and you explained that the
| |
| 318 auto iter = profile_notifications_.find(id); | 197 return false; |
| 319 if (iter == profile_notifications_.end()) | |
| 320 return nullptr; | |
| 321 | |
| 322 return iter->second; | |
| 323 } | 198 } |
| 324 | 199 |
| 325 ProfileNotification* NotificationUIManagerAndroid::FindNotificationToReplace( | 200 void NotificationUIManagerAndroid::CancelAll() { |
| 326 const Notification& notification, Profile* profile) const { | 201 NOTIMPLEMENTED(); |
| 327 const std::string& tag = notification.tag(); | 202 } |
| 328 if (tag.empty()) | |
| 329 return nullptr; | |
| 330 | 203 |
| 331 const GURL origin_url = notification.origin_url(); | 204 bool NotificationUIManagerAndroid::RegisterNotificationUIManager(JNIEnv* env) { |
| 332 DCHECK(origin_url.is_valid()); | 205 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 } | 206 } |
| OLD | NEW |