summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoraruslan@chromium.org <aruslan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-01 00:09:59 +0000
committeraruslan@chromium.org <aruslan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-11-01 00:09:59 +0000
commit084f82bdeef5f754cc9e52155168fad902649ac9 (patch)
tree0bab992041e713af7fe12cacdafc3fada75d12b8
parent1403cbaadcad3593b0dd397dc9136fb4dcff8398 (diff)
downloadchromium_src-084f82bdeef5f754cc9e52155168fad902649ac9.zip
chromium_src-084f82bdeef5f754cc9e52155168fad902649ac9.tar.gz
chromium_src-084f82bdeef5f754cc9e52155168fad902649ac9.tar.bz2
Editable/removable partner bookmarks.
Persists renames/removals of the partner bookmarks and folders in the user profile. Details: https://goto.google.com/editable-partnerbookmarks BUG=266233 Review URL: https://codereview.chromium.org/26442002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@232241 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/android/testshell/testshell_tab.cc5
-rw-r--r--chrome/android/testshell/testshell_tab.h5
-rw-r--r--chrome/browser/android/tab_android.h5
-rw-r--r--chrome/browser/prefs/browser_prefs.cc2
-rw-r--r--chrome/browser/ui/webui/ntp/android/bookmarks_handler.cc118
-rw-r--r--chrome/browser/ui/webui/ntp/android/bookmarks_handler.h7
-rw-r--r--chrome/browser/ui/webui/ntp/android/partner_bookmarks_shim.cc264
-rw-r--r--chrome/browser/ui/webui/ntp/android/partner_bookmarks_shim.h119
-rw-r--r--chrome/browser/ui/webui/ntp/android/partner_bookmarks_shim_unittest.cc331
-rw-r--r--chrome/common/pref_names.cc11
-rw-r--r--chrome/common/pref_names.h4
11 files changed, 650 insertions, 221 deletions
diff --git a/chrome/android/testshell/testshell_tab.cc b/chrome/android/testshell/testshell_tab.cc
index e19de5a..6e94ea5 100644
--- a/chrome/android/testshell/testshell_tab.cc
+++ b/chrome/android/testshell/testshell_tab.cc
@@ -58,7 +58,10 @@ void TestShellTab::AddShortcutToBookmark(
NOTIMPLEMENTED();
}
-void TestShellTab::EditBookmark(int64 node_id, bool is_folder) {
+void TestShellTab::EditBookmark(int64 node_id,
+ const base::string16& node_title,
+ bool is_folder,
+ bool is_partner_bookmark) {
NOTIMPLEMENTED();
}
diff --git a/chrome/android/testshell/testshell_tab.h b/chrome/android/testshell/testshell_tab.h
index 2e01185..e1aa09d 100644
--- a/chrome/android/testshell/testshell_tab.h
+++ b/chrome/android/testshell/testshell_tab.h
@@ -57,7 +57,10 @@ class TestShellTab : public TabAndroid {
int r_value,
int g_value,
int b_value) OVERRIDE;
- virtual void EditBookmark(int64 node_id, bool is_folder) OVERRIDE;
+ virtual void EditBookmark(int64 node_id,
+ const base::string16& node_title,
+ bool is_folder,
+ bool is_partner_bookmark) OVERRIDE;
virtual bool ShouldWelcomePageLinkToTermsOfService() OVERRIDE;
virtual void OnNewTabPageReady() OVERRIDE;
diff --git a/chrome/browser/android/tab_android.h b/chrome/browser/android/tab_android.h
index adbc6a5..bbb29e6 100644
--- a/chrome/browser/android/tab_android.h
+++ b/chrome/browser/android/tab_android.h
@@ -97,7 +97,10 @@ class TabAndroid : public CoreTabHelperDelegate,
int r_value, int g_value, int b_value) = 0;
// Called when a bookmark node should be edited.
- virtual void EditBookmark(int64 node_id, bool is_folder) = 0;
+ virtual void EditBookmark(int64 node_id,
+ const base::string16& node_title,
+ bool is_folder,
+ bool is_partner_bookmark) = 0;
// Called to determine if chrome://welcome should contain links to the terms
// of service and the privacy notice.
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 69b2c86..e59b349 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -170,6 +170,7 @@
#endif
#if defined(OS_ANDROID)
+#include "chrome/browser/ui/webui/ntp/android/partner_bookmarks_shim.h"
#include "chrome/browser/ui/webui/ntp/android/promo_handler.h"
#else
#include "chrome/browser/profile_resetter/automatic_profile_resetter_factory.h"
@@ -394,6 +395,7 @@ void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
#endif
#if defined(OS_ANDROID)
+ PartnerBookmarksShim::RegisterProfilePrefs(registry);
PromoHandler::RegisterProfilePrefs(registry);
#endif
diff --git a/chrome/browser/ui/webui/ntp/android/bookmarks_handler.cc b/chrome/browser/ui/webui/ntp/android/bookmarks_handler.cc
index 406c8ae..e73609d 100644
--- a/chrome/browser/ui/webui/ntp/android/bookmarks_handler.cc
+++ b/chrome/browser/ui/webui/ntp/android/bookmarks_handler.cc
@@ -13,6 +13,7 @@
#include "chrome/browser/bookmarks/bookmark_model.h"
#include "chrome/browser/bookmarks/bookmark_model_factory.h"
#include "chrome/browser/favicon/favicon_service_factory.h"
+#include "chrome/browser/profiles/incognito_helpers.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/webui/favicon_source.h"
@@ -99,7 +100,9 @@ void BookmarksHandler::RegisterMessages() {
// Create the partner Bookmarks shim as early as possible (but don't attach).
if (!partner_bookmarks_shim_) {
- partner_bookmarks_shim_ = PartnerBookmarksShim::GetInstance();
+ partner_bookmarks_shim_ = PartnerBookmarksShim::BuildForBrowserContext(
+ chrome::GetBrowserContextRedirectedInIncognito(
+ web_ui()->GetWebContents()->GetBrowserContext()));
partner_bookmarks_shim_->AddObserver(this);
}
@@ -130,13 +133,6 @@ void BookmarksHandler::HandleGetBookmarks(const ListValue* args) {
if (!BookmarkModelFactory::GetForProfile(profile)->loaded())
return; // is handled in Loaded().
- // Attach the Partner Bookmarks shim under the Mobile Bookmarks.
- // Cannot do this earlier because mobile_node is not yet set.
- DCHECK(partner_bookmarks_shim_ != NULL);
- if (bookmark_model_) {
- partner_bookmarks_shim_->AttachTo(
- bookmark_model_, bookmark_model_->mobile_node());
- }
if (!partner_bookmarks_shim_->IsLoaded())
return; // is handled with a PartnerShimLoaded() callback
@@ -158,6 +154,11 @@ void BookmarksHandler::HandleDeleteBookmark(const ListValue* args) {
return;
}
+ if (partner_bookmarks_shim_->IsPartnerBookmark(node)) {
+ partner_bookmarks_shim_->RemoveBookmark(node);
+ return;
+ }
+
const BookmarkNode* parent_node = node->parent();
bookmark_model_->Remove(parent_node, parent_node->GetIndexOf(node));
}
@@ -174,8 +175,12 @@ void BookmarksHandler::HandleEditBookmark(const ListValue* args) {
}
TabAndroid* tab = TabAndroid::FromWebContents(web_ui()->GetWebContents());
- if (tab)
- tab->EditBookmark(node->id(), node->is_folder());
+ if (tab) {
+ tab->EditBookmark(node->id(),
+ GetTitle(node),
+ node->is_folder(),
+ partner_bookmarks_shim_->IsPartnerBookmark(node));
+ }
}
std::string BookmarksHandler::GetBookmarkIdForNtp(const BookmarkNode* node) {
@@ -197,8 +202,11 @@ void BookmarksHandler::PopulateBookmark(const BookmarkNode* node,
if (!result)
return;
+ if (!IsReachable(node))
+ return;
+
DictionaryValue* filler_value = new DictionaryValue();
- filler_value->SetString("title", node->GetTitle());
+ filler_value->SetString("title", GetTitle(node));
filler_value->SetBoolean("editable", IsEditable(node));
if (node->is_url()) {
filler_value->SetBoolean("folder", false);
@@ -214,6 +222,9 @@ void BookmarksHandler::PopulateBookmark(const BookmarkNode* node,
void BookmarksHandler::PopulateBookmarksInFolder(
const BookmarkNode* folder,
DictionaryValue* result) {
+ DCHECK(partner_bookmarks_shim_ != NULL);
+ DCHECK(IsReachable(folder));
+
ListValue* bookmarks = new ListValue();
// If this is the Mobile bookmarks folder then add the "Managed bookmarks"
@@ -230,11 +241,10 @@ void BookmarksHandler::PopulateBookmarksInFolder(
}
// Make sure we iterate over the partner's attach point
- DCHECK(partner_bookmarks_shim_ != NULL);
- if (partner_bookmarks_shim_->HasPartnerBookmarks() &&
- folder == partner_bookmarks_shim_->get_attach_point()) {
- PopulateBookmark(
- partner_bookmarks_shim_->GetPartnerBookmarksRoot(), bookmarks);
+ if (bookmark_model_ && folder == bookmark_model_->mobile_node() &&
+ partner_bookmarks_shim_->HasPartnerBookmarks()) {
+ PopulateBookmark(partner_bookmarks_shim_->GetPartnerBookmarksRoot(),
+ bookmarks);
}
ListValue* folder_hierarchy = new ListValue();
@@ -245,13 +255,13 @@ void BookmarksHandler::PopulateBookmarksInFolder(
if (IsRoot(parent))
hierarchy_entry->SetBoolean("root", true);
- hierarchy_entry->SetString("title", parent->GetTitle());
+ hierarchy_entry->SetString("title", GetTitle(parent));
hierarchy_entry->SetString("id", GetBookmarkIdForNtp(parent));
folder_hierarchy->Append(hierarchy_entry);
parent = GetParentOf(parent);
}
- result->SetString("title", folder->GetTitle());
+ result->SetString("title", GetTitle(folder));
result->SetString("id", GetBookmarkIdForNtp(folder));
result->SetBoolean("root", IsRoot(folder));
result->Set("bookmarks", bookmarks);
@@ -259,7 +269,7 @@ void BookmarksHandler::PopulateBookmarksInFolder(
}
void BookmarksHandler::QueryBookmarkFolder(const BookmarkNode* node) {
- if (node->is_folder()) {
+ if (node->is_folder() && IsReachable(node)) {
DictionaryValue result;
PopulateBookmarksInFolder(node, &result);
SendResult(result);
@@ -272,15 +282,7 @@ void BookmarksHandler::QueryBookmarkFolder(const BookmarkNode* node) {
void BookmarksHandler::QueryInitialBookmarks() {
DictionaryValue result;
- DCHECK(partner_bookmarks_shim_ != NULL);
-
- if (partner_bookmarks_shim_->HasPartnerBookmarks()) {
- PopulateBookmarksInFolder(
- partner_bookmarks_shim_->GetPartnerBookmarksRoot(), &result);
- } else {
- PopulateBookmarksInFolder(bookmark_model_->mobile_node(), &result);
- }
-
+ PopulateBookmarksInFolder(bookmark_model_->mobile_node(), &result);
SendResult(result);
}
@@ -292,6 +294,10 @@ void BookmarksHandler::Loaded(BookmarkModel* model, bool ids_reassigned) {
BookmarkModelChanged();
}
+void BookmarksHandler::PartnerShimChanged(PartnerBookmarksShim* shim) {
+ BookmarkModelChanged();
+}
+
void BookmarksHandler::PartnerShimLoaded(PartnerBookmarksShim* shim) {
BookmarkModelChanged();
}
@@ -397,7 +403,8 @@ void BookmarksHandler::OnShortcutFaviconDataAvailable(
}
TabAndroid* tab = TabAndroid::FromWebContents(web_ui()->GetWebContents());
if (tab) {
- tab->AddShortcutToBookmark(node->url(), node->GetTitle(),
+ tab->AddShortcutToBookmark(node->url(),
+ GetTitle(node),
favicon_bitmap, SkColorGetR(color),
SkColorGetG(color), SkColorGetB(color));
}
@@ -432,29 +439,60 @@ const BookmarkNode* BookmarksHandler::GetNodeByID(
if (is_managed)
return managed_bookmarks_shim_->GetNodeByID(id);
- else
- return partner_bookmarks_shim_->GetNodeByID(id, is_partner);
+
+ if (is_partner)
+ return partner_bookmarks_shim_->GetNodeByID(id);
+
+ return bookmark_model_->GetNodeByID(id);
}
const BookmarkNode* BookmarksHandler::GetParentOf(
const BookmarkNode* node) const {
- if (node == managed_bookmarks_shim_->GetManagedBookmarksRoot())
+ if (node == managed_bookmarks_shim_->GetManagedBookmarksRoot() ||
+ node == partner_bookmarks_shim_->GetPartnerBookmarksRoot()) {
return bookmark_model_->mobile_node();
- return partner_bookmarks_shim_->GetParentOf(node);
+ }
+
+ return node->parent();
+}
+
+base::string16 BookmarksHandler::GetTitle(const BookmarkNode* node) const {
+ if (partner_bookmarks_shim_->IsPartnerBookmark(node))
+ return partner_bookmarks_shim_->GetTitle(node);
+
+ return node->GetTitle();
+}
+
+bool BookmarksHandler::IsReachable(const BookmarkNode* node) const {
+ if (!partner_bookmarks_shim_->IsPartnerBookmark(node))
+ return true;
+
+ return partner_bookmarks_shim_->IsReachable(node);
}
bool BookmarksHandler::IsEditable(const BookmarkNode* node) const {
- // Reserved system nodes, partner bookmarks and managed bookmarks are not
- // editable. Additionally, bookmark editing may be completely disabled via
- // a managed preference.
+ // Reserved system nodes and managed bookmarks are not editable.
+ // Additionally, bookmark editing may be completely disabled
+ // via a managed preference.
+ if (!node ||
+ (node->type() != BookmarkNode::FOLDER &&
+ node->type() != BookmarkNode::URL)) {
+ return false;
+ }
+
const PrefService* pref = Profile::FromBrowserContext(
web_ui()->GetWebContents()->GetBrowserContext())->GetPrefs();
- return partner_bookmarks_shim_->IsBookmarkEditable(node) &&
- !managed_bookmarks_shim_->IsManagedBookmark(node) &&
- pref->GetBoolean(prefs::kEditBookmarksEnabled);
+ if (!pref->GetBoolean(prefs::kEditBookmarksEnabled))
+ return false;
+
+ if (partner_bookmarks_shim_->IsPartnerBookmark(node))
+ return true;
+
+ return !managed_bookmarks_shim_->IsManagedBookmark(node);
}
bool BookmarksHandler::IsRoot(const BookmarkNode* node) const {
- return partner_bookmarks_shim_->IsRootNode(node) &&
+ return node->is_root() &&
+ node != partner_bookmarks_shim_->GetPartnerBookmarksRoot() &&
node != managed_bookmarks_shim_->GetManagedBookmarksRoot();
}
diff --git a/chrome/browser/ui/webui/ntp/android/bookmarks_handler.h b/chrome/browser/ui/webui/ntp/android/bookmarks_handler.h
index 9c91417..d7f0278 100644
--- a/chrome/browser/ui/webui/ntp/android/bookmarks_handler.h
+++ b/chrome/browser/ui/webui/ntp/android/bookmarks_handler.h
@@ -87,6 +87,7 @@ class BookmarksHandler : public content::WebUIMessageHandler,
const BookmarkNode* node) OVERRIDE;
// Override the methods of PartnerBookmarksShim::Observer
+ virtual void PartnerShimChanged(PartnerBookmarksShim* shim) OVERRIDE;
virtual void PartnerShimLoaded(PartnerBookmarksShim* shim) OVERRIDE;
virtual void ShimBeingDeleted(PartnerBookmarksShim* shim) OVERRIDE;
@@ -152,6 +153,12 @@ class BookmarksHandler : public content::WebUIMessageHandler,
// Returns the parent of |node|, or NULL if it's the root node.
const BookmarkNode* GetParentOf(const BookmarkNode* node) const;
+ // Returns the title of |node|, possibly remapped (if a partner bookmark).
+ base::string16 GetTitle(const BookmarkNode* node) const;
+
+ // Returns true if the node is reachable.
+ bool IsReachable(const BookmarkNode* node) const;
+
// Returns true if |node| can be modified by the user.
bool IsEditable(const BookmarkNode* node) const;
diff --git a/chrome/browser/ui/webui/ntp/android/partner_bookmarks_shim.cc b/chrome/browser/ui/webui/ntp/android/partner_bookmarks_shim.cc
index 565af9f..4a227c1 100644
--- a/chrome/browser/ui/webui/ntp/android/partner_bookmarks_shim.cc
+++ b/chrome/browser/ui/webui/ntp/android/partner_bookmarks_shim.cc
@@ -5,42 +5,103 @@
#include "chrome/browser/ui/webui/ntp/android/partner_bookmarks_shim.h"
#include "base/lazy_instance.h"
+#include "base/prefs/pref_service.h"
+#include "base/values.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/pref_names.h"
+#include "components/user_prefs/pref_registry_syncable.h"
#include "content/public/browser/browser_thread.h"
-using base::LazyInstance;
using content::BrowserThread;
namespace {
-static LazyInstance<PartnerBookmarksShim> g_partner_bookmarks_shim_instance =
+// PartnerModelKeeper is used as a singleton to store an immutable hierarchy
+// of partner bookmarks. The hierarchy is retrieved from the partner bookmarks
+// provider and doesn't depend on the user profile.
+// The retrieved hierarchy persists
+// PartnerBookmarksShim is responsible to applying and storing the user changes
+// (deletions/renames) in the user profile, thus keeping the hierarchy intact.
+struct PartnerModelKeeper {
+ scoped_ptr<BookmarkNode> partner_bookmarks_root;
+ bool loaded;
+
+ PartnerModelKeeper()
+ : loaded(false) {}
+};
+
+base::LazyInstance<PartnerModelKeeper> g_partner_model_keeper =
LAZY_INSTANCE_INITIALIZER;
+const void* kPartnerBookmarksShimUserDataKey =
+ &kPartnerBookmarksShimUserDataKey;
+
+// Dictionary keys for entries in the kPartnerBookmarksMapping pref.
+static const char kMappingUrl[] = "url";
+static const char kMappingProviderTitle[] = "provider_title";
+static const char kMappingTitle[] = "mapped_title";
+
} // namespace
-PartnerBookmarksShim::PartnerBookmarksShim()
- : bookmark_model_(NULL),
- attach_point_(NULL),
- loaded_(false),
- observers_(
- ObserverList<PartnerBookmarksShim::Observer>::NOTIFY_EXISTING_ONLY) {
+// static
+PartnerBookmarksShim* PartnerBookmarksShim::BuildForBrowserContext(
+ content::BrowserContext* browser_context) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ PartnerBookmarksShim* data =
+ reinterpret_cast<PartnerBookmarksShim*>(
+ browser_context->GetUserData(kPartnerBookmarksShimUserDataKey));
+ if (data)
+ return data;
+
+ data = new PartnerBookmarksShim(
+ Profile::FromBrowserContext(browser_context)->GetPrefs());
+ browser_context->SetUserData(kPartnerBookmarksShimUserDataKey, data);
+ data->ReloadNodeMapping();
+ return data;
}
-PartnerBookmarksShim::~PartnerBookmarksShim() {
- FOR_EACH_OBSERVER(PartnerBookmarksShim::Observer, observers_,
- ShimBeingDeleted(this));
+// static
+void PartnerBookmarksShim::RegisterProfilePrefs(
+ user_prefs::PrefRegistrySyncable* registry) {
+ registry->RegisterListPref(
+ prefs::kPartnerBookmarkMappings,
+ user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
+}
+
+bool PartnerBookmarksShim::IsLoaded() const {
+ return g_partner_model_keeper.Get().loaded;
}
-PartnerBookmarksShim* PartnerBookmarksShim::GetInstance() {
- return g_partner_bookmarks_shim_instance.Pointer();
+bool PartnerBookmarksShim::HasPartnerBookmarks() const {
+ DCHECK(IsLoaded());
+ return g_partner_model_keeper.Get().partner_bookmarks_root.get() != NULL;
}
-void PartnerBookmarksShim::Reset() {
- partner_bookmarks_root_.reset();
- bookmark_model_ = NULL;
- attach_point_ = NULL;
- loaded_ = false;
- observers_.Clear();
+bool PartnerBookmarksShim::IsReachable(const BookmarkNode* node) const {
+ DCHECK(HasPartnerBookmarks());
+ DCHECK(IsPartnerBookmark(node));
+ for (const BookmarkNode* i = node; i != NULL; i = i->parent()) {
+ const NodeRenamingMapKey key(i->url(), i->GetTitle());
+ NodeRenamingMap::const_iterator remap = node_rename_remove_map_.find(key);
+ if (remap != node_rename_remove_map_.end() && remap->second.empty())
+ return false;
+ }
+ return true;
+}
+
+void PartnerBookmarksShim::RemoveBookmark(const BookmarkNode* node) {
+ RenameBookmark(node, base::string16());
+}
+
+void PartnerBookmarksShim::RenameBookmark(const BookmarkNode* node,
+ const base::string16& title) {
+ const NodeRenamingMapKey key(node->url(), node->GetTitle());
+ node_rename_remove_map_[key] = title;
+ SaveNodeMapping();
+ FOR_EACH_OBSERVER(PartnerBookmarksShim::Observer, observers_,
+ PartnerShimChanged(this));
}
void PartnerBookmarksShim::AddObserver(
@@ -53,12 +114,32 @@ void PartnerBookmarksShim::RemoveObserver(
observers_.RemoveObserver(observer);
}
-bool PartnerBookmarksShim::IsPartnerBookmark(const BookmarkNode* node) {
+const BookmarkNode* PartnerBookmarksShim::GetNodeByID(int64 id) const {
+ DCHECK(IsLoaded());
+ DCHECK(HasPartnerBookmarks());
+ if (!HasPartnerBookmarks())
+ return NULL;
+ return GetNodeByID(GetPartnerBookmarksRoot(), id);
+}
+
+base::string16 PartnerBookmarksShim::GetTitle(const BookmarkNode* node) const {
+ DCHECK(node);
+ DCHECK(IsPartnerBookmark(node));
+
+ const NodeRenamingMapKey key(node->url(), node->GetTitle());
+ NodeRenamingMap::const_iterator i = node_rename_remove_map_.find(key);
+ if (i != node_rename_remove_map_.end())
+ return i->second;
+
+ return node->GetTitle();
+}
+
+bool PartnerBookmarksShim::IsPartnerBookmark(const BookmarkNode* node) const {
DCHECK(IsLoaded());
if (!HasPartnerBookmarks())
return false;
const BookmarkNode* parent = node;
- while (parent != NULL) {
+ while (parent) {
if (parent == GetPartnerBookmarksRoot())
return true;
parent = parent->parent();
@@ -66,56 +147,52 @@ bool PartnerBookmarksShim::IsPartnerBookmark(const BookmarkNode* node) {
return false;
}
-bool PartnerBookmarksShim::IsBookmarkEditable(const BookmarkNode* node) {
- return node && !IsPartnerBookmark(node) &&
- (node->type() == BookmarkNode::FOLDER ||
- node->type() == BookmarkNode::URL);
+const BookmarkNode* PartnerBookmarksShim::GetPartnerBookmarksRoot() const {
+ return g_partner_model_keeper.Get().partner_bookmarks_root.get();
}
-void PartnerBookmarksShim::AttachTo(
- BookmarkModel* bookmark_model,
- const BookmarkNode* attach_point) {
- if (bookmark_model_ == bookmark_model && attach_point_ == attach_point)
- return;
- if (attach_point && (attach_point->type() == BookmarkNode::FOLDER ||
- attach_point->type() == BookmarkNode::URL)) {
- DCHECK(false) << "Can not attach partner bookmarks to node of type: "
- << attach_point->type();
- return;
- }
- DCHECK(!bookmark_model_ || !bookmark_model);
- DCHECK(!attach_point_ || !attach_point);
- bookmark_model_ = bookmark_model;
- attach_point_ = attach_point;
+void PartnerBookmarksShim::SetPartnerBookmarksRoot(BookmarkNode* root_node) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ g_partner_model_keeper.Get().partner_bookmarks_root.reset(root_node);
+ g_partner_model_keeper.Get().loaded = true;
+ FOR_EACH_OBSERVER(PartnerBookmarksShim::Observer, observers_,
+ PartnerShimLoaded(this));
}
-const BookmarkNode* PartnerBookmarksShim::GetParentOf(
- const BookmarkNode* node) const {
- DCHECK(IsLoaded());
- DCHECK(node != NULL);
- if (HasPartnerBookmarks() && node == GetPartnerBookmarksRoot())
- return get_attach_point();
- return node->parent();
+PartnerBookmarksShim::NodeRenamingMapKey::NodeRenamingMapKey(
+ const GURL& url, const base::string16& provider_title)
+ : url_(url), provider_title_(provider_title) {}
+
+PartnerBookmarksShim::NodeRenamingMapKey::~NodeRenamingMapKey() {}
+
+bool operator<(const PartnerBookmarksShim::NodeRenamingMapKey& a,
+ const PartnerBookmarksShim::NodeRenamingMapKey& b) {
+ return (a.url_ < b.url_) ||
+ (a.url_ == b.url_ && a.provider_title_ < b.provider_title_);
}
-bool PartnerBookmarksShim::IsRootNode(const BookmarkNode* node) const {
- DCHECK(node != NULL);
- return node->is_root()
- && (!HasPartnerBookmarks() || node != GetPartnerBookmarksRoot());
+// static
+void PartnerBookmarksShim::ClearInBrowserContextForTesting(
+ content::BrowserContext* browser_context) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ browser_context->SetUserData(kPartnerBookmarksShimUserDataKey, 0);
}
-const BookmarkNode* PartnerBookmarksShim::GetNodeByID(int64 id,
- bool is_partner) const {
- DCHECK(IsLoaded());
- if (is_partner) {
- DCHECK(HasPartnerBookmarks());
- if (!HasPartnerBookmarks())
- return NULL;
- return GetNodeByID(GetPartnerBookmarksRoot(), id);
- }
- if (bookmark_model_)
- return bookmark_model_->GetNodeByID(id);
- return NULL;
+// static
+void PartnerBookmarksShim::ClearPartnerModelForTesting() {
+ g_partner_model_keeper.Get().loaded = false;
+ g_partner_model_keeper.Get().partner_bookmarks_root.reset(0);
+}
+
+PartnerBookmarksShim::PartnerBookmarksShim(PrefService* prefs)
+ : prefs_(prefs),
+ observers_(
+ ObserverList<PartnerBookmarksShim::Observer>::NOTIFY_EXISTING_ONLY) {
+}
+
+PartnerBookmarksShim::~PartnerBookmarksShim() {
+ FOR_EACH_OBSERVER(PartnerBookmarksShim::Observer, observers_,
+ ShimBeingDeleted(this));
}
const BookmarkNode* PartnerBookmarksShim::GetNodeByID(
@@ -130,24 +207,55 @@ const BookmarkNode* PartnerBookmarksShim::GetNodeByID(
return NULL;
}
-bool PartnerBookmarksShim::IsLoaded() const {
- return loaded_;
-}
+void PartnerBookmarksShim::ReloadNodeMapping() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
-bool PartnerBookmarksShim::HasPartnerBookmarks() const {
- DCHECK(IsLoaded());
- return partner_bookmarks_root_.get() != NULL;
-}
+ node_rename_remove_map_.clear();
+ if (!prefs_)
+ return;
-const BookmarkNode* PartnerBookmarksShim::GetPartnerBookmarksRoot() const {
- DCHECK(HasPartnerBookmarks());
- return partner_bookmarks_root_.get();
+ const base::ListValue* list =
+ prefs_->GetList(prefs::kPartnerBookmarkMappings);
+ if (!list)
+ return;
+
+ for (base::ListValue::const_iterator it = list->begin();
+ it != list->end(); ++it) {
+ const base::DictionaryValue* dict = NULL;
+ if (!*it || !(*it)->GetAsDictionary(&dict)) {
+ NOTREACHED();
+ continue;
+ }
+
+ std::string url;
+ base::string16 provider_title;
+ base::string16 mapped_title;
+ if (!dict->GetString(kMappingUrl, &url) ||
+ !dict->GetString(kMappingProviderTitle, &provider_title) ||
+ !dict->GetString(kMappingTitle, &mapped_title)) {
+ NOTREACHED();
+ continue;
+ }
+
+ const NodeRenamingMapKey key(GURL(url), provider_title);
+ node_rename_remove_map_[key] = mapped_title;
+ }
}
-void PartnerBookmarksShim::SetPartnerBookmarksRoot(BookmarkNode* root_node) {
+void PartnerBookmarksShim::SaveNodeMapping() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
- partner_bookmarks_root_.reset(root_node);
- loaded_ = true;
- FOR_EACH_OBSERVER(PartnerBookmarksShim::Observer, observers_,
- PartnerShimLoaded(this));
+ if (!prefs_)
+ return;
+
+ base::ListValue list;
+ for (NodeRenamingMap::const_iterator i = node_rename_remove_map_.begin();
+ i != node_rename_remove_map_.end();
+ ++i) {
+ base::DictionaryValue* dict = new base::DictionaryValue();
+ dict->SetString(kMappingUrl, i->first.url().spec());
+ dict->SetString(kMappingProviderTitle, i->first.provider_title());
+ dict->SetString(kMappingTitle, i->second);
+ list.Append(dict);
+ }
+ prefs_->Set(prefs::kPartnerBookmarkMappings, list);
}
diff --git a/chrome/browser/ui/webui/ntp/android/partner_bookmarks_shim.h b/chrome/browser/ui/webui/ntp/android/partner_bookmarks_shim.h
index be6a7ed..f27d8cc 100644
--- a/chrome/browser/ui/webui/ntp/android/partner_bookmarks_shim.h
+++ b/chrome/browser/ui/webui/ntp/android/partner_bookmarks_shim.h
@@ -7,71 +7,114 @@
#include "base/android/jni_helper.h"
#include "base/memory/scoped_ptr.h"
+#include "base/strings/string16.h"
+#include "base/supports_user_data.h"
#include "chrome/browser/bookmarks/bookmark_model.h"
+#include "url/gurl.h"
+
+class PrefService;
+
+namespace content {
+class WebContents;
+}
+
+namespace user_prefs {
+class PrefRegistrySyncable;
+}
// A shim that lives on top of a BookmarkModel that allows the injection of
-// Partner bookmarks without submitting changes to the user configured bookmark
-// model.
-// Partner bookmarks folder is pseudo-injected as a subfolder to "attach node".
-// Because we cannot modify the BookmarkModel, the following needs to
-// be done on a client side:
-// 1. bookmark_node->is_root() -> shim->IsRootNode(bookmark_node)
-// 2. bookmark_node->parent() -> shim->GetParentOf(bookmark_node)
-// 3. bookmark_model->GetNodeByID(id) -> shim->GetNodeByID(id)
-class PartnerBookmarksShim {
+// partner bookmarks without submitting changes to the bookmark model.
+// The shim persists bookmark renames/deletions in a user profile and could be
+// queried via shim->GetTitle(node) and shim->IsReachable(node).
+// Note that node->GetTitle() returns an original (unmodified) title.
+class PartnerBookmarksShim : public base::SupportsUserData::Data {
public:
- // Constructor is public for LazyInstance; DON'T CALL; use ::GetInstance().
- PartnerBookmarksShim();
- // Destructor is public for LazyInstance;
- ~PartnerBookmarksShim();
-
- // Returns the active instance of the shim.
- static PartnerBookmarksShim* GetInstance();
-
- // Resets back to the initial state. Clears any attached observers, deletes
- // the partner bookmarks if any, and returns back to the unloaded state.
- void Reset();
-
- // Pseudo-injects partner bookmarks (if any) under the "attach_node".
- void AttachTo(BookmarkModel* bookmark_model,
- const BookmarkNode* attach_node);
- // Returns true if everything got loaded and attached
+ // Returns an instance of the shim for a given |browser_context|.
+ static PartnerBookmarksShim* BuildForBrowserContext(
+ content::BrowserContext* browser_context);
+
+ // Registers preferences.
+ static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
+
+ // Returns true if everything got loaded.
bool IsLoaded() const;
- // Returns true if there are partner bookmarks
+
+ // Returns true if there are partner bookmarks.
bool HasPartnerBookmarks() const;
- // For "Loaded" and "ShimBeingDeleted" notifications
+ // Returns true if a given bookmark is reachable (i.e. neither the bookmark,
+ // nor any of its parents were "removed").
+ bool IsReachable(const BookmarkNode* node) const;
+
+ // Removes a given bookmark.
+ // Makes the |node| (and, consequently, all its children) unreachable.
+ void RemoveBookmark(const BookmarkNode* node);
+
+ // Renames a given bookmark.
+ void RenameBookmark(const BookmarkNode* node, const base::string16& title);
+
+ // For Loaded/Changed/ShimBeingDeleted notifications
class Observer {
public:
- // Called when everything is loaded and attached
+ // Called when the set of bookmarks, or their values/visibility changes
+ virtual void PartnerShimChanged(PartnerBookmarksShim*) {}
+ // Called when everything is loaded
virtual void PartnerShimLoaded(PartnerBookmarksShim*) {}
// Called just before everything got destroyed
virtual void ShimBeingDeleted(PartnerBookmarksShim*) {}
protected:
virtual ~Observer() {}
};
+
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
- // Replacements for BookmarkModel/BookmarkNode methods
- bool IsBookmarkEditable(const BookmarkNode* node);
- bool IsRootNode(const BookmarkNode* node) const;
- const BookmarkNode* GetNodeByID(int64 id, bool is_partner) const;
- const BookmarkNode* GetParentOf(const BookmarkNode* node) const;
- const BookmarkNode* get_attach_point() const { return attach_point_; }
- bool IsPartnerBookmark(const BookmarkNode* node);
+ // PartnerBookmarksShim versions of BookmarkModel/BookmarkNode methods
+ const BookmarkNode* GetNodeByID(int64 id) const;
+ base::string16 GetTitle(const BookmarkNode* node) const;
+
+ bool IsPartnerBookmark(const BookmarkNode* node) const;
const BookmarkNode* GetPartnerBookmarksRoot() const;
+
// Sets the root node of the partner bookmarks and notifies any observers that
// the shim has now been loaded. Takes ownership of |root_node|.
void SetPartnerBookmarksRoot(BookmarkNode* root_node);
+ // Used as a "unique" identifier of the partner bookmark node for the purposes
+ // of node deletion and title editing. Two bookmarks with the same URLs and
+ // titles are considered indistinguishable.
+ class NodeRenamingMapKey {
+ public:
+ NodeRenamingMapKey(const GURL& url, const base::string16& provider_title);
+ ~NodeRenamingMapKey();
+ const GURL& url() const { return url_; }
+ const base::string16& provider_title() const { return provider_title_; }
+ friend bool operator<(const NodeRenamingMapKey& a,
+ const NodeRenamingMapKey& b);
+ private:
+ GURL url_;
+ base::string16 provider_title_;
+ };
+ typedef std::map<NodeRenamingMapKey, base::string16> NodeRenamingMap;
+
+ // For testing: clears an instance of the shim in a given |browser_context|.
+ static void ClearInBrowserContextForTesting(
+ content::BrowserContext* browser_context);
+
+ // For testing: clears partner bookmark model data.
+ static void ClearPartnerModelForTesting();
+
private:
+ explicit PartnerBookmarksShim(PrefService* prefs);
+ virtual ~PartnerBookmarksShim();
+
const BookmarkNode* GetNodeByID(const BookmarkNode* parent, int64 id) const;
+ void ReloadNodeMapping();
+ void SaveNodeMapping();
scoped_ptr<BookmarkNode> partner_bookmarks_root_;
- BookmarkModel* bookmark_model_;
- const BookmarkNode* attach_point_;
- bool loaded_; // Set only on UI thread
+ PrefService* prefs_;
+ NodeRenamingMap node_rename_remove_map_;
// The observers.
ObserverList<Observer> observers_;
diff --git a/chrome/browser/ui/webui/ntp/android/partner_bookmarks_shim_unittest.cc b/chrome/browser/ui/webui/ntp/android/partner_bookmarks_shim_unittest.cc
index a0e5737..986e595 100644
--- a/chrome/browser/ui/webui/ntp/android/partner_bookmarks_shim_unittest.cc
+++ b/chrome/browser/ui/webui/ntp/android/partner_bookmarks_shim_unittest.cc
@@ -13,9 +13,22 @@
#include "chrome/test/base/testing_profile.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/test/test_browser_thread.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
+using testing::_;
+
+class MockObserver : public PartnerBookmarksShim::Observer {
+ public:
+ MockObserver() {}
+ MOCK_METHOD1(PartnerShimChanged, void(PartnerBookmarksShim*));
+ MOCK_METHOD1(PartnerShimLoaded, void(PartnerBookmarksShim*));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockObserver);
+};
+
class PartnerBookmarksShimTest : public testing::Test {
public:
PartnerBookmarksShimTest()
@@ -25,17 +38,20 @@ class PartnerBookmarksShimTest : public testing::Test {
}
TestingProfile* profile() const { return profile_.get(); }
+ PartnerBookmarksShim* partner_bookmarks_shim() const {
+ return PartnerBookmarksShim::BuildForBrowserContext(profile_.get());
+ }
- const BookmarkNode* AddBookmark(const BookmarkNode* parent,
- const GURL& url,
- const string16& title) {
+ const BookmarkNode* AddBookmark(const BookmarkNode* parent,
+ const GURL& url,
+ const string16& title) {
if (!parent)
parent = model_->bookmark_bar_node();
return model_->AddURL(parent, parent->child_count(), title, url);
}
- const BookmarkNode* AddFolder(const BookmarkNode* parent,
- const string16& title) {
+ const BookmarkNode* AddFolder(const BookmarkNode* parent,
+ const string16& title) {
if (!parent)
parent = model_->bookmark_bar_node();
return model_->AddFolder(parent, parent->child_count(), title);
@@ -52,8 +68,9 @@ class PartnerBookmarksShimTest : public testing::Test {
}
virtual void TearDown() OVERRIDE {
+ PartnerBookmarksShim::ClearInBrowserContextForTesting(profile_.get());
+ PartnerBookmarksShim::ClearPartnerModelForTesting();
profile_.reset(NULL);
- PartnerBookmarksShim::GetInstance()->Reset();
}
scoped_ptr<TestingProfile> profile_;
@@ -63,47 +80,12 @@ class PartnerBookmarksShimTest : public testing::Test {
content::TestBrowserThread file_thread_;
BookmarkModel* model_;
+ MockObserver observer_;
DISALLOW_COPY_AND_ASSIGN(PartnerBookmarksShimTest);
};
-class TestObserver : public PartnerBookmarksShim::Observer {
- public:
- TestObserver()
- : notified_of_load_(false) {
- }
-
- // Called when everything is loaded and attached
- virtual void PartnerShimLoaded(PartnerBookmarksShim*) OVERRIDE {
- notified_of_load_ = true;
- }
-
- bool IsNotifiedOfLoad() { return notified_of_load_; }
-
- private:
- bool notified_of_load_;
-
- DISALLOW_COPY_AND_ASSIGN(TestObserver);
-};
-
TEST_F(PartnerBookmarksShimTest, GetNodeByID) {
- // Add a bookmark.
- GURL bookmark_url("http://www.google.com/");
- AddBookmark(
- NULL,
- bookmark_url,
- ASCIIToUTF16("bar"));
- const BookmarkNode* test_folder1 = AddFolder(NULL,
- ASCIIToUTF16("test_folder1"));
- const BookmarkNode* test_folder2 = AddFolder(test_folder1,
- ASCIIToUTF16("test_folder2"));
- const BookmarkNode* model_bookmark1 = AddBookmark(test_folder2,
- GURL("http://www.test.com"),
- ASCIIToUTF16("bar"));
- const BookmarkNode* model_bookmark2 = AddBookmark(test_folder2,
- GURL("http://www.foo.com"),
- ASCIIToUTF16("baz"));
-
BookmarkNode* root_partner_node = new BookmarkPermanentNode(0);
BookmarkNode* partner_folder1 = new BookmarkNode(1, GURL());
partner_folder1->set_type(BookmarkNode::FOLDER);
@@ -123,30 +105,28 @@ TEST_F(PartnerBookmarksShimTest, GetNodeByID) {
partner_bookmark2->set_type(BookmarkNode::URL);
partner_folder2->Add(partner_bookmark2, partner_folder2->child_count());
- PartnerBookmarksShim* shim = PartnerBookmarksShim::GetInstance();
+ PartnerBookmarksShim* shim = partner_bookmarks_shim();
ASSERT_FALSE(shim->IsLoaded());
- shim->AttachTo(model_, model_->mobile_node());
shim->SetPartnerBookmarksRoot(root_partner_node);
ASSERT_TRUE(shim->IsLoaded());
- ASSERT_EQ(shim->GetNodeByID(model_bookmark1->id(), false), model_bookmark1);
- ASSERT_EQ(shim->GetNodeByID(model_bookmark2->id(), false), model_bookmark2);
- ASSERT_EQ(shim->GetNodeByID(test_folder2->id(), false), test_folder2);
- ASSERT_EQ(shim->GetNodeByID(0, true), root_partner_node);
- ASSERT_EQ(shim->GetNodeByID(1, true), partner_folder1);
- ASSERT_EQ(shim->GetNodeByID(4, true), partner_bookmark2);
+ ASSERT_TRUE(shim->IsPartnerBookmark(root_partner_node));
+ ASSERT_EQ(shim->GetNodeByID(0), root_partner_node);
+ ASSERT_EQ(shim->GetNodeByID(1), partner_folder1);
+ ASSERT_EQ(shim->GetNodeByID(4), partner_bookmark2);
}
TEST_F(PartnerBookmarksShimTest, ObserverNotifiedOfLoadNoPartnerBookmarks) {
- TestObserver* observer = new TestObserver();
- PartnerBookmarksShim* shim = PartnerBookmarksShim::GetInstance();
- shim->AddObserver(observer);
- ASSERT_FALSE(observer->IsNotifiedOfLoad());
+ EXPECT_CALL(observer_, PartnerShimLoaded(_)).Times(0);
+ PartnerBookmarksShim* shim = partner_bookmarks_shim();
+ shim->AddObserver(&observer_);
+
+ EXPECT_CALL(observer_, PartnerShimLoaded(shim)).Times(1);
shim->SetPartnerBookmarksRoot(NULL);
- ASSERT_TRUE(observer->IsNotifiedOfLoad());
}
TEST_F(PartnerBookmarksShimTest, ObserverNotifiedOfLoadWithPartnerBookmarks) {
+ EXPECT_CALL(observer_, PartnerShimLoaded(_)).Times(0);
int64 id = 5;
BookmarkNode* root_partner_node = new BookmarkPermanentNode(id++);
BookmarkNode* partner_bookmark1 = new BookmarkNode(id++,
@@ -154,11 +134,240 @@ TEST_F(PartnerBookmarksShimTest, ObserverNotifiedOfLoadWithPartnerBookmarks) {
partner_bookmark1->set_type(BookmarkNode::URL);
root_partner_node->Add(partner_bookmark1, root_partner_node->child_count());
- TestObserver* observer = new TestObserver();
- PartnerBookmarksShim* shim = PartnerBookmarksShim::GetInstance();
- shim->AddObserver(observer);
- shim->AttachTo(model_, model_->bookmark_bar_node());
- ASSERT_FALSE(observer->IsNotifiedOfLoad());
+ PartnerBookmarksShim* shim = partner_bookmarks_shim();
+ shim->AddObserver(&observer_);
+
+ EXPECT_CALL(observer_, PartnerShimLoaded(shim)).Times(1);
+ shim->SetPartnerBookmarksRoot(root_partner_node);
+}
+
+TEST_F(PartnerBookmarksShimTest, RemoveBookmarks) {
+ PartnerBookmarksShim* shim = partner_bookmarks_shim();
+ shim->AddObserver(&observer_);
+
+ EXPECT_CALL(observer_, PartnerShimLoaded(shim)).Times(0);
+ EXPECT_CALL(observer_, PartnerShimChanged(shim)).Times(0);
+
+ BookmarkNode* root_partner_node = new BookmarkPermanentNode(0);
+ root_partner_node->SetTitle(ASCIIToUTF16("Partner bookmarks"));
+
+ BookmarkNode* partner_folder1 = new BookmarkNode(1, GURL("http://www.a.net"));
+ partner_folder1->set_type(BookmarkNode::FOLDER);
+ root_partner_node->Add(partner_folder1, root_partner_node->child_count());
+
+ BookmarkNode* partner_folder2 = new BookmarkNode(2, GURL("http://www.b.net"));
+ partner_folder2->set_type(BookmarkNode::FOLDER);
+ root_partner_node->Add(partner_folder2, root_partner_node->child_count());
+
+ BookmarkNode* partner_bookmark1 = new BookmarkNode(3,
+ GURL("http://www.a.com"));
+ partner_bookmark1->set_type(BookmarkNode::URL);
+ partner_folder1->Add(partner_bookmark1, partner_folder1->child_count());
+
+ BookmarkNode* partner_bookmark2 = new BookmarkNode(4,
+ GURL("http://www.b.com"));
+ partner_bookmark2->set_type(BookmarkNode::URL);
+ partner_folder2->Add(partner_bookmark2, partner_folder2->child_count());
+
+ BookmarkNode* partner_folder3 = new BookmarkNode(5, GURL("http://www.c.net"));
+ partner_folder3->set_type(BookmarkNode::FOLDER);
+ partner_folder2->Add(partner_folder3, partner_folder2->child_count());
+
+ BookmarkNode* partner_bookmark3 = new BookmarkNode(6,
+ GURL("http://www.c.com"));
+ partner_bookmark3->set_type(BookmarkNode::URL);
+ partner_folder3->Add(partner_bookmark3, partner_folder3->child_count());
+
+ ASSERT_FALSE(shim->IsLoaded());
+ EXPECT_CALL(observer_, PartnerShimLoaded(shim)).Times(1);
shim->SetPartnerBookmarksRoot(root_partner_node);
- ASSERT_TRUE(observer->IsNotifiedOfLoad());
+ ASSERT_TRUE(shim->IsLoaded());
+
+ EXPECT_EQ(root_partner_node, shim->GetNodeByID(0));
+ EXPECT_EQ(partner_folder1, shim->GetNodeByID(1));
+ EXPECT_EQ(partner_folder2, shim->GetNodeByID(2));
+ EXPECT_EQ(partner_bookmark1, shim->GetNodeByID(3));
+ EXPECT_EQ(partner_bookmark2, shim->GetNodeByID(4));
+ EXPECT_EQ(partner_folder3, shim->GetNodeByID(5));
+ EXPECT_EQ(partner_bookmark3, shim->GetNodeByID(6));
+
+ EXPECT_TRUE(shim->IsReachable(root_partner_node));
+ EXPECT_TRUE(shim->IsReachable(partner_folder1));
+ EXPECT_TRUE(shim->IsReachable(partner_folder2));
+ EXPECT_TRUE(shim->IsReachable(partner_bookmark1));
+ EXPECT_TRUE(shim->IsReachable(partner_bookmark2));
+ EXPECT_TRUE(shim->IsReachable(partner_folder3));
+ EXPECT_TRUE(shim->IsReachable(partner_bookmark3));
+
+ EXPECT_CALL(observer_, PartnerShimChanged(shim)).Times(1);
+ shim->RemoveBookmark(partner_bookmark2);
+ EXPECT_TRUE(shim->IsReachable(root_partner_node));
+ EXPECT_TRUE(shim->IsReachable(partner_folder1));
+ EXPECT_TRUE(shim->IsReachable(partner_folder2));
+ EXPECT_TRUE(shim->IsReachable(partner_bookmark1));
+ EXPECT_FALSE(shim->IsReachable(partner_bookmark2));
+ EXPECT_TRUE(shim->IsReachable(partner_folder3));
+ EXPECT_TRUE(shim->IsReachable(partner_bookmark3));
+
+ EXPECT_CALL(observer_, PartnerShimChanged(shim)).Times(1);
+ shim->RemoveBookmark(partner_folder1);
+ EXPECT_TRUE(shim->IsReachable(root_partner_node));
+ EXPECT_FALSE(shim->IsReachable(partner_folder1));
+ EXPECT_TRUE(shim->IsReachable(partner_folder2));
+ EXPECT_FALSE(shim->IsReachable(partner_bookmark1));
+ EXPECT_FALSE(shim->IsReachable(partner_bookmark2));
+ EXPECT_TRUE(shim->IsReachable(partner_folder3));
+ EXPECT_TRUE(shim->IsReachable(partner_bookmark3));
+
+ EXPECT_CALL(observer_, PartnerShimChanged(shim)).Times(1);
+ shim->RemoveBookmark(root_partner_node);
+ EXPECT_FALSE(shim->IsReachable(root_partner_node));
+ EXPECT_FALSE(shim->IsReachable(partner_folder1));
+ EXPECT_FALSE(shim->IsReachable(partner_folder2));
+ EXPECT_FALSE(shim->IsReachable(partner_bookmark1));
+ EXPECT_FALSE(shim->IsReachable(partner_bookmark2));
+ EXPECT_FALSE(shim->IsReachable(partner_folder3));
+ EXPECT_FALSE(shim->IsReachable(partner_bookmark3));
+}
+
+TEST_F(PartnerBookmarksShimTest, RenameBookmarks) {
+ PartnerBookmarksShim* shim = partner_bookmarks_shim();
+ shim->AddObserver(&observer_);
+
+ EXPECT_CALL(observer_, PartnerShimLoaded(shim)).Times(0);
+ EXPECT_CALL(observer_, PartnerShimChanged(shim)).Times(0);
+
+ BookmarkNode* root_partner_node = new BookmarkPermanentNode(0);
+ root_partner_node->SetTitle(ASCIIToUTF16("Partner bookmarks"));
+
+ BookmarkNode* partner_folder1 = new BookmarkNode(1, GURL("http://www.a.net"));
+ partner_folder1->set_type(BookmarkNode::FOLDER);
+ partner_folder1->SetTitle(ASCIIToUTF16("a.net"));
+ root_partner_node->Add(partner_folder1, root_partner_node->child_count());
+
+ BookmarkNode* partner_folder2 = new BookmarkNode(2, GURL("http://www.b.net"));
+ partner_folder2->set_type(BookmarkNode::FOLDER);
+ partner_folder2->SetTitle(ASCIIToUTF16("b.net"));
+ root_partner_node->Add(partner_folder2, root_partner_node->child_count());
+
+ BookmarkNode* partner_bookmark1 = new BookmarkNode(3,
+ GURL("http://www.a.com"));
+ partner_bookmark1->set_type(BookmarkNode::URL);
+ partner_bookmark1->SetTitle(ASCIIToUTF16("a.com"));
+ partner_folder1->Add(partner_bookmark1, partner_folder1->child_count());
+
+ BookmarkNode* partner_bookmark2 = new BookmarkNode(4,
+ GURL("http://www.b.com"));
+ partner_bookmark2->set_type(BookmarkNode::URL);
+ partner_bookmark2->SetTitle(ASCIIToUTF16("b.com"));
+ partner_folder2->Add(partner_bookmark2, partner_folder2->child_count());
+
+ ASSERT_FALSE(shim->IsLoaded());
+ EXPECT_CALL(observer_, PartnerShimLoaded(shim)).Times(1);
+ shim->SetPartnerBookmarksRoot(root_partner_node);
+ ASSERT_TRUE(shim->IsLoaded());
+
+ EXPECT_EQ(root_partner_node, shim->GetNodeByID(0));
+ EXPECT_EQ(partner_folder1, shim->GetNodeByID(1));
+ EXPECT_EQ(partner_folder2, shim->GetNodeByID(2));
+ EXPECT_EQ(partner_bookmark1, shim->GetNodeByID(3));
+ EXPECT_EQ(partner_bookmark2, shim->GetNodeByID(4));
+
+ EXPECT_TRUE(shim->IsReachable(root_partner_node));
+ EXPECT_TRUE(shim->IsReachable(partner_folder1));
+ EXPECT_TRUE(shim->IsReachable(partner_folder2));
+ EXPECT_TRUE(shim->IsReachable(partner_bookmark1));
+ EXPECT_TRUE(shim->IsReachable(partner_bookmark2));
+
+ EXPECT_CALL(observer_, PartnerShimChanged(shim)).Times(1);
+ EXPECT_EQ(ASCIIToUTF16("b.com"), shim->GetTitle(partner_bookmark2));
+ shim->RenameBookmark(partner_bookmark2, ASCIIToUTF16("b2.com"));
+ EXPECT_EQ(ASCIIToUTF16("b2.com"), shim->GetTitle(partner_bookmark2));
+
+ EXPECT_TRUE(shim->IsReachable(root_partner_node));
+ EXPECT_TRUE(shim->IsReachable(partner_folder1));
+ EXPECT_TRUE(shim->IsReachable(partner_folder2));
+ EXPECT_TRUE(shim->IsReachable(partner_bookmark1));
+ EXPECT_TRUE(shim->IsReachable(partner_bookmark2));
+
+ EXPECT_CALL(observer_, PartnerShimChanged(shim)).Times(1);
+ EXPECT_EQ(ASCIIToUTF16("a.net"), shim->GetTitle(partner_folder1));
+ shim->RenameBookmark(partner_folder1, ASCIIToUTF16("a2.net"));
+ EXPECT_EQ(ASCIIToUTF16("a2.net"), shim->GetTitle(partner_folder1));
+
+ EXPECT_TRUE(shim->IsReachable(root_partner_node));
+ EXPECT_TRUE(shim->IsReachable(partner_folder1));
+ EXPECT_TRUE(shim->IsReachable(partner_folder2));
+ EXPECT_TRUE(shim->IsReachable(partner_bookmark1));
+ EXPECT_TRUE(shim->IsReachable(partner_bookmark2));
+
+ EXPECT_CALL(observer_, PartnerShimChanged(shim)).Times(1);
+ EXPECT_EQ(ASCIIToUTF16("Partner bookmarks"),
+ shim->GetTitle(root_partner_node));
+ shim->RenameBookmark(root_partner_node, ASCIIToUTF16("Partner"));
+ EXPECT_EQ(ASCIIToUTF16("Partner"), shim->GetTitle(root_partner_node));
+
+ EXPECT_TRUE(shim->IsReachable(root_partner_node));
+ EXPECT_TRUE(shim->IsReachable(partner_folder1));
+ EXPECT_TRUE(shim->IsReachable(partner_folder2));
+ EXPECT_TRUE(shim->IsReachable(partner_bookmark1));
+ EXPECT_TRUE(shim->IsReachable(partner_bookmark2));
+}
+
+TEST_F(PartnerBookmarksShimTest, SaveLoadProfile) {
+ {
+ PartnerBookmarksShim* shim = partner_bookmarks_shim();
+ shim->AddObserver(&observer_);
+
+ EXPECT_CALL(observer_, PartnerShimLoaded(shim)).Times(0);
+ EXPECT_CALL(observer_, PartnerShimChanged(shim)).Times(0);
+
+ BookmarkNode* root_partner_node = new BookmarkPermanentNode(0);
+ root_partner_node->SetTitle(ASCIIToUTF16("Partner bookmarks"));
+
+ BookmarkNode* partner_folder1 = new BookmarkNode(1, GURL("http://a.net"));
+ partner_folder1->set_type(BookmarkNode::FOLDER);
+ partner_folder1->SetTitle(ASCIIToUTF16("a.net"));
+ root_partner_node->Add(partner_folder1, root_partner_node->child_count());
+
+ BookmarkNode* partner_bookmark1 = new BookmarkNode(3,
+ GURL("http://a.com"));
+ partner_bookmark1->set_type(BookmarkNode::URL);
+ partner_bookmark1->SetTitle(ASCIIToUTF16("a.com"));
+ partner_folder1->Add(partner_bookmark1, partner_folder1->child_count());
+
+ BookmarkNode* partner_bookmark2 = new BookmarkNode(5,
+ GURL("http://b.com"));
+ partner_bookmark2->set_type(BookmarkNode::URL);
+ partner_bookmark2->SetTitle(ASCIIToUTF16("b.com"));
+ partner_folder1->Add(partner_bookmark2, partner_folder1->child_count());
+
+ ASSERT_FALSE(shim->IsLoaded());
+ EXPECT_CALL(observer_, PartnerShimLoaded(shim)).Times(1);
+ shim->SetPartnerBookmarksRoot(root_partner_node);
+ ASSERT_TRUE(shim->IsLoaded());
+
+ EXPECT_CALL(observer_, PartnerShimChanged(shim)).Times(2);
+ shim->RenameBookmark(partner_bookmark1, ASCIIToUTF16("a2.com"));
+ shim->RemoveBookmark(partner_bookmark2);
+ EXPECT_EQ(ASCIIToUTF16("a2.com"), shim->GetTitle(partner_bookmark1));
+ EXPECT_FALSE(shim->IsReachable(partner_bookmark2));
+ }
+
+ PartnerBookmarksShim::ClearInBrowserContextForTesting(profile_.get());
+
+ {
+ PartnerBookmarksShim* shim = partner_bookmarks_shim();
+ shim->AddObserver(&observer_);
+
+ EXPECT_CALL(observer_, PartnerShimLoaded(shim)).Times(0);
+ EXPECT_CALL(observer_, PartnerShimChanged(shim)).Times(0);
+ ASSERT_TRUE(shim->IsLoaded());
+
+ const BookmarkNode* partner_bookmark1 = shim->GetNodeByID(3);
+ const BookmarkNode* partner_bookmark2 = shim->GetNodeByID(5);
+
+ EXPECT_EQ(ASCIIToUTF16("a2.com"), shim->GetTitle(partner_bookmark1));
+ EXPECT_FALSE(shim->IsReachable(partner_bookmark2));
+ }
}
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index a4e95ca..924d731 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -507,7 +507,7 @@ const char kUrlWhitelist[] = "policy.url_whitelist";
const char kLastPolicyCheckTime[] = "policy.last_policy_check_time";
// A list of bookmarks to include in a Managed Bookmarks root node. Each
-// list item is a dictionary containig a "name" and an "url" entry, detailing
+// list item is a dictionary containing a "name" and an "url" entry, detailing
// the bookmark name and target URL respectively.
const char kManagedBookmarks[] = "policy.managed_bookmarks";
#endif
@@ -2590,4 +2590,13 @@ const char kProfilePreferenceHashes[] = "profile.preference_hashes";
// network time tracker when browser starts.
const char kNetworkTimeMapping[] = "profile.network_time_mapping";
+#if defined(OS_ANDROID)
+// A list of partner bookmark rename/remove mappings.
+// Each list item is a dictionary containing a "url", a "provider_title" and
+// "mapped_title" entries, detailing the bookmark target URL (if any), the title
+// given by the PartnerBookmarksProvider and either the user-visible renamed
+// title or an empty string if the bookmark node was removed.
+const char kPartnerBookmarkMappings[] = "partnerbookmarks.mappings";
+#endif
+
} // namespace prefs
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 4a4bc05..59d82f0 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -926,6 +926,10 @@ extern const char kProfilePreferenceHashes[];
extern const char kNetworkTimeMapping[];
+#if defined(OS_ANDROID)
+extern const char kPartnerBookmarkMappings[];
+#endif
+
} // namespace prefs
#endif // CHROME_COMMON_PREF_NAMES_H_