diff options
author | aruslan@chromium.org <aruslan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-11-01 00:09:59 +0000 |
---|---|---|
committer | aruslan@chromium.org <aruslan@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-11-01 00:09:59 +0000 |
commit | 084f82bdeef5f754cc9e52155168fad902649ac9 (patch) | |
tree | 0bab992041e713af7fe12cacdafc3fada75d12b8 | |
parent | 1403cbaadcad3593b0dd397dc9136fb4dcff8398 (diff) | |
download | chromium_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.cc | 5 | ||||
-rw-r--r-- | chrome/android/testshell/testshell_tab.h | 5 | ||||
-rw-r--r-- | chrome/browser/android/tab_android.h | 5 | ||||
-rw-r--r-- | chrome/browser/prefs/browser_prefs.cc | 2 | ||||
-rw-r--r-- | chrome/browser/ui/webui/ntp/android/bookmarks_handler.cc | 118 | ||||
-rw-r--r-- | chrome/browser/ui/webui/ntp/android/bookmarks_handler.h | 7 | ||||
-rw-r--r-- | chrome/browser/ui/webui/ntp/android/partner_bookmarks_shim.cc | 264 | ||||
-rw-r--r-- | chrome/browser/ui/webui/ntp/android/partner_bookmarks_shim.h | 119 | ||||
-rw-r--r-- | chrome/browser/ui/webui/ntp/android/partner_bookmarks_shim_unittest.cc | 331 | ||||
-rw-r--r-- | chrome/common/pref_names.cc | 11 | ||||
-rw-r--r-- | chrome/common/pref_names.h | 4 |
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_ |