Home | History | Annotate | Download | only in bookmarks
      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