summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpetewil@chromium.org <petewil@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-23 21:24:08 +0000
committerpetewil@chromium.org <petewil@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-23 21:24:08 +0000
commitd2cb1fde3883bd2aa4603b8ab4ea3a48f082aa9c (patch)
tree2384377746f2ee36bf8b916667e805e489e9898a
parent87ed1b6a2f88506a7982386f3ba2bc679312fd8b (diff)
downloadchromium_src-d2cb1fde3883bd2aa4603b8ab4ea3a48f082aa9c.zip
chromium_src-d2cb1fde3883bd2aa4603b8ab4ea3a48f082aa9c.tar.gz
chromium_src-d2cb1fde3883bd2aa4603b8ab4ea3a48f082aa9c.tar.bz2
Make the protobuf data format for SyncedNotifications more useful, and change the code that depends on the protobuf format.
This change adapts to the new protobuffers, and renames the "coalescing_key" to "key". It changes the "READ" state to "Dismissed" to correspond to the new protobufs. It adds support for some new data, a header and a description. BUG=197114 Review URL: https://chromiumcodereview.appspot.com/12574010 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@190076 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/notifications/sync_notifier/chrome_notifier_delegate.cc9
-rw-r--r--chrome/browser/notifications/sync_notifier/chrome_notifier_delegate.h6
-rw-r--r--chrome/browser/notifications/sync_notifier/chrome_notifier_service.cc77
-rw-r--r--chrome/browser/notifications/sync_notifier/chrome_notifier_service.h5
-rw-r--r--chrome/browser/notifications/sync_notifier/chrome_notifier_service_unittest.cc152
-rw-r--r--chrome/browser/notifications/sync_notifier/synced_notification.cc234
-rw-r--r--chrome/browser/notifications/sync_notifier/synced_notification.h18
-rw-r--r--chrome/browser/notifications/sync_notifier/synced_notification_unittest.cc106
-rw-r--r--sync/protocol/synced_notification_data.proto62
-rw-r--r--sync/protocol/synced_notification_render.proto143
10 files changed, 459 insertions, 353 deletions
diff --git a/chrome/browser/notifications/sync_notifier/chrome_notifier_delegate.cc b/chrome/browser/notifications/sync_notifier/chrome_notifier_delegate.cc
index ef368a6..1348d17 100644
--- a/chrome/browser/notifications/sync_notifier/chrome_notifier_delegate.cc
+++ b/chrome/browser/notifications/sync_notifier/chrome_notifier_delegate.cc
@@ -4,9 +4,12 @@
#include "chrome/browser/notifications/sync_notifier/chrome_notifier_delegate.h"
+#include "chrome/browser/notifications/sync_notifier/chrome_notifier_service.h"
+
namespace notifier {
-ChromeNotifierDelegate::ChromeNotifierDelegate(const std::string& id)
- : id_(id) {}
+ChromeNotifierDelegate::ChromeNotifierDelegate(const std::string& id,
+ ChromeNotifierService* notifier)
+ : id_(id), chrome_notifier_(notifier) {}
ChromeNotifierDelegate::~ChromeNotifierDelegate() {}
@@ -19,7 +22,7 @@ content::RenderViewHost* ChromeNotifierDelegate::GetRenderViewHost() const {
}
void ChromeNotifierDelegate::Close(bool by_user) {
- // TODO(petewil): implement
+ chrome_notifier_->MarkNotificationAsDismissed(id_);
}
} // namespace notifier
diff --git a/chrome/browser/notifications/sync_notifier/chrome_notifier_delegate.h b/chrome/browser/notifications/sync_notifier/chrome_notifier_delegate.h
index 6d28ee8..ad462b8 100644
--- a/chrome/browser/notifications/sync_notifier/chrome_notifier_delegate.h
+++ b/chrome/browser/notifications/sync_notifier/chrome_notifier_delegate.h
@@ -11,13 +11,16 @@
namespace notifier {
+class ChromeNotifierService;
+
// ChromeNotifierDelegate is a NotificationDelegate which catches
// responses from the NotificationUIManager when a notification
// has been closed.
class ChromeNotifierDelegate : public NotificationDelegate {
public:
- explicit ChromeNotifierDelegate(const std::string& id);
+ explicit ChromeNotifierDelegate(const std::string& id,
+ ChromeNotifierService* notifier);
// NotificationDelegate interface.
virtual void Display() OVERRIDE {}
@@ -31,6 +34,7 @@ class ChromeNotifierDelegate : public NotificationDelegate {
virtual ~ChromeNotifierDelegate();
const std::string id_;
+ ChromeNotifierService* const chrome_notifier_;
DISALLOW_COPY_AND_ASSIGN(ChromeNotifierDelegate);
};
diff --git a/chrome/browser/notifications/sync_notifier/chrome_notifier_service.cc b/chrome/browser/notifications/sync_notifier/chrome_notifier_service.cc
index 194ce87..c58e0e6 100644
--- a/chrome/browser/notifications/sync_notifier/chrome_notifier_service.cc
+++ b/chrome/browser/notifications/sync_notifier/chrome_notifier_service.cc
@@ -48,6 +48,7 @@ syncer::SyncMergeResult ChromeNotifierService::MergeDataAndStartSyncing(
syncer::SyncMergeResult merge_result(syncer::SYNCED_NOTIFICATIONS);
// A list of local changes to send up to the sync server.
syncer::SyncChangeList new_changes;
+ sync_processor_ = sync_processor.Pass();
for (syncer::SyncDataList::const_iterator it = initial_sync_data.begin();
it != initial_sync_data.end(); ++it) {
@@ -77,9 +78,9 @@ syncer::SyncMergeResult ChromeNotifierService::MergeDataAndStartSyncing(
continue;
} else {
// If the read state is different, read wins for both places.
- if (incoming->read_state() == SyncedNotification::kRead) {
+ if (incoming->read_state() == SyncedNotification::kDismissed) {
// If it is marked as read on the server, but not the client.
- found->NotificationHasBeenRead();
+ found->NotificationHasBeenDismissed();
// TODO(petewil): Tell the Notification UI Manager to mark it read.
} else {
// If it is marked as read on the client, but not the server.
@@ -103,8 +104,8 @@ syncer::SyncMergeResult ChromeNotifierService::MergeDataAndStartSyncing(
// Send up the changes that were made locally.
if (new_changes.size() > 0) {
- merge_result.set_error(
- sync_processor.get()->ProcessSyncChanges(FROM_HERE, new_changes));
+ merge_result.set_error(sync_processor_->ProcessSyncChanges(
+ FROM_HERE, new_changes));
}
return merge_result;
@@ -188,14 +189,27 @@ scoped_ptr<SyncedNotification>
// Check for mandatory fields in the sync_data object.
if (!specifics.has_coalesced_notification() ||
- !specifics.coalesced_notification().has_id() ||
- !specifics.coalesced_notification().id().has_app_id() ||
- specifics.coalesced_notification().id().app_id().empty() ||
- !specifics.coalesced_notification().has_render_info() ||
- !specifics.coalesced_notification().has_creation_time_msec()) {
+ !specifics.coalesced_notification().has_key() ||
+ !specifics.coalesced_notification().has_read_state()) {
return scoped_ptr<SyncedNotification>();
}
+ // TODO(petewil): Is this the right set? Should I add more?
+ bool is_well_formed_unread_notification =
+ (static_cast<SyncedNotification::ReadState>(
+ specifics.coalesced_notification().read_state()) ==
+ SyncedNotification::kUnread &&
+ specifics.coalesced_notification().has_render_info());
+ bool is_well_formed_dismissed_notification =
+ (static_cast<SyncedNotification::ReadState>(
+ specifics.coalesced_notification().read_state()) ==
+ SyncedNotification::kDismissed);
+
+ // if the notification is poorly formed, return a null pointer
+ if (!is_well_formed_unread_notification &&
+ !is_well_formed_dismissed_notification)
+ return scoped_ptr<SyncedNotification>();
+
// Create a new notification object based on the supplied sync_data.
scoped_ptr<SyncedNotification> notification(
new SyncedNotification(sync_data));
@@ -210,7 +224,7 @@ SyncedNotification* ChromeNotifierService::FindNotificationById(
const std::string& id) {
// TODO(petewil): We can make a performance trade off here.
// While the vector has good locality of reference, a map has faster lookup.
- // Based on how bit we expect this to get, maybe change this to a map.
+ // Based on how big we expect this to get, maybe change this to a map.
for (std::vector<SyncedNotification*>::const_iterator it =
notification_data_.begin();
it != notification_data_.end();
@@ -223,6 +237,23 @@ SyncedNotification* ChromeNotifierService::FindNotificationById(
return NULL;
}
+void ChromeNotifierService::MarkNotificationAsDismissed(const std::string& id) {
+ SyncedNotification* notification = FindNotificationById(id);
+ CHECK(notification != NULL);
+
+ notification->NotificationHasBeenDismissed();
+ syncer::SyncChangeList new_changes;
+
+ syncer::SyncData sync_data = CreateSyncDataFromNotification(*notification);
+ new_changes.push_back(
+ syncer::SyncChange(FROM_HERE,
+ syncer::SyncChange::ACTION_UPDATE,
+ sync_data));
+
+ // Send up the changes that were made locally.
+ sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes);
+}
+
// Add a new notification to our data structure. This takes ownership
// of the passed in pointer.
void ChromeNotifierService::Add(scoped_ptr<SyncedNotification> notification) {
@@ -238,25 +269,39 @@ void ChromeNotifierService::Add(scoped_ptr<SyncedNotification> notification) {
void ChromeNotifierService::Show(SyncedNotification* notification) {
// Set up the fields we need to send and create a Notification object.
GURL origin_url(notification->origin_url());
- GURL icon_url(notification->icon_url());
+ GURL app_icon_url(notification->app_icon_url());
string16 title = UTF8ToUTF16(notification->title());
- string16 body = UTF8ToUTF16(notification->body());
+ string16 text = UTF8ToUTF16(notification->text());
+ string16 heading = UTF8ToUTF16(notification->heading());
+ string16 description = UTF8ToUTF16(notification->description());
+
// TODO(petewil): What goes in the display source, is empty OK?
string16 display_source;
string16 replace_id = UTF8ToUTF16(notification->notification_id());
+
+ // TODO(petewil): For now, just punt on dismissed notifications until
+ // I change the interface to let NotificationUIManager know the right way.
+ if (SyncedNotification::kRead == notification->read_state() ||
+ SyncedNotification::kDismissed == notification->read_state() ) {
+ DVLOG(2) << "Not showing dismissed notification"
+ << notification->title() << " " << notification->text();
+ return;
+ }
+
// The delegate will eventually catch calls that the notification
// was read or deleted, and send the changes back to the server.
scoped_refptr<NotificationDelegate> delegate =
- new ChromeNotifierDelegate(notification->notification_id());
+ new ChromeNotifierDelegate(notification->notification_id(), this);
- Notification ui_notification(origin_url, icon_url, title, body,
+ Notification ui_notification(origin_url, app_icon_url, heading, description,
WebKit::WebTextDirectionDefault,
display_source, replace_id, delegate);
notification_manager_->Add(ui_notification, profile_);
- DVLOG(1) << "Synced Notification arrived! " << title << " " << body
- << " " << icon_url << " " << replace_id;
+ DVLOG(1) << "Synced Notification arrived! " << title << " " << text
+ << " " << app_icon_url << " " << replace_id << " "
+ << notification->read_state();
return;
}
diff --git a/chrome/browser/notifications/sync_notifier/chrome_notifier_service.h b/chrome/browser/notifications/sync_notifier/chrome_notifier_service.h
index 58add25..4332e51 100644
--- a/chrome/browser/notifications/sync_notifier/chrome_notifier_service.h
+++ b/chrome/browser/notifications/sync_notifier/chrome_notifier_service.h
@@ -56,6 +56,9 @@ class ChromeNotifierService : public syncer::SyncableService,
// The caller must not free it.
notifier::SyncedNotification* FindNotificationById(const std::string& id);
+ // Called when we dismiss a notification.
+ void MarkNotificationAsDismissed(const std::string& id);
+
// functions for test
void AddForTest(scoped_ptr<notifier::SyncedNotification> notification) {
Add(notification.Pass());
@@ -65,11 +68,13 @@ class ChromeNotifierService : public syncer::SyncableService,
// Add a notification to our list. This takes ownership of the pointer.
void Add(scoped_ptr<notifier::SyncedNotification> notification);
+ // Display a notification in the notification center.
void Show(notifier::SyncedNotification* notification);
// Back pointer to the owning profile.
Profile* const profile_;
NotificationUIManager* const notification_manager_;
+ scoped_ptr<syncer::SyncChangeProcessor> sync_processor_;
// TODO(petewil): consider whether a map would better suit our data.
// If there are many entries, lookup time may trump locality of reference.
diff --git a/chrome/browser/notifications/sync_notifier/chrome_notifier_service_unittest.cc b/chrome/browser/notifications/sync_notifier/chrome_notifier_service_unittest.cc
index 095ca35..f9322e2 100644
--- a/chrome/browser/notifications/sync_notifier/chrome_notifier_service_unittest.cc
+++ b/chrome/browser/notifications/sync_notifier/chrome_notifier_service_unittest.cc
@@ -18,7 +18,6 @@
using sync_pb::SyncedNotificationSpecifics;
using sync_pb::EntitySpecifics;
-using sync_pb::SyncedNotificationRenderInfo_Layout_LayoutType_TITLE_AND_SUBTEXT;
using syncer::SyncData;
using syncer::SyncChange;
using syncer::SyncChangeList;
@@ -36,23 +35,16 @@ const char kAppId4[] = "fbcmoldooppoahjhfflnmljoanccek44";
const char kAppId5[] = "fbcmoldooppoahjhfflnmljoanccek55";
const char kAppId6[] = "fbcmoldooppoahjhfflnmljoanccek66";
const char kAppId7[] = "fbcmoldooppoahjhfflnmljoanccek77";
-const char kCoalescingKey1[] = "foo";
-const char kCoalescingKey2[] = "bar";
-const char kCoalescingKey3[] = "bat";
-const char kCoalescingKey4[] = "baz";
-const char kCoalescingKey5[] = "foobar";
-const char kCoalescingKey6[] = "fu";
-const char kCoalescingKey7[] = "meta";
-const char kNotificationId1[] = "fboilmbenheemaomgaeehigklolhkhnf/foo";
-const char kNotificationId2[] = "fbcmoldooppoahjhfflnmljoanccekpf/bar";
-const char kNotificationId3[] = "fbcmoldooppoahjhfflnmljoanccek33/bat";
-const char kNotificationId4[] = "fbcmoldooppoahjhfflnmljoanccek44/baz";
-const char kNotificationId5[] = "fbcmoldooppoahjhfflnmljoanccek55/foobar";
-const char kNotificationId6[] = "fbcmoldooppoahjhfflnmljoanccek66/fu";
-const char kNotificationId7[] = "fbcmoldooppoahjhfflnmljoanccek77/meta";
+const char kKey1[] = "foo";
+const char kKey2[] = "bar";
+const char kKey3[] = "bat";
+const char kKey4[] = "baz";
+const char kKey5[] = "foobar";
+const char kKey6[] = "fu";
+const char kKey7[] = "meta";
const int64 kFakeCreationTime = 42;
-const sync_pb::CoalescedSyncedNotification_ReadState kRead =
- sync_pb::CoalescedSyncedNotification_ReadState_READ;
+const sync_pb::CoalescedSyncedNotification_ReadState kDismissed =
+ sync_pb::CoalescedSyncedNotification_ReadState_DISMISSED;
const sync_pb::CoalescedSyncedNotification_ReadState kUnread =
sync_pb::CoalescedSyncedNotification_ReadState_UNREAD;
@@ -60,11 +52,7 @@ const sync_pb::CoalescedSyncedNotification_ReadState kUnread =
std::string GetNotificationId(const SyncData& sync_data) {
SyncedNotificationSpecifics specifics = sync_data.GetSpecifics().
synced_notification();
- std::string notification_id = specifics.
- coalesced_notification().id().app_id();
- notification_id += "/";
- notification_id += specifics.coalesced_notification().id().coalescing_key();
- return notification_id;
+ return specifics.coalesced_notification().key();
}
// Stub out the NotificationUIManager for unit testing.
@@ -194,10 +182,10 @@ class ChromeNotifierServiceTest : public testing::Test {
SyncedNotification* CreateNotification(
const std::string& message,
const std::string& app_id,
- const std::string& coalescing_key,
+ const std::string& key,
const std::string& external_id,
sync_pb::CoalescedSyncedNotification_ReadState read_state) {
- SyncData sync_data = CreateSyncData(message, app_id, coalescing_key,
+ SyncData sync_data = CreateSyncData(message, app_id, key,
external_id, read_state);
// Set enough fields in sync_data, including specifics, for our tests
// to pass.
@@ -221,7 +209,7 @@ class ChromeNotifierServiceTest : public testing::Test {
static SyncData CreateSyncData(
const std::string& message,
const std::string& app_id,
- const std::string& coalescing_key,
+ const std::string& key,
const std::string& external_id,
sync_pb::CoalescedSyncedNotification_ReadState read_state) {
// CreateLocalData makes a copy of this, so this can safely live
@@ -232,34 +220,31 @@ class ChromeNotifierServiceTest : public testing::Test {
entity_specifics.mutable_synced_notification();
specifics->mutable_coalesced_notification()->
- mutable_render_info()->
- mutable_layout()->
- set_layout_type(
- SyncedNotificationRenderInfo_Layout_LayoutType_TITLE_AND_SUBTEXT);
-
- specifics->mutable_coalesced_notification()->
- mutable_id()->
set_app_id(app_id);
specifics->mutable_coalesced_notification()->
- mutable_id()->
- set_coalescing_key(coalescing_key);
+ set_key(key);
specifics->mutable_coalesced_notification()->
mutable_render_info()->
- mutable_layout()->
- mutable_title_and_subtext_data()->
+ mutable_expanded_info()->
+ mutable_simple_expanded_layout()->
set_title(message);
- specifics->mutable_coalesced_notification()->
+ specifics->
+ mutable_coalesced_notification()->
set_creation_time_msec(kFakeCreationTime);
- specifics->mutable_coalesced_notification()->
+ specifics->
+ mutable_coalesced_notification()->
add_notification();
- specifics->mutable_coalesced_notification()->
+
+ specifics->
+ mutable_coalesced_notification()->
mutable_notification(0)->set_external_id(external_id);
- specifics->mutable_coalesced_notification()->
+ specifics->
+ mutable_coalesced_notification()->
set_read_state(read_state);
SyncData sync_data = SyncData::CreateLocalData(
@@ -283,7 +268,7 @@ class ChromeNotifierServiceTest : public testing::Test {
// Create a Notification, convert it to SyncData and convert it back.
TEST_F(ChromeNotifierServiceTest, NotificationToSyncDataToNotification) {
scoped_ptr<SyncedNotification> notification1(
- CreateNotification("1", kAppId1, kCoalescingKey1, "11", kUnread));
+ CreateNotification("1", kAppId1, kKey1, "11", kUnread));
SyncData sync_data =
ChromeNotifierService::CreateSyncDataFromNotification(*notification1);
scoped_ptr<SyncedNotification> notification2(
@@ -324,13 +309,13 @@ TEST_F(ChromeNotifierServiceTest, ProcessSyncChangesEmptyModel) {
SyncChangeList changes;
changes.push_back(CreateSyncChange(
SyncChange::ACTION_ADD, CreateNotification(
- "1", kAppId1, kCoalescingKey1, "11", kUnread)));
+ "1", kAppId1, kKey1, "11", kUnread)));
changes.push_back(CreateSyncChange(
SyncChange::ACTION_ADD, CreateNotification(
- "2", kAppId2, kCoalescingKey2, "22", kUnread)));
+ "2", kAppId2, kKey2, "22", kUnread)));
changes.push_back(CreateSyncChange(
SyncChange::ACTION_ADD, CreateNotification(
- "3", kAppId3, kCoalescingKey3, "33", kUnread)));
+ "3", kAppId3, kKey3, "33", kUnread)));
notifier.ProcessSyncChanges(FROM_HERE, changes);
@@ -347,24 +332,24 @@ TEST_F(ChromeNotifierServiceTest, LocalRemoteBothNonEmptyNoOverlap) {
// Create some local fake data.
scoped_ptr<SyncedNotification> n1(CreateNotification(
- "1", kAppId1, kCoalescingKey1, "11", kUnread));
+ "1", kAppId1, kKey1, "11", kUnread));
notifier.AddForTest(n1.Pass());
scoped_ptr<SyncedNotification> n2(CreateNotification(
- "2", kAppId2, kCoalescingKey2, "22", kUnread));
+ "2", kAppId2, kKey2, "22", kUnread));
notifier.AddForTest(n2.Pass());
scoped_ptr<SyncedNotification> n3(CreateNotification(
- "3", kAppId3, kCoalescingKey3, "33", kUnread));
+ "3", kAppId3, kKey3, "33", kUnread));
notifier.AddForTest(n3.Pass());
// Create some remote fake data.
SyncDataList initial_data;
- initial_data.push_back(CreateSyncData("4", kAppId4, kCoalescingKey4,
+ initial_data.push_back(CreateSyncData("4", kAppId4, kKey4,
"44", kUnread));
- initial_data.push_back(CreateSyncData("5", kAppId5, kCoalescingKey5,
+ initial_data.push_back(CreateSyncData("5", kAppId5, kKey5,
"55", kUnread));
- initial_data.push_back(CreateSyncData("6", kAppId6, kCoalescingKey6,
+ initial_data.push_back(CreateSyncData("6", kAppId6, kKey6,
"66", kUnread));
- initial_data.push_back(CreateSyncData("7", kAppId7, kCoalescingKey7,
+ initial_data.push_back(CreateSyncData("7", kAppId7, kKey7,
"77", kUnread));
// Merge the local and remote data.
@@ -376,13 +361,13 @@ TEST_F(ChromeNotifierServiceTest, LocalRemoteBothNonEmptyNoOverlap) {
// Ensure the local store now has all local and remote notifications.
EXPECT_EQ(7U, notifier.GetAllSyncData(SYNCED_NOTIFICATIONS).size());
- EXPECT_TRUE(notifier.FindNotificationById(kNotificationId1));
- EXPECT_TRUE(notifier.FindNotificationById(kNotificationId2));
- EXPECT_TRUE(notifier.FindNotificationById(kNotificationId3));
- EXPECT_TRUE(notifier.FindNotificationById(kNotificationId4));
- EXPECT_TRUE(notifier.FindNotificationById(kNotificationId5));
- EXPECT_TRUE(notifier.FindNotificationById(kNotificationId6));
- EXPECT_TRUE(notifier.FindNotificationById(kNotificationId7));
+ EXPECT_TRUE(notifier.FindNotificationById(kKey1));
+ EXPECT_TRUE(notifier.FindNotificationById(kKey2));
+ EXPECT_TRUE(notifier.FindNotificationById(kKey3));
+ EXPECT_TRUE(notifier.FindNotificationById(kKey4));
+ EXPECT_TRUE(notifier.FindNotificationById(kKey5));
+ EXPECT_TRUE(notifier.FindNotificationById(kKey6));
+ EXPECT_TRUE(notifier.FindNotificationById(kKey7));
// Test the type conversion and construction functions.
for (SyncDataList::const_iterator iter = initial_data.begin();
@@ -396,9 +381,9 @@ TEST_F(ChromeNotifierServiceTest, LocalRemoteBothNonEmptyNoOverlap) {
EXPECT_TRUE(notification1->EqualsIgnoringReadState(*notification2));
EXPECT_EQ(notification1->read_state(), notification2->read_state());
}
- EXPECT_TRUE(notifier.FindNotificationById(kNotificationId1));
- EXPECT_TRUE(notifier.FindNotificationById(kNotificationId2));
- EXPECT_TRUE(notifier.FindNotificationById(kNotificationId3));
+ EXPECT_TRUE(notifier.FindNotificationById(kKey1));
+ EXPECT_TRUE(notifier.FindNotificationById(kKey2));
+ EXPECT_TRUE(notifier.FindNotificationById(kKey3));
}
// Test the local store having the read bit unset, the remote store having
@@ -409,16 +394,16 @@ TEST_F(ChromeNotifierServiceTest, ModelAssocBothNonEmptyReadMismatch1) {
// Create some local fake data.
scoped_ptr<SyncedNotification> n1(CreateNotification(
- "1", kAppId1, kCoalescingKey1, "11", kUnread));
+ "1", kAppId1, kKey1, "11", kUnread));
notifier.AddForTest(n1.Pass());
scoped_ptr<SyncedNotification> n2(CreateNotification(
- "2", kAppId2, kCoalescingKey2, "22", kUnread));
+ "2", kAppId2, kKey2, "22", kUnread));
notifier.AddForTest(n2.Pass());
// Create some remote fake data, item 1 matches except for the read state.
syncer::SyncDataList initial_data;
- initial_data.push_back(CreateSyncData("1", kAppId1, kCoalescingKey1,
- "11", kRead));
+ initial_data.push_back(CreateSyncData("1", kAppId1, kKey1,
+ "11", kDismissed));
// Merge the local and remote data.
notifier.MergeDataAndStartSyncing(
syncer::SYNCED_NOTIFICATIONS,
@@ -430,15 +415,15 @@ TEST_F(ChromeNotifierServiceTest, ModelAssocBothNonEmptyReadMismatch1) {
// state of the first is now read.
EXPECT_EQ(2U, notifier.GetAllSyncData(syncer::SYNCED_NOTIFICATIONS).size());
SyncedNotification* notification1 =
- notifier.FindNotificationById(kNotificationId1);
+ notifier.FindNotificationById(kKey1);
EXPECT_FALSE(NULL == notification1);
- EXPECT_EQ(SyncedNotification::kRead, notification1->read_state());
- EXPECT_TRUE(notifier.FindNotificationById(kNotificationId2));
- EXPECT_FALSE(notifier.FindNotificationById(kNotificationId3));
+ EXPECT_EQ(SyncedNotification::kDismissed, notification1->read_state());
+ EXPECT_TRUE(notifier.FindNotificationById(kKey2));
+ EXPECT_FALSE(notifier.FindNotificationById(kKey3));
// Ensure no new data will be sent to the remote store for notification1.
EXPECT_EQ(0U, processor()->change_list_size());
- EXPECT_FALSE(processor()->ContainsId(kNotificationId1));
+ EXPECT_FALSE(processor()->ContainsId(kKey1));
}
// Test when the local store has the read bit set, and the remote store has
@@ -449,15 +434,15 @@ TEST_F(ChromeNotifierServiceTest, ModelAssocBothNonEmptyReadMismatch2) {
// Create some local fake data.
scoped_ptr<SyncedNotification> n1(CreateNotification(
- "1", kAppId1, kCoalescingKey1, "11", kRead));
+ "1", kAppId1, kKey1, "11", kDismissed));
notifier.AddForTest(n1.Pass());
scoped_ptr<SyncedNotification> n2(CreateNotification(
- "2", kAppId2, kCoalescingKey2, "22", kUnread));
+ "2", kAppId2, kKey2, "22", kUnread));
notifier.AddForTest(n2.Pass());
// Create some remote fake data, item 1 matches except for the read state.
syncer::SyncDataList initial_data;
- initial_data.push_back(CreateSyncData("1", kAppId1, kCoalescingKey1,
+ initial_data.push_back(CreateSyncData("1", kAppId1, kKey1,
"11", kUnread));
// Merge the local and remote data.
notifier.MergeDataAndStartSyncing(
@@ -470,17 +455,17 @@ TEST_F(ChromeNotifierServiceTest, ModelAssocBothNonEmptyReadMismatch2) {
// state of the first is now read.
EXPECT_EQ(2U, notifier.GetAllSyncData(syncer::SYNCED_NOTIFICATIONS).size());
SyncedNotification* notification1 =
- notifier.FindNotificationById(kNotificationId1);
+ notifier.FindNotificationById(kKey1);
EXPECT_FALSE(NULL == notification1);
- EXPECT_EQ(SyncedNotification::kRead, notification1->read_state());
- EXPECT_TRUE(notifier.FindNotificationById(kNotificationId2));
- EXPECT_FALSE(notifier.FindNotificationById(kNotificationId3));
+ EXPECT_EQ(SyncedNotification::kDismissed, notification1->read_state());
+ EXPECT_TRUE(notifier.FindNotificationById(kKey2));
+ EXPECT_FALSE(notifier.FindNotificationById(kKey3));
// Ensure the new data will be sent to the remote store for notification1.
EXPECT_EQ(1U, processor()->change_list_size());
- EXPECT_TRUE(processor()->ContainsId(kNotificationId1));
+ EXPECT_TRUE(processor()->ContainsId(kKey1));
EXPECT_EQ(SyncChange::ACTION_UPDATE, processor()->GetChangeById(
- kNotificationId1).change_type());
+ kKey1).change_type());
}
// We have a notification in the local store, we get an updated version
@@ -491,13 +476,12 @@ TEST_F(ChromeNotifierServiceTest, ModelAssocBothNonEmptyWithUpdate) {
// Create some local fake data.
scoped_ptr<SyncedNotification> n1(CreateNotification(
- "1", kAppId1, kCoalescingKey1, "11", kRead));
+ "1", kAppId1, kKey1, "11", kDismissed));
notifier.AddForTest(n1.Pass());
-
// Create some remote fake data, item 1 matches the ID, but has different data
syncer::SyncDataList initial_data;
- initial_data.push_back(CreateSyncData("One", kAppId1, kCoalescingKey1,
+ initial_data.push_back(CreateSyncData("One", kAppId1, kKey1,
"Eleven", kUnread));
// Merge the local and remote data.
notifier.MergeDataAndStartSyncing(
@@ -509,7 +493,7 @@ TEST_F(ChromeNotifierServiceTest, ModelAssocBothNonEmptyWithUpdate) {
// Ensure the local store still has only one notification
EXPECT_EQ(1U, notifier.GetAllSyncData(syncer::SYNCED_NOTIFICATIONS).size());
SyncedNotification* notification1 =
- notifier.FindNotificationById(kNotificationId1);
+ notifier.FindNotificationById(kKey1);
EXPECT_FALSE(NULL == notification1);
EXPECT_EQ(SyncedNotification::kUnread, notification1->read_state());
EXPECT_EQ("One", notification1->title());
@@ -517,7 +501,7 @@ TEST_F(ChromeNotifierServiceTest, ModelAssocBothNonEmptyWithUpdate) {
// Ensure no new data will be sent to the remote store for notification1.
EXPECT_EQ(0U, processor()->change_list_size());
- EXPECT_FALSE(processor()->ContainsId(kNotificationId1));
+ EXPECT_FALSE(processor()->ContainsId(kKey1));
}
// TODO(petewil): There are more tests to add, such as when we add an API
diff --git a/chrome/browser/notifications/sync_notifier/synced_notification.cc b/chrome/browser/notifications/sync_notifier/synced_notification.cc
index e225a47..951a50d 100644
--- a/chrome/browser/notifications/sync_notifier/synced_notification.cc
+++ b/chrome/browser/notifications/sync_notifier/synced_notification.cc
@@ -21,6 +21,10 @@ COMPILE_ASSERT(static_cast<sync_pb::CoalescedSyncedNotification_ReadState>(
SyncedNotification::kRead) ==
sync_pb::CoalescedSyncedNotification_ReadState_READ,
local_enum_must_match_protobuf_enum);
+COMPILE_ASSERT(static_cast<sync_pb::CoalescedSyncedNotification_ReadState>(
+ SyncedNotification::kDismissed) ==
+ sync_pb::CoalescedSyncedNotification_ReadState_DISMISSED,
+ local_enum_must_match_protobuf_enum);
SyncedNotification::SyncedNotification(const syncer::SyncData& sync_data) {
Update(sync_data);
@@ -32,32 +36,38 @@ void SyncedNotification::Update(const syncer::SyncData& sync_data) {
specifics_.CopyFrom(sync_data.GetSpecifics().synced_notification());
}
-sync_pb::EntitySpecifics
-SyncedNotification::GetEntitySpecifics() const {
+sync_pb::EntitySpecifics SyncedNotification::GetEntitySpecifics() const {
sync_pb::EntitySpecifics entity_specifics;
entity_specifics.mutable_synced_notification()->CopyFrom(specifics_);
return entity_specifics;
}
-
std::string SyncedNotification::title() const {
return ExtractTitle();
}
+std::string SyncedNotification::heading() const {
+ return ExtractHeading();
+}
+
+std::string SyncedNotification::description() const {
+ return ExtractDescription();
+}
+
std::string SyncedNotification::app_id() const {
return ExtractAppId();
}
-std::string SyncedNotification::coalescing_key() const {
- return ExtractCoalescingKey();
+std::string SyncedNotification::key() const {
+ return ExtractKey();
}
GURL SyncedNotification::origin_url() const {
return ExtractOriginUrl();
}
-GURL SyncedNotification::icon_url() const {
- return ExtractIconUrl();
+GURL SyncedNotification::app_icon_url() const {
+ return ExtractAppIconUrl();
}
GURL SyncedNotification::image_url() const {
@@ -72,8 +82,8 @@ std::string SyncedNotification::notification_id() const {
return ExtractNotificationId();
}
-std::string SyncedNotification::body() const {
- return ExtractBody();
+std::string SyncedNotification::text() const {
+ return ExtractText();
}
SyncedNotification::ReadState SyncedNotification::read_state() const {
@@ -85,12 +95,10 @@ bool SyncedNotification::EqualsIgnoringReadState(
const SyncedNotification& other) const {
return (title() == other.title() &&
app_id() == other.app_id() &&
- coalescing_key() == other.coalescing_key() &&
- first_external_id() == other.first_external_id() &&
- notification_id() == other.notification_id() &&
- body() == other.body() &&
+ key() == other.key() &&
+ text() == other.text() &&
origin_url() == other.origin_url() &&
- icon_url() == other.icon_url() &&
+ app_icon_url() == other.app_icon_url() &&
image_url() == other.image_url() );
}
@@ -104,21 +112,27 @@ bool SyncedNotification::IdMatches(const SyncedNotification& other) const {
void SyncedNotification::SetReadState(const ReadState& read_state) {
// convert the read state to the protobuf type for read state
- if (kRead == read_state)
- specifics_.mutable_coalesced_notification()->
- set_read_state(sync_pb::CoalescedSyncedNotification_ReadState_READ);
+ if (kDismissed == read_state)
+ specifics_.mutable_coalesced_notification()->set_read_state(
+ sync_pb::CoalescedSyncedNotification_ReadState_DISMISSED);
else if (kUnread == read_state)
- specifics_.mutable_coalesced_notification()->
- set_read_state(sync_pb::CoalescedSyncedNotification_ReadState_UNREAD);
+ specifics_.mutable_coalesced_notification()->set_read_state(
+ sync_pb::CoalescedSyncedNotification_ReadState_UNREAD);
+ else if (kRead == read_state)
+ specifics_.mutable_coalesced_notification()->set_read_state(
+ sync_pb::CoalescedSyncedNotification_ReadState_READ);
else
NOTREACHED();
}
-// Mark this notification as having been read locally.
void SyncedNotification::NotificationHasBeenRead() {
SetReadState(kRead);
}
+void SyncedNotification::NotificationHasBeenDismissed() {
+ SetReadState(kDismissed);
+}
+
std::string SyncedNotification::ExtractFirstExternalId() const {
if (!specifics_.has_coalesced_notification() ||
specifics_.coalesced_notification().notification_size() < 1 ||
@@ -129,56 +143,42 @@ std::string SyncedNotification::ExtractFirstExternalId() const {
}
std::string SyncedNotification::ExtractTitle() const {
- if (!specifics_.coalesced_notification().render_info().layout().
- has_layout_type())
- return std::string();
+ if (!specifics_.coalesced_notification().render_info().expanded_info().
+ simple_expanded_layout().has_title())
+ return "";
- const sync_pb::SyncedNotificationRenderInfo_Layout_LayoutType layout_type =
- specifics_.coalesced_notification().render_info().layout().
- layout_type();
-
- // Depending on the layout type, get the proper title.
- switch (layout_type) {
- case sync_pb::
- SyncedNotificationRenderInfo_Layout_LayoutType_TITLE_AND_SUBTEXT: {
- // If we have title and subtext, get that title.
- if (!specifics_.coalesced_notification().render_info().layout().
- title_and_subtext_data().has_title())
- return std::string();
-
- return specifics_.coalesced_notification().render_info().layout().
- title_and_subtext_data().title();
- }
-
- case sync_pb::
- SyncedNotificationRenderInfo_Layout_LayoutType_TITLE_AND_IMAGE: {
- // If we have title and image, get that title.
- if (!specifics_.coalesced_notification().render_info().layout().
- title_and_image_data().has_title())
- return std::string();
-
- return specifics_.coalesced_notification().render_info().layout().
- title_and_image_data().title();
- }
- default: {
- // This is an error case, we should never get here unless the protobuf
- // is bad, or a new type is introduced and this code does not get updated.
- NOTREACHED();
- return std::string();
- }
- }
+ return specifics_.coalesced_notification().render_info().expanded_info().
+ simple_expanded_layout().title();
+}
+
+std::string SyncedNotification::ExtractHeading() const {
+ if (!specifics_.coalesced_notification().render_info().collapsed_info().
+ simple_collapsed_layout().has_heading())
+ return "";
+
+ return specifics_.coalesced_notification().render_info().collapsed_info().
+ simple_collapsed_layout().heading();
+}
+
+std::string SyncedNotification::ExtractDescription() const {
+ if (!specifics_.coalesced_notification().render_info().collapsed_info().
+ simple_collapsed_layout().has_description())
+ return "";
+
+ return specifics_.coalesced_notification().render_info().collapsed_info().
+ simple_collapsed_layout().description();
}
std::string SyncedNotification::ExtractAppId() const {
- if (!specifics_.coalesced_notification().id().has_app_id())
- return std::string();
- return specifics_.coalesced_notification().id().app_id();
+ if (!specifics_.coalesced_notification().has_app_id())
+ return "";
+ return specifics_.coalesced_notification().app_id();
}
-std::string SyncedNotification::ExtractCoalescingKey() const {
- if (!specifics_.coalesced_notification().id().has_coalescing_key())
- return std::string();
- return specifics_.coalesced_notification().id().coalescing_key();
+std::string SyncedNotification::ExtractKey() const {
+ if (!specifics_.coalesced_notification().has_key())
+ return "";
+ return specifics_.coalesced_notification().key();
}
GURL SyncedNotification::ExtractOriginUrl() const {
@@ -187,85 +187,42 @@ GURL SyncedNotification::ExtractOriginUrl() const {
return GURL(origin_url);
}
-GURL SyncedNotification::ExtractIconUrl() const {
- if (!specifics_.coalesced_notification().render_info().layout().
- has_layout_type())
+GURL SyncedNotification::ExtractAppIconUrl() const {
+ if (specifics_.coalesced_notification().render_info().expanded_info().
+ collapsed_info_size() == 0)
return GURL();
- const sync_pb::SyncedNotificationRenderInfo_Layout_LayoutType layout_type =
- specifics_.coalesced_notification().render_info().layout().
- layout_type();
-
- // Depending on the layout type, get the icon.
- if (sync_pb::SyncedNotificationRenderInfo_Layout_LayoutType_TITLE_AND_SUBTEXT
- == layout_type) {
- // If we have title and subtext, get that icon.
- if (!specifics_.coalesced_notification().render_info().layout().
- title_and_subtext_data().icon().has_url())
- return GURL();
+ if (!specifics_.coalesced_notification().render_info().expanded_info().
+ collapsed_info(0).simple_collapsed_layout().has_app_icon())
+ return GURL();
- return GURL(specifics_.coalesced_notification().render_info().layout().
- title_and_subtext_data().icon().url());
- }
- return GURL();
+ return GURL(specifics_.coalesced_notification().render_info().
+ expanded_info().collapsed_info(0).simple_collapsed_layout().
+ app_icon().url());
}
+// TODO(petewil): This currenly only handles the first image from the first
+// collapsed item, someday return all images.
GURL SyncedNotification::ExtractImageUrl() const {
- if (!specifics_.coalesced_notification().render_info().layout().
- has_layout_type())
+ if (specifics_.coalesced_notification().render_info().expanded_info().
+ simple_expanded_layout().media_size() == 0)
return GURL();
- const sync_pb::SyncedNotificationRenderInfo_Layout_LayoutType layout_type =
- specifics_.coalesced_notification().render_info().layout().
- layout_type();
-
- // Depending on the layout type, get the image.
- if (sync_pb::SyncedNotificationRenderInfo_Layout_LayoutType_TITLE_AND_IMAGE
- == layout_type) {
- // If we have title and subtext, get that image.
- if (!specifics_.coalesced_notification().render_info().layout().
- title_and_image_data().image().has_url())
- return GURL();
+ if (!specifics_.coalesced_notification().render_info().expanded_info().
+ simple_expanded_layout().media(0).image().has_url())
+ return GURL();
- return GURL(specifics_.coalesced_notification().render_info().layout().
- title_and_image_data().image().url());
- }
- return GURL();
+ return GURL(specifics_.coalesced_notification().render_info().
+ expanded_info().simple_expanded_layout().media(0).image().url());
}
-std::string SyncedNotification::ExtractBody() const {
- // If we have subtext data, concatenate the text lines and return it.
- if (!specifics_.coalesced_notification().render_info().layout().
- has_layout_type())
- return std::string();
+std::string SyncedNotification::ExtractText() const {
+ if (!specifics_.coalesced_notification().render_info().expanded_info().
+ simple_expanded_layout().has_text())
+ return "";
- const sync_pb::SyncedNotificationRenderInfo_Layout_LayoutType layout_type =
- specifics_.coalesced_notification().render_info().layout().
- layout_type();
-
- // Check if this layout type includes body text.
- if (sync_pb::SyncedNotificationRenderInfo_Layout_LayoutType_TITLE_AND_SUBTEXT
- == layout_type) {
- // If we have title and subtext, get the text.
- if (!specifics_.coalesced_notification().render_info().layout().
- has_title_and_subtext_data())
- return std::string();
- int subtext_lines = specifics_.coalesced_notification().render_info().
- layout().title_and_subtext_data().subtext_size();
- if (subtext_lines < 1)
- return std::string();
-
- std::string subtext;
- for (int ii = 0; ii < subtext_lines; ++ii) {
- subtext += specifics_.coalesced_notification().render_info().
- layout().
- title_and_subtext_data().subtext(ii);
- if (ii < subtext_lines - 1)
- subtext += '\n';
- }
- return subtext;
- }
- return std::string();
+ return specifics_.coalesced_notification().render_info().expanded_info().
+ simple_expanded_layout().text();
}
SyncedNotification::ReadState SyncedNotification::ExtractReadState() const {
@@ -274,11 +231,15 @@ SyncedNotification::ReadState SyncedNotification::ExtractReadState() const {
sync_pb::CoalescedSyncedNotification_ReadState found_read_state =
specifics_.coalesced_notification().read_state();
- if (found_read_state == sync_pb::CoalescedSyncedNotification_ReadState_READ) {
- return kRead;
+ if (found_read_state ==
+ sync_pb::CoalescedSyncedNotification_ReadState_DISMISSED) {
+ return kDismissed;
} else if (found_read_state ==
sync_pb::CoalescedSyncedNotification_ReadState_UNREAD) {
return kUnread;
+ } else if (found_read_state ==
+ sync_pb::CoalescedSyncedNotification_ReadState_READ) {
+ return kRead;
} else {
NOTREACHED();
return static_cast<SyncedNotification::ReadState>(found_read_state);
@@ -286,12 +247,7 @@ SyncedNotification::ReadState SyncedNotification::ExtractReadState() const {
}
std::string SyncedNotification::ExtractNotificationId() const {
- // Append the coalescing key to the app id to get the unique id.
- std::string id = app_id();
- id += "/";
- id += coalescing_key();
-
- return id;
+ return key();
}
} // namespace notifier
diff --git a/chrome/browser/notifications/sync_notifier/synced_notification.h b/chrome/browser/notifications/sync_notifier/synced_notification.h
index 90e2185..b7eb805 100644
--- a/chrome/browser/notifications/sync_notifier/synced_notification.h
+++ b/chrome/browser/notifications/sync_notifier/synced_notification.h
@@ -31,6 +31,7 @@ class SyncedNotification {
enum ReadState {
kUnread = 1,
kRead = 2,
+ kDismissed = 3,
};
void Update(const syncer::SyncData& sync_data);
@@ -39,20 +40,23 @@ class SyncedNotification {
// SyncedNotification.
// TODO(petewil): Add more types as we expand support for the protobuf.
std::string title() const;
+ std::string heading() const;
+ std::string description() const;
std::string app_id() const;
- std::string coalescing_key() const;
+ std::string key() const;
GURL origin_url() const;
- GURL icon_url() const;
+ GURL app_icon_url() const;
GURL image_url() const;
std::string first_external_id() const;
std::string notification_id() const;
- std::string body() const;
+ std::string text() const;
ReadState read_state() const;
bool EqualsIgnoringReadState(const SyncedNotification& other) const;
bool IdMatches(const SyncedNotification& other) const;
void NotificationHasBeenRead();
+ void NotificationHasBeenDismissed();
// This gets a pointer to the SyncedNotificationSpecifics part
// of the sync data.
@@ -65,14 +69,16 @@ class SyncedNotification {
// Parsing functions to get this information out of the sync_data and into
// our local variables.
std::string ExtractTitle() const;
+ std::string ExtractHeading() const;
+ std::string ExtractDescription() const;
std::string ExtractAppId() const;
- std::string ExtractCoalescingKey() const;
+ std::string ExtractKey() const;
GURL ExtractOriginUrl() const;
- GURL ExtractIconUrl() const;
+ GURL ExtractAppIconUrl() const;
GURL ExtractImageUrl() const;
std::string ExtractFirstExternalId() const;
std::string ExtractNotificationId() const;
- std::string ExtractBody() const;
+ std::string ExtractText() const;
ReadState ExtractReadState() const;
sync_pb::SyncedNotificationSpecifics specifics_;
diff --git a/chrome/browser/notifications/sync_notifier/synced_notification_unittest.cc b/chrome/browser/notifications/sync_notifier/synced_notification_unittest.cc
index 4b928d3..f77af5e 100644
--- a/chrome/browser/notifications/sync_notifier/synced_notification_unittest.cc
+++ b/chrome/browser/notifications/sync_notifier/synced_notification_unittest.cc
@@ -15,7 +15,6 @@ using syncer::SyncData;
using notifier::SyncedNotification;
using sync_pb::EntitySpecifics;
using sync_pb::SyncedNotificationSpecifics;
-using sync_pb::SyncedNotificationRenderInfo_Layout_LayoutType_TITLE_AND_SUBTEXT;
namespace {
@@ -26,11 +25,11 @@ const char kTitle2[] = "Email from Mark: Upcoming Ski trip";
const char kTitle3[] = "Weather alert - light rain tonight.";
const char kAppId1[] = "fboilmbenheemaomgaeehigklolhkhnf";
const char kAppId2[] = "fbcmoldooppoahjhfflnmljoanccekpf";
-const char kCoalescingKey1[] = "foo";
-const char kCoalescingKey2[] = "bar";
-const char kBody1[] = "Space Needle, 12:00 pm";
-const char kBody2[] = "Stevens Pass is our first choice.";
-const char kBody3[] = "More rain expected in the Seattle area tonight.";
+const char kKey1[] = "foo";
+const char kKey2[] = "bar";
+const char kText1[] = "Space Needle, 12:00 pm";
+const char kText2[] = "Stevens Pass is our first choice.";
+const char kText3[] = "More rain expected in the Seattle area tonight.";
const char kIconUrl1[] = "http://www.google.com/icon1.jpg";
const char kIconUrl2[] = "http://www.google.com/icon2.jpg";
const char kIconUrl3[] = "http://www.google.com/icon3.jpg";
@@ -41,6 +40,8 @@ const sync_pb::CoalescedSyncedNotification_ReadState kRead =
sync_pb::CoalescedSyncedNotification_ReadState_READ;
const sync_pb::CoalescedSyncedNotification_ReadState kUnread =
sync_pb::CoalescedSyncedNotification_ReadState_UNREAD;
+const sync_pb::CoalescedSyncedNotification_ReadState kDismissed =
+ sync_pb::CoalescedSyncedNotification_ReadState_DISMISSED;
} // namespace
class SyncedNotificationTest : public testing::Test {
@@ -51,17 +52,17 @@ class SyncedNotificationTest : public testing::Test {
// Methods from testing::Test.
virtual void SetUp() OVERRIDE {
- sync_data1_ = CreateSyncData(
- kTitle1, kBody1, kIconUrl1, kAppId1, kCoalescingKey1, kUnread);
- sync_data2_ = CreateSyncData(
- kTitle2, kBody2, kIconUrl2, kAppId2, kCoalescingKey2, kUnread);
+ sync_data1_ = CreateSyncData(kTitle1, kText1, kIconUrl1, kImageUrl1,
+ kAppId1, kKey1, kUnread);
+ sync_data2_ = CreateSyncData(kTitle2, kText2, kIconUrl2, kImageUrl1,
+ kAppId2, kKey2, kUnread);
// Notification 3 will have the same ID as notification1, but different
// data inside.
- sync_data3_ = CreateSyncData(
- kTitle3, kBody3, kIconUrl3, kAppId1, kCoalescingKey1, kUnread);
+ sync_data3_ = CreateSyncData(kTitle3, kText3, kIconUrl3, kImageUrl1,
+ kAppId1, kKey1, kUnread);
// Notification 4 will be the same as 1, but the read state will be 'read'.
- sync_data4_ = CreateSyncData(
- kTitle1, kBody1, kIconUrl1, kAppId1, kCoalescingKey1, kRead);
+ sync_data4_ = CreateSyncData(kTitle1, kText1, kIconUrl1, kImageUrl1,
+ kAppId1, kKey1, kDismissed);
notification1_.reset(new SyncedNotification(sync_data1_));
notification2_.reset(new SyncedNotification(sync_data2_));
@@ -85,10 +86,11 @@ class SyncedNotificationTest : public testing::Test {
// Helper to create syncer::SyncData.
static SyncData CreateSyncData(
const std::string& title,
- const std::string& body,
- const std::string& icon_url,
+ const std::string& text,
+ const std::string& app_icon_url,
+ const std::string& image_url,
const std::string& app_id,
- const std::string& coalescing_key,
+ const std::string& key,
const sync_pb::CoalescedSyncedNotification_ReadState read_state) {
// CreateLocalData makes a copy of this, so this can safely live
// on the stack.
@@ -100,37 +102,47 @@ class SyncedNotificationTest : public testing::Test {
entity_specifics.mutable_synced_notification();
specifics->mutable_coalesced_notification()->
- mutable_render_info()->
- mutable_layout()->
- set_layout_type(
- SyncedNotificationRenderInfo_Layout_LayoutType_TITLE_AND_SUBTEXT);
-
- specifics->mutable_coalesced_notification()->
- mutable_id()->
set_app_id(app_id);
specifics->mutable_coalesced_notification()->
- mutable_id()->
- set_coalescing_key(coalescing_key);
+ set_key(key);
specifics->mutable_coalesced_notification()->
mutable_render_info()->
- mutable_layout()->
- mutable_title_and_subtext_data()->
+ mutable_expanded_info()->
+ mutable_simple_expanded_layout()->
set_title(title);
specifics->mutable_coalesced_notification()->
mutable_render_info()->
- mutable_layout()->
- mutable_title_and_subtext_data()->
- add_subtext(body);
+ mutable_expanded_info()->
+ mutable_simple_expanded_layout()->
+ set_text(text);
+
+ specifics->mutable_coalesced_notification()->
+ mutable_render_info()->
+ mutable_expanded_info()->
+ add_collapsed_info();
+ specifics->mutable_coalesced_notification()->
+ mutable_render_info()->
+ mutable_expanded_info()->
+ mutable_collapsed_info(0)->
+ mutable_simple_collapsed_layout()->
+ mutable_app_icon()->
+ set_url(app_icon_url);
specifics->mutable_coalesced_notification()->
mutable_render_info()->
- mutable_layout()->
- mutable_title_and_subtext_data()->
- mutable_icon()->
- set_url(icon_url);
+ mutable_expanded_info()->
+ mutable_simple_expanded_layout()->
+ add_media();
+ specifics->mutable_coalesced_notification()->
+ mutable_render_info()->
+ mutable_expanded_info()->
+ mutable_simple_expanded_layout()->
+ mutable_media(0)->
+ mutable_image()->
+ set_url(image_url);
specifics->mutable_coalesced_notification()->
set_creation_time_msec(kFakeCreationTime);
@@ -164,9 +176,9 @@ TEST_F(SyncedNotificationTest, GetAppIdTest) {
EXPECT_EQ(found_app_id, expected_app_id);
}
-TEST_F(SyncedNotificationTest, GetCoalescingKeyTest) {
- std::string found_key = notification1_->coalescing_key();
- std::string expected_key(kCoalescingKey1);
+TEST_F(SyncedNotificationTest, GetKeyTest) {
+ std::string found_key = notification1_->key();
+ std::string expected_key(kKey1);
EXPECT_EQ(expected_key, found_key);
}
@@ -179,7 +191,7 @@ TEST_F(SyncedNotificationTest, GetTitleTest) {
}
TEST_F(SyncedNotificationTest, GetIconURLTest) {
- std::string found_icon_url = notification1_->icon_url().spec();
+ std::string found_icon_url = notification1_->app_icon_url().spec();
std::string expected_icon_url(kIconUrl1);
EXPECT_EQ(expected_icon_url, found_icon_url);
@@ -194,7 +206,7 @@ TEST_F(SyncedNotificationTest, GetReadStateTest) {
SyncedNotification::ReadState found_state2 =
notification4_->read_state();
- SyncedNotification::ReadState expected_state2(SyncedNotification::kRead);
+ SyncedNotification::ReadState expected_state2(SyncedNotification::kDismissed);
EXPECT_EQ(expected_state2, found_state2);
}
@@ -203,24 +215,22 @@ TEST_F(SyncedNotificationTest, GetReadStateTest) {
// pass on actual data.
TEST_F(SyncedNotificationTest, GetImageURLTest) {
std::string found_image_url = notification1_->image_url().spec();
- std::string expected_image_url; // TODO(petewil): (kImageUrl1)
+ std::string expected_image_url = kImageUrl1;
EXPECT_EQ(expected_image_url, found_image_url);
}
// TODO(petewil): test with a multi-line body
-TEST_F(SyncedNotificationTest, GetBodyTest) {
- std::string found_body = notification1_->body();
- std::string expected_body(kBody1);
+TEST_F(SyncedNotificationTest, GetTextTest) {
+ std::string found_text = notification1_->text();
+ std::string expected_text(kText1);
- EXPECT_EQ(expected_body, found_body);
+ EXPECT_EQ(expected_text, found_text);
}
TEST_F(SyncedNotificationTest, GetNotificationIdTest) {
std::string found_id = notification1_->notification_id();
- std::string expected_id(kAppId1);
- expected_id += "/";
- expected_id += kCoalescingKey1;
+ std::string expected_id(kKey1);
EXPECT_EQ(expected_id, found_id);
}
diff --git a/sync/protocol/synced_notification_data.proto b/sync/protocol/synced_notification_data.proto
index 1b8112e..fed7ee7 100644
--- a/sync/protocol/synced_notification_data.proto
+++ b/sync/protocol/synced_notification_data.proto
@@ -26,31 +26,59 @@ message SyncedNotificationIdentifier {
optional string coalescing_key = 2;
}
-message SyncedNotification {
- // The unique identifier of the notification.
- optional SyncedNotificationIdentifier id = 1;
+message SyncedNotificationCreator {
+ // The gaia id of the creator. If a notification does not have a clear
+ // creator, skip this and follow the directions below to use a system creator.
+ optional int64 gaia_id = 1;
+
+ // Indicates that the creator is a "system" creator. Example of these are
+ // notifications sent to the user where the addressee is "Google", such as the
+ // "You have violated our TOS, and have 3 days to fix it or you'll lose your
+ // account" notifications. If is_system is set, gaia_id must not be set and
+ // instead the app_id field must be set.
+ optional bool is_system = 2;
+
+ // Only set this in the system-creator case.
+ optional string app_id = 3;
+}
+
+message SyncedNotificationRecipients {
+ repeated int64 gaia_id = 1;
+
+ // For now, only support gaia id recipients. Add more recipient types via
+ // 'repeated Type other_type = X' when necessary.
+}
+message SyncedNotification {
// A secondary type that is isolated within the same app_id.
//
// NOTE: For ASBE support purposes this must be in the format [A-Za-z_]+.
- optional string type = 2;
+ optional string type = 1;
// Whatever string the client entered during creation. If no external_id is
// specified, the notification can no longer be identified individually for
// fetching/deleting, etc...
- optional string external_id = 3;
+ optional string external_id = 2;
+
+ // The creator of the notification.
+ optional SyncedNotificationCreator creator = 3;
+
+ // TODO(petewil): This won't build. Import the relevant protobuf.
+ // optional MapData client_data = 4;
}
message CoalescedSyncedNotification {
- // The identifier used to identify individual coalesced notifications.
- optional SyncedNotificationIdentifier id = 1;
+ // An opaque string key used to identify individual coalesced notifications.
+ optional string key = 1;
+
+ optional string app_id = 2;
// All the notifications that are grouped together.
- repeated SyncedNotification notification = 2;
+ repeated SyncedNotification notification = 3;
// Data that is used directly by endpoints to render notifications in the case
// where no "native" app can handle the notification.
- optional SyncedNotificationRenderInfo render_info = 3;
+ optional SyncedNotificationRenderInfo render_info = 4;
// Read state will be per coalesced notification.
enum ReadState {
@@ -58,9 +86,21 @@ message CoalescedSyncedNotification {
READ = 2;
DISMISSED = 3;
}
- optional ReadState read_state = 4;
+ optional ReadState read_state = 5;
// The time when the LATEST notification of the coalesced notification is
// created (in milliseconds since the linux epoch).
- optional uint64 creation_time_msec = 5;
+ optional uint64 creation_time_msec = 6;
+
+ enum Priority {
+ LOW = 1;
+ STANDARD = 2;
+ HIGH = 3;
+ // We will most likely add at least one more priority in the near future.
+ };
+ optional Priority priority = 7;
}
+
+message SyncedNotificationList {
+ repeated CoalescedSyncedNotification coalesced_notification = 1;
+} \ No newline at end of file
diff --git a/sync/protocol/synced_notification_render.proto b/sync/protocol/synced_notification_render.proto
index 47dd6c8..ce5a721 100644
--- a/sync/protocol/synced_notification_render.proto
+++ b/sync/protocol/synced_notification_render.proto
@@ -16,68 +16,121 @@ package sync_pb;
// Data that is used directly by endpoints to render notifications in the case
// where no "native" app can handle the notification.
message SyncedNotificationRenderInfo {
- message Layout {
- enum LayoutType {
- TITLE_AND_SUBTEXT = 1;
- TITLE_AND_IMAGE = 2;
+
+ // Render information for the collapsed (summary) view of a coalesced
+ // notification.
+ message CollapsedInfo {
+ message SimpleCollapsedLayout {
+ // Application icon.
+ optional SyncedNotificationImage app_icon = 1;
+
+ // Profile image(s) of the notification creator(s) to show in the
+ // collapsed UI.
+ repeated SyncedNotificationProfileImage profile_image = 2;
+
+ // Heading - often the name(s) of the notification creator(s).
+ optional string heading = 3;
+
+ // Description - often the action that generated the notification.
+ optional string description = 4;
}
- optional LayoutType layout_type = 1;
+ optional SimpleCollapsedLayout simple_collapsed_layout = 1;
- message TitleAndSubtextData {
- optional string title = 1;
- // The icon to show on the left of the notification.
- optional SyncedNotificationIcon icon = 2;
- // Multiple lines of the sub-text.
- repeated string subtext = 3;
+ // The creation time of the notification in microseconds since the UNIX
+ // epoch.
+ optional uint64 creation_timestamp_usec = 2;
+
+ // The default destination target.
+ optional SyncedNotificationDestination default_destination = 3;
+
+ // Secondary destinations and actions grouped into a message to account for
+ // ordering.
+ message Target {
+ optional SyncedNotificationDestination destination = 1;
+ optional SyncedNotificationAction action = 2;
}
- optional TitleAndSubtextData title_and_subtext_data = 3;
+ repeated Target target = 4;
+ }
+ optional CollapsedInfo collapsed_info = 1;
- message TitleAndImageData {
+ // Render information for the expanded (detail) view of a coalesced
+ // notification.
+ message ExpandedInfo {
+ message SimpleExpandedLayout {
+ // Title - often the title of the underlying entity referred to by the
+ // notification(s).
optional string title = 1;
- optional SyncedNotificationImage image = 2;
+
+ // Text content - often a snippet of text from the underlying entity
+ // reference or the notification.
+ optional string text = 2;
+
+ // Media.
+ message Media {
+ // TOOD(jro): Do we need other media types?
+ optional SyncedNotificationImage image = 1;
+ }
+ repeated Media media = 3;
}
- optional TitleAndImageData title_and_image_data = 4;
- }
- optional Layout layout = 1;
+ optional SimpleExpandedLayout simple_expanded_layout = 1;
- // An Action encapsulates an UI component that trigger certain programmable
- // actions. Depending on the endpoint, this may show up as a html button,
- // "quick actions" in the Android notification drawer, a link, or even the
- // notification card itself (the "default" action case).
- message Action {
- // The description for the Action.
- optional string text = 1;
+ // Collapsed information for each notification in the coalesced group.
+ repeated CollapsedInfo collapsed_info = 2;
+ }
+ optional ExpandedInfo expanded_info = 2;
+}
- // The icon to use for the Action.
- optional SyncedNotificationIcon icon = 2;
+// A Destination is a target URL that the user can be taken to by clicking on or
+// selecting the notification or part thereof.
+message SyncedNotificationDestination {
+ // The description for the link to the destination.
+ optional string text = 1;
- // Specify whether the action should be a background action or
- // should open up a web page with the specified URL.
- optional bool is_background = 3;
+ // The icon to use for the link to the destination.
+ optional SyncedNotificationImage icon = 2;
- // The url to send users to when they trigger the action.
- optional string action_url = 4;
+ // The destination URL.
+ optional string url = 3;
- // If post_data is populated, this indicates that action_url should be
- // contacted via a POST rather than a GET.
- optional string post_data = 5;
- }
- // All the actions that can be triggered from this (coalesced) notification.
- // This is sorted by importance so depending on the end point, the first N
- // actions should be used (and the first action is the "default" action).
- // For default actions, the icon and text params are ignored.
- repeated Action action = 2;
+ // Optional label to aid accessibility.
+ optional string accessibility_label = 4;
+}
+
+// An Action encapsulates an UI component that trigger certain programmable
+// actions. Depending on the endpoint, this may show up as a HTML button, an
+// action button associated with the notification on native mobile, a link, or
+// even the notification card itself.
+message SyncedNotificationAction {
+ // The description for the Action.
+ optional string text = 1;
+
+ // The icon to use for the Action.
+ optional SyncedNotificationImage icon = 2;
+
+ // The URL that performs the action.
+ optional string url = 3;
+
+ // Additional request data.
+ optional string request_data = 4;
+
+ // Optional label to aid accessibility.
+ optional string accessibility_label= 5;
}
message SyncedNotificationImage {
+ // Note that the image may be from any source. Clients wishing to resize the
+ // image should ensure the image is proxied appropriately.
optional string url = 1;
- // This is somewhat made up - not sure what else apart from url do we need
- // about an image.
optional string alt_text = 2;
optional int32 preferred_width = 3;
optional int32 preferred_height = 4;
}
-message SyncedNotificationIcon {
- optional string url = 1;
-}
+message SyncedNotificationProfileImage {
+ // Url for the image.
+ optional string image_url = 1;
+ // Object id for the image.
+ optional string oid = 2;
+ // Name to display for this image.
+ optional string display_name = 3;
+} \ No newline at end of file