chrome_bookmark_client.cc revision 116680a4aac90f2aa7413d9095a592090648e557
1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/bookmarks/chrome_bookmark_client.h" 6 7#include "base/bind.h" 8#include "base/bind_helpers.h" 9#include "base/logging.h" 10#include "base/values.h" 11#include "chrome/browser/chrome_notification_types.h" 12#include "chrome/browser/favicon/favicon_changed_details.h" 13#include "chrome/browser/favicon/favicon_service.h" 14#include "chrome/browser/favicon/favicon_service_factory.h" 15#include "chrome/browser/history/history_service.h" 16#include "chrome/browser/history/history_service_factory.h" 17#include "chrome/browser/policy/profile_policy_connector.h" 18#include "chrome/browser/policy/profile_policy_connector_factory.h" 19#include "chrome/browser/profiles/profile.h" 20#include "components/bookmarks/browser/bookmark_model.h" 21#include "components/bookmarks/browser/bookmark_node.h" 22#include "components/history/core/browser/url_database.h" 23#include "content/public/browser/browser_thread.h" 24#include "content/public/browser/notification_details.h" 25#include "content/public/browser/notification_source.h" 26#include "content/public/browser/user_metrics.h" 27#include "grit/components_strings.h" 28#include "policy/policy_constants.h" 29#include "ui/base/l10n/l10n_util.h" 30 31namespace { 32 33void NotifyHistoryOfRemovedURLs(Profile* profile, 34 const std::set<GURL>& removed_urls) { 35 HistoryService* history_service = 36 HistoryServiceFactory::GetForProfile(profile, Profile::EXPLICIT_ACCESS); 37 if (history_service) 38 history_service->URLsNoLongerBookmarked(removed_urls); 39} 40 41void RunCallbackWithImage( 42 const favicon_base::FaviconImageCallback& callback, 43 const favicon_base::FaviconRawBitmapResult& bitmap_result) { 44 favicon_base::FaviconImageResult result; 45 if (bitmap_result.is_valid()) { 46 result.image = gfx::Image::CreateFrom1xPNGBytes( 47 bitmap_result.bitmap_data->front(), bitmap_result.bitmap_data->size()); 48 result.icon_url = bitmap_result.icon_url; 49 callback.Run(result); 50 return; 51 } 52 callback.Run(result); 53} 54 55} // namespace 56 57ChromeBookmarkClient::ChromeBookmarkClient(Profile* profile) 58 : profile_(profile), model_(NULL), managed_node_(NULL) { 59} 60 61ChromeBookmarkClient::~ChromeBookmarkClient() { 62} 63 64void ChromeBookmarkClient::Init(BookmarkModel* model) { 65 DCHECK(model); 66 DCHECK(!model_); 67 model_ = model; 68 model_->AddObserver(this); 69 70 managed_bookmarks_tracker_.reset(new policy::ManagedBookmarksTracker( 71 model_, 72 profile_->GetPrefs(), 73 base::Bind(&ChromeBookmarkClient::GetManagedBookmarksDomain, 74 base::Unretained(this)))); 75 76 // Listen for changes to favicons so that we can update the favicon of the 77 // node appropriately. 78 registrar_.Add(this, 79 chrome::NOTIFICATION_FAVICON_CHANGED, 80 content::Source<Profile>(profile_)); 81} 82 83void ChromeBookmarkClient::Shutdown() { 84 if (model_) { 85 registrar_.RemoveAll(); 86 87 model_->RemoveObserver(this); 88 model_ = NULL; 89 } 90 BookmarkClient::Shutdown(); 91} 92 93bool ChromeBookmarkClient::IsDescendantOfManagedNode(const BookmarkNode* node) { 94 return node && node->HasAncestor(managed_node_); 95} 96 97bool ChromeBookmarkClient::HasDescendantsOfManagedNode( 98 const std::vector<const BookmarkNode*>& list) { 99 for (size_t i = 0; i < list.size(); ++i) { 100 if (IsDescendantOfManagedNode(list[i])) 101 return true; 102 } 103 return false; 104} 105 106bool ChromeBookmarkClient::PreferTouchIcon() { 107#if !defined(OS_IOS) 108 return false; 109#else 110 return true; 111#endif 112} 113 114base::CancelableTaskTracker::TaskId 115ChromeBookmarkClient::GetFaviconImageForPageURL( 116 const GURL& page_url, 117 favicon_base::IconType type, 118 const favicon_base::FaviconImageCallback& callback, 119 base::CancelableTaskTracker* tracker) { 120 FaviconService* favicon_service = 121 FaviconServiceFactory::GetForProfile(profile_, Profile::EXPLICIT_ACCESS); 122 if (!favicon_service) 123 return base::CancelableTaskTracker::kBadTaskId; 124 if (type == favicon_base::FAVICON) { 125 return favicon_service->GetFaviconImageForPageURL( 126 page_url, callback, tracker); 127 } else { 128 return favicon_service->GetRawFaviconForPageURL( 129 page_url, 130 type, 131 0, 132 base::Bind(&RunCallbackWithImage, callback), 133 tracker); 134 } 135} 136 137bool ChromeBookmarkClient::SupportsTypedCountForNodes() { 138 return true; 139} 140 141void ChromeBookmarkClient::GetTypedCountForNodes( 142 const NodeSet& nodes, 143 NodeTypedCountPairs* node_typed_count_pairs) { 144 HistoryService* history_service = 145 HistoryServiceFactory::GetForProfile(profile_, Profile::EXPLICIT_ACCESS); 146 history::URLDatabase* url_db = 147 history_service ? history_service->InMemoryDatabase() : NULL; 148 for (NodeSet::const_iterator i = nodes.begin(); i != nodes.end(); ++i) { 149 int typed_count = 0; 150 151 // If |url_db| is the InMemoryDatabase, it might not cache all URLRows, but 152 // it guarantees to contain those with |typed_count| > 0. Thus, if we cannot 153 // fetch the URLRow, it is safe to assume that its |typed_count| is 0. 154 history::URLRow url; 155 if (url_db && url_db->GetRowForURL((*i)->url(), &url)) 156 typed_count = url.typed_count(); 157 158 NodeTypedCountPair pair(*i, typed_count); 159 node_typed_count_pairs->push_back(pair); 160 } 161} 162 163bool ChromeBookmarkClient::IsPermanentNodeVisible( 164 const BookmarkPermanentNode* node) { 165 DCHECK(node->type() == BookmarkNode::BOOKMARK_BAR || 166 node->type() == BookmarkNode::OTHER_NODE || 167 node->type() == BookmarkNode::MOBILE || 168 node == managed_node_); 169 if (node == managed_node_) 170 return false; 171#if !defined(OS_IOS) 172 return node->type() != BookmarkNode::MOBILE; 173#else 174 return node->type() == BookmarkNode::MOBILE; 175#endif 176} 177 178void ChromeBookmarkClient::RecordAction(const base::UserMetricsAction& action) { 179 content::RecordAction(action); 180} 181 182bookmarks::LoadExtraCallback ChromeBookmarkClient::GetLoadExtraNodesCallback() { 183 // Create the managed_node now; it will be populated in the LoadExtraNodes 184 // callback. 185 // The ownership of managed_node_ is in limbo until LoadExtraNodes runs, 186 // so we leave it in the care of the closure meanwhile. 187 scoped_ptr<BookmarkPermanentNode> managed(new BookmarkPermanentNode(0)); 188 managed_node_ = managed.get(); 189 190 return base::Bind( 191 &ChromeBookmarkClient::LoadExtraNodes, 192 base::Passed(&managed), 193 base::Passed(managed_bookmarks_tracker_->GetInitialManagedBookmarks())); 194} 195 196bool ChromeBookmarkClient::CanSetPermanentNodeTitle( 197 const BookmarkNode* permanent_node) { 198 // The |managed_node_| can have its title updated if the user signs in or 199 // out. 200 return !IsDescendantOfManagedNode(permanent_node) || 201 permanent_node == managed_node_; 202} 203 204bool ChromeBookmarkClient::CanSyncNode(const BookmarkNode* node) { 205 return !IsDescendantOfManagedNode(node); 206} 207 208bool ChromeBookmarkClient::CanBeEditedByUser(const BookmarkNode* node) { 209 return !IsDescendantOfManagedNode(node); 210} 211 212void ChromeBookmarkClient::Observe( 213 int type, 214 const content::NotificationSource& source, 215 const content::NotificationDetails& details) { 216 switch (type) { 217 case chrome::NOTIFICATION_FAVICON_CHANGED: { 218 content::Details<FaviconChangedDetails> favicon_details(details); 219 model_->OnFaviconChanged(favicon_details->urls); 220 break; 221 } 222 223 default: 224 NOTREACHED(); 225 break; 226 } 227} 228 229void ChromeBookmarkClient::BookmarkModelChanged() { 230} 231 232void ChromeBookmarkClient::BookmarkNodeRemoved( 233 BookmarkModel* model, 234 const BookmarkNode* parent, 235 int old_index, 236 const BookmarkNode* node, 237 const std::set<GURL>& removed_urls) { 238 NotifyHistoryOfRemovedURLs(profile_, removed_urls); 239} 240 241void ChromeBookmarkClient::BookmarkAllUserNodesRemoved( 242 BookmarkModel* model, 243 const std::set<GURL>& removed_urls) { 244 NotifyHistoryOfRemovedURLs(profile_, removed_urls); 245} 246 247void ChromeBookmarkClient::BookmarkModelLoaded(BookmarkModel* model, 248 bool ids_reassigned) { 249 // Start tracking the managed bookmarks. This will detect any changes that 250 // may have occurred while the initial managed bookmarks were being loaded 251 // on the background. 252 managed_bookmarks_tracker_->Init(managed_node_); 253} 254 255// static 256bookmarks::BookmarkPermanentNodeList ChromeBookmarkClient::LoadExtraNodes( 257 scoped_ptr<BookmarkPermanentNode> managed_node, 258 scoped_ptr<base::ListValue> initial_managed_bookmarks, 259 int64* next_node_id) { 260 // Load the initial contents of the |managed_node| now, and assign it an 261 // unused ID. 262 int64 managed_id = *next_node_id; 263 managed_node->set_id(managed_id); 264 *next_node_id = policy::ManagedBookmarksTracker::LoadInitial( 265 managed_node.get(), initial_managed_bookmarks.get(), managed_id + 1); 266 managed_node->set_visible(!managed_node->empty()); 267 managed_node->SetTitle( 268 l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_MANAGED_FOLDER_DEFAULT_NAME)); 269 270 bookmarks::BookmarkPermanentNodeList extra_nodes; 271 // Ownership of the managed node passed to the caller. 272 extra_nodes.push_back(managed_node.release()); 273 274 return extra_nodes.Pass(); 275} 276 277std::string ChromeBookmarkClient::GetManagedBookmarksDomain() { 278 policy::ProfilePolicyConnector* connector = 279 policy::ProfilePolicyConnectorFactory::GetForProfile(profile_); 280 if (connector->IsPolicyFromCloudPolicy(policy::key::kManagedBookmarks)) 281 return connector->GetManagementDomain(); 282 return std::string(); 283} 284