blob: a11aaf175c2fa2c6174d54b82e7d78414e70210b [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/notifications/notification_ui_manager_android.h"
#include "base/android/jni_string.h"
#include "base/logging.h"
#include "base/strings/string16.h"
#include "chrome/browser/notifications/profile_notification.h"
#include "jni/NotificationUIManager_jni.h"
#include "ui/gfx/android/java_bitmap.h"
#include "ui/gfx/image/image.h"
using base::android::AttachCurrentThread;
using base::android::ConvertJavaStringToUTF8;
using base::android::ConvertUTF16ToJavaString;
using base::android::ConvertUTF8ToJavaString;
// static
NotificationUIManager* NotificationUIManager::Create(PrefService* local_state) {
return new NotificationUIManagerAndroid();
}
NotificationUIManagerAndroid::NotificationUIManagerAndroid() {
java_object_.Reset(
Java_NotificationUIManager_create(
AttachCurrentThread(),
reinterpret_cast<intptr_t>(this),
base::android::GetApplicationContext()));
}
NotificationUIManagerAndroid::~NotificationUIManagerAndroid() {}
void NotificationUIManagerAndroid::OnNotificationClicked(
JNIEnv* env, jobject java_object, jstring notification_id) {
std::string id = ConvertJavaStringToUTF8(env, notification_id);
auto iter = profile_notifications_.find(id);
if (iter == profile_notifications_.end())
return;
const Notification& notification = iter->second->notification();
notification.delegate()->Click();
}
void NotificationUIManagerAndroid::OnNotificationClosed(
JNIEnv* env, jobject java_object, jstring notification_id) {
std::string id = ConvertJavaStringToUTF8(env, notification_id);
auto iter = profile_notifications_.find(id);
if (iter == profile_notifications_.end())
return;
const Notification& notification = iter->second->notification();
notification.delegate()->Close(true /** by_user **/);
}
void NotificationUIManagerAndroid::Add(const Notification& notification,
Profile* profile) {
if (Update(notification, profile))
return;
ProfileNotification* profile_notification =
new ProfileNotification(profile, notification);
// Takes ownership of |profile_notification|.
AddProfileNotification(profile_notification);
JNIEnv* env = AttachCurrentThread();
ScopedJavaLocalRef<jstring> id = ConvertUTF8ToJavaString(
env, profile_notification->notification().id());
ScopedJavaLocalRef<jstring> title = ConvertUTF16ToJavaString(
env, notification.title());
ScopedJavaLocalRef<jstring> body = ConvertUTF16ToJavaString(
env, notification.message());
SkBitmap icon_bitmap = notification.icon().AsBitmap();
ScopedJavaLocalRef<jobject> icon = gfx::ConvertToJavaBitmap(&icon_bitmap);
int platform_id = Java_NotificationUIManager_displayNotification(
env, java_object_.obj(), id.obj(), title.obj(), body.obj(), icon.obj());
std::string notification_id = profile_notification->notification().id();
platform_notifications_[notification_id] = platform_id;
notification.delegate()->Display();
}
bool NotificationUIManagerAndroid::Update(const Notification& notification,
Profile* profile) {
const base::string16& replace_id = notification.replace_id();
if (replace_id.empty())
return false;
const GURL origin_url = notification.origin_url();
DCHECK(origin_url.is_valid());
for (auto iterator : profile_notifications_) {
ProfileNotification* profile_notification = iterator.second;
if (profile_notification->notification().replace_id() != replace_id ||
profile_notification->notification().origin_url() != origin_url ||
profile_notification->profile() != profile)
continue;
std::string notification_id = profile_notification->notification().id();
// TODO(peter): Use Android's native notification replacement mechanism.
// Right now FALSE is returned from this function even when we would be
// able to update the notification, so that Add() creates a new one.
RemoveProfileNotification(profile_notification);
break;
}
return false;
}
const Notification* NotificationUIManagerAndroid::FindById(
const std::string& delegate_id,
ProfileID profile_id) const {
std::string profile_notification_id =
ProfileNotification::GetProfileNotificationId(delegate_id, profile_id);
ProfileNotification* profile_notification =
FindProfileNotification(profile_notification_id);
if (!profile_notification)
return 0;
return &profile_notification->notification();
}
bool NotificationUIManagerAndroid::CancelById(const std::string& delegate_id,
ProfileID profile_id) {
std::string profile_notification_id =
ProfileNotification::GetProfileNotificationId(delegate_id, profile_id);
ProfileNotification* profile_notification =
FindProfileNotification(profile_notification_id);
if (!profile_notification)
return false;
RemoveProfileNotification(profile_notification);
return true;
}
std::set<std::string>
NotificationUIManagerAndroid::GetAllIdsByProfileAndSourceOrigin(
Profile* profile,
const GURL& source) {
// |profile| may be invalid, so no calls must be made based on the instance.
std::set<std::string> delegate_ids;
for (auto iterator : profile_notifications_) {
ProfileNotification* profile_notification = iterator.second;
if (profile_notification->notification().origin_url() == source &&
profile_notification->profile() == profile)
delegate_ids.insert(profile_notification->notification().id());
}
return delegate_ids;
}
bool NotificationUIManagerAndroid::CancelAllBySourceOrigin(
const GURL& source_origin) {
bool removed = true;
for (auto iterator = profile_notifications_.begin();
iterator != profile_notifications_.end();) {
auto current_iterator = iterator++;
ProfileNotification* profile_notification = current_iterator->second;
if (profile_notification->notification().origin_url() == source_origin) {
RemoveProfileNotification(profile_notification);
removed = true;
}
}
return removed;
}
bool NotificationUIManagerAndroid::CancelAllByProfile(ProfileID profile_id) {
bool removed = true;
for (auto iterator = profile_notifications_.begin();
iterator != profile_notifications_.end();) {
auto current_iterator = iterator++;
ProfileNotification* profile_notification = current_iterator->second;
ProfileID current_profile_id =
NotificationUIManager::GetProfileID(profile_notification->profile());
if (current_profile_id == profile_id) {
RemoveProfileNotification(profile_notification);
removed = true;
}
}
return removed;
}
void NotificationUIManagerAndroid::CancelAll() {
for (auto iterator : profile_notifications_) {
ProfileNotification* profile_notification = iterator.second;
PlatformCloseNotification(profile_notification);
delete profile_notification;
}
profile_notifications_.clear();
}
bool NotificationUIManagerAndroid::RegisterNotificationUIManager(JNIEnv* env) {
return RegisterNativesImpl(env);
}
void NotificationUIManagerAndroid::PlatformCloseNotification(
ProfileNotification* profile_notification) {
std::string id = profile_notification->notification().id();
auto iterator = platform_notifications_.find(id);
if (iterator == platform_notifications_.end())
return;
int platform_id = iterator->second;
platform_notifications_.erase(id);
Java_NotificationUIManager_closeNotification(AttachCurrentThread(),
java_object_.obj(),
platform_id);
}
void NotificationUIManagerAndroid::AddProfileNotification(
ProfileNotification* profile_notification) {
std::string id = profile_notification->notification().id();
// Notification ids should be unique.
DCHECK(profile_notifications_.find(id) == profile_notifications_.end());
profile_notifications_[id] = profile_notification;
}
void NotificationUIManagerAndroid::RemoveProfileNotification(
ProfileNotification* profile_notification) {
PlatformCloseNotification(profile_notification);
std::string id = profile_notification->notification().id();
profile_notifications_.erase(id);
delete profile_notification;
}
ProfileNotification* NotificationUIManagerAndroid::FindProfileNotification(
const std::string& id) const {
auto iter = profile_notifications_.find(id);
if (iter == profile_notifications_.end())
return nullptr;
return iter->second;
}