| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/bookmarks/chrome_bookmark_client.h" |
| |
| #include "base/bind.h" |
| #include "base/bind_helpers.h" |
| #include "base/logging.h" |
| #include "base/values.h" |
| #include "chrome/browser/chrome_notification_types.h" |
| #include "chrome/browser/favicon/favicon_changed_details.h" |
| #include "chrome/browser/favicon/favicon_service.h" |
| #include "chrome/browser/favicon/favicon_service_factory.h" |
| #include "chrome/browser/history/history_service.h" |
| #include "chrome/browser/history/history_service_factory.h" |
| #include "chrome/browser/history/url_database.h" |
| #include "chrome/browser/policy/profile_policy_connector.h" |
| #include "chrome/browser/policy/profile_policy_connector_factory.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/profiles/startup_task_runner_service.h" |
| #include "chrome/browser/profiles/startup_task_runner_service_factory.h" |
| #include "components/bookmarks/browser/bookmark_model.h" |
| #include "components/bookmarks/browser/bookmark_node.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/notification_details.h" |
| #include "content/public/browser/notification_source.h" |
| #include "content/public/browser/user_metrics.h" |
| #include "grit/components_strings.h" |
| #include "policy/policy_constants.h" |
| #include "ui/base/l10n/l10n_util.h" |
| |
| namespace { |
| |
| void NotifyHistoryOfRemovedURLs(Profile* profile, |
| const std::set<GURL>& removed_urls) { |
| HistoryService* history_service = |
| HistoryServiceFactory::GetForProfile(profile, Profile::EXPLICIT_ACCESS); |
| if (history_service) |
| history_service->URLsNoLongerBookmarked(removed_urls); |
| } |
| |
| } // namespace |
| |
| ChromeBookmarkClient::ChromeBookmarkClient(Profile* profile) |
| : profile_(profile), model_(NULL), managed_node_(NULL) { |
| } |
| |
| ChromeBookmarkClient::~ChromeBookmarkClient() { |
| } |
| |
| void ChromeBookmarkClient::Init(BookmarkModel* model) { |
| DCHECK(model); |
| DCHECK(!model_); |
| model_ = model; |
| model_->AddObserver(this); |
| |
| managed_bookmarks_tracker_.reset(new policy::ManagedBookmarksTracker( |
| model_, |
| profile_->GetPrefs(), |
| base::Bind(&ChromeBookmarkClient::GetManagedBookmarksDomain, |
| base::Unretained(this)))); |
| |
| // Listen for changes to favicons so that we can update the favicon of the |
| // node appropriately. |
| registrar_.Add(this, |
| chrome::NOTIFICATION_FAVICON_CHANGED, |
| content::Source<Profile>(profile_)); |
| } |
| |
| void ChromeBookmarkClient::Shutdown() { |
| if (model_) { |
| registrar_.RemoveAll(); |
| |
| model_->RemoveObserver(this); |
| model_ = NULL; |
| } |
| BookmarkClient::Shutdown(); |
| } |
| |
| bool ChromeBookmarkClient::IsDescendantOfManagedNode(const BookmarkNode* node) { |
| return node && node->HasAncestor(managed_node_); |
| } |
| |
| bool ChromeBookmarkClient::HasDescendantsOfManagedNode( |
| const std::vector<const BookmarkNode*>& list) { |
| for (size_t i = 0; i < list.size(); ++i) { |
| if (IsDescendantOfManagedNode(list[i])) |
| return true; |
| } |
| return false; |
| } |
| |
| bool ChromeBookmarkClient::PreferTouchIcon() { |
| #if !defined(OS_IOS) |
| return false; |
| #else |
| return true; |
| #endif |
| } |
| |
| base::CancelableTaskTracker::TaskId ChromeBookmarkClient::GetFaviconImageForURL( |
| const GURL& page_url, |
| int icon_types, |
| int desired_size_in_dip, |
| const favicon_base::FaviconImageCallback& callback, |
| base::CancelableTaskTracker* tracker) { |
| FaviconService* favicon_service = |
| FaviconServiceFactory::GetForProfile(profile_, Profile::EXPLICIT_ACCESS); |
| if (!favicon_service) |
| return base::CancelableTaskTracker::kBadTaskId; |
| return favicon_service->GetFaviconImageForPageURL( |
| FaviconService::FaviconForPageURLParams( |
| page_url, icon_types, desired_size_in_dip), |
| callback, |
| tracker); |
| } |
| |
| bool ChromeBookmarkClient::SupportsTypedCountForNodes() { |
| return true; |
| } |
| |
| void ChromeBookmarkClient::GetTypedCountForNodes( |
| const NodeSet& nodes, |
| NodeTypedCountPairs* node_typed_count_pairs) { |
| HistoryService* history_service = |
| HistoryServiceFactory::GetForProfile(profile_, Profile::EXPLICIT_ACCESS); |
| history::URLDatabase* url_db = |
| history_service ? history_service->InMemoryDatabase() : NULL; |
| for (NodeSet::const_iterator i = nodes.begin(); i != nodes.end(); ++i) { |
| int typed_count = 0; |
| |
| // If |url_db| is the InMemoryDatabase, it might not cache all URLRows, but |
| // it guarantees to contain those with |typed_count| > 0. Thus, if we cannot |
| // fetch the URLRow, it is safe to assume that its |typed_count| is 0. |
| history::URLRow url; |
| if (url_db && url_db->GetRowForURL((*i)->url(), &url)) |
| typed_count = url.typed_count(); |
| |
| NodeTypedCountPair pair(*i, typed_count); |
| node_typed_count_pairs->push_back(pair); |
| } |
| } |
| |
| bool ChromeBookmarkClient::IsPermanentNodeVisible( |
| const BookmarkPermanentNode* node) { |
| DCHECK(node->type() == BookmarkNode::BOOKMARK_BAR || |
| node->type() == BookmarkNode::OTHER_NODE || |
| node->type() == BookmarkNode::MOBILE || |
| node == managed_node_); |
| if (node == managed_node_) |
| return false; |
| #if !defined(OS_IOS) |
| return node->type() != BookmarkNode::MOBILE; |
| #else |
| return node->type() == BookmarkNode::MOBILE; |
| #endif |
| } |
| |
| void ChromeBookmarkClient::RecordAction(const base::UserMetricsAction& action) { |
| content::RecordAction(action); |
| } |
| |
| bookmarks::LoadExtraCallback ChromeBookmarkClient::GetLoadExtraNodesCallback() { |
| // Create the managed_node now; it will be populated in the LoadExtraNodes |
| // callback. |
| managed_node_ = new BookmarkPermanentNode(0); |
| return base::Bind( |
| &ChromeBookmarkClient::LoadExtraNodes, |
| StartupTaskRunnerServiceFactory::GetForProfile(profile_) |
| ->GetBookmarkTaskRunner(), |
| managed_node_, |
| base::Passed(managed_bookmarks_tracker_->GetInitialManagedBookmarks())); |
| } |
| |
| bool ChromeBookmarkClient::CanSetPermanentNodeTitle( |
| const BookmarkNode* permanent_node) { |
| // The |managed_node_| can have its title updated if the user signs in or |
| // out. |
| return !IsDescendantOfManagedNode(permanent_node) || |
| permanent_node == managed_node_; |
| } |
| |
| bool ChromeBookmarkClient::CanSyncNode(const BookmarkNode* node) { |
| return !IsDescendantOfManagedNode(node); |
| } |
| |
| bool ChromeBookmarkClient::CanBeEditedByUser(const BookmarkNode* node) { |
| return !IsDescendantOfManagedNode(node); |
| } |
| |
| void ChromeBookmarkClient::Observe( |
| int type, |
| const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| switch (type) { |
| case chrome::NOTIFICATION_FAVICON_CHANGED: { |
| content::Details<FaviconChangedDetails> favicon_details(details); |
| model_->OnFaviconChanged(favicon_details->urls); |
| break; |
| } |
| |
| default: |
| NOTREACHED(); |
| break; |
| } |
| } |
| |
| void ChromeBookmarkClient::BookmarkModelChanged() { |
| } |
| |
| void ChromeBookmarkClient::BookmarkNodeRemoved( |
| BookmarkModel* model, |
| const BookmarkNode* parent, |
| int old_index, |
| const BookmarkNode* node, |
| const std::set<GURL>& removed_urls) { |
| NotifyHistoryOfRemovedURLs(profile_, removed_urls); |
| } |
| |
| void ChromeBookmarkClient::BookmarkAllUserNodesRemoved( |
| BookmarkModel* model, |
| const std::set<GURL>& removed_urls) { |
| NotifyHistoryOfRemovedURLs(profile_, removed_urls); |
| } |
| |
| void ChromeBookmarkClient::BookmarkModelLoaded(BookmarkModel* model, |
| bool ids_reassigned) { |
| // Start tracking the managed bookmarks. This will detect any changes that |
| // may have occurred while the initial managed bookmarks were being loaded |
| // on the background. |
| managed_bookmarks_tracker_->Init(managed_node_); |
| } |
| |
| // static |
| bookmarks::BookmarkPermanentNodeList ChromeBookmarkClient::LoadExtraNodes( |
| const scoped_refptr<base::DeferredSequencedTaskRunner>& profile_io_runner, |
| BookmarkPermanentNode* managed_node, |
| scoped_ptr<base::ListValue> initial_managed_bookmarks, |
| int64* next_node_id) { |
| DCHECK(profile_io_runner->RunsTasksOnCurrentThread()); |
| // Load the initial contents of the |managed_node| now, and assign it an |
| // unused ID. |
| int64 managed_id = *next_node_id; |
| managed_node->set_id(managed_id); |
| *next_node_id = policy::ManagedBookmarksTracker::LoadInitial( |
| managed_node, initial_managed_bookmarks.get(), managed_id + 1); |
| managed_node->set_visible(!managed_node->empty()); |
| managed_node->SetTitle( |
| l10n_util::GetStringUTF16(IDS_BOOKMARK_BAR_MANAGED_FOLDER_DEFAULT_NAME)); |
| |
| bookmarks::BookmarkPermanentNodeList extra_nodes; |
| extra_nodes.push_back(managed_node); |
| return extra_nodes.Pass(); |
| } |
| |
| std::string ChromeBookmarkClient::GetManagedBookmarksDomain() { |
| policy::ProfilePolicyConnector* connector = |
| policy::ProfilePolicyConnectorFactory::GetForProfile(profile_); |
| if (connector->IsPolicyFromCloudPolicy(policy::key::kManagedBookmarks)) |
| return connector->GetManagementDomain(); |
| return std::string(); |
| } |