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