1 // Copyright 2018 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 #ifndef COMPONENTS_FEED_CONTENT_FEED_OFFLINE_HOST_H_ 6 #define COMPONENTS_FEED_CONTENT_FEED_OFFLINE_HOST_H_ 7 8 #include <string> 9 #include <vector> 10 11 #include "base/callback.h" 12 #include "base/containers/flat_map.h" 13 #include "base/macros.h" 14 #include "base/memory/weak_ptr.h" 15 #include "base/optional.h" 16 #include "base/sequenced_task_runner.h" 17 #include "components/feed/core/content_metadata.h" 18 #include "components/offline_pages/core/offline_page_model.h" 19 #include "components/offline_pages/core/prefetch/suggestions_provider.h" 20 21 class GURL; 22 23 namespace offline_pages { 24 class PrefetchService; 25 } // namespace offline_pages 26 27 namespace feed { 28 29 // Responsible for wiring up connections for Feed operations pertaining to 30 // articles that can be loaded from Offline Pages component. Most significantly 31 // this class connects Prefetch and the Feed, and tracks offlined articles the 32 // Feed may have badged for this user. This knowledge is later used when Feed 33 // articles are opened to populate load params. 34 class FeedOfflineHost : public offline_pages::SuggestionsProvider, 35 public offline_pages::OfflinePageModel::Observer { 36 public: 37 using GetKnownContentCallback = 38 base::OnceCallback<void(std::vector<ContentMetadata>)>; 39 using NotifyStatusChangeCallback = 40 base::RepeatingCallback<void(const std::string&, bool)>; 41 42 FeedOfflineHost(offline_pages::OfflinePageModel* offline_page_model, 43 offline_pages::PrefetchService* prefetch_service, 44 base::RepeatingClosure on_suggestion_consumed, 45 base::RepeatingClosure on_suggestions_shown); 46 ~FeedOfflineHost() override; 47 48 // Initialize with callbacks to call into bridge/Java side. Should only be 49 // called once, and done as soon as the bridge is ready. The FeedOfflineHost 50 // will not be fully ready to perform its function without these dependencies. 51 // Neither of these callbacks will be invoked until after this method exits. 52 void Initialize(const base::RepeatingClosure& trigger_get_known_content, 53 const NotifyStatusChangeCallback& notify_status_change); 54 55 // Called during initialization make ourselves known to |prefetch_service_|. 56 // This method is used to wrap PrefetchService::SetSuggestionProvider() to let 57 // our weak pointer guarantee everyone is still alive. 58 void SetSuggestionProvider(); 59 60 // Synchronously returns the offline id of the given page. The host will only 61 // have knowledge of the page if it had previously returned status about it 62 // through GetOfflineState() or as a notification. Otherwise the caller will 63 // receive a false negative. Additionally, since the host tracks pages by 64 // hashing, there's also a small chance that the host erroneously returns an 65 // id for a page that is not offlined. 66 base::Optional<int64_t> GetOfflineId(const std::string& url); 67 68 // Asynchronously fetches offline status for the given URLs. Any pages that 69 // are currently offlined will be remembered by the FeedOfflineHost. 70 void GetOfflineStatus( 71 std::vector<std::string> urls, 72 base::OnceCallback<void(std::vector<std::string>)> callback); 73 74 // Should be called from Feed any time the user manually removes articles or 75 // groupings of articles. Propagates the signal to Prefetch. 76 void OnContentRemoved(std::vector<std::string> urls); 77 78 // Should be called from Feed any time new articles are fetched. 79 void OnNewContentReceived(); 80 81 // Should be called from Feed side any time there are no active surfaces 82 // displaying articles and listening to our notifications. This signal is used 83 // to clear local tracking of offlined items. 84 void OnNoListeners(); 85 86 // Should be called when async GetKnownContent is completed. Broadcasts to all 87 // waiting consumers in |pending_known_content_callbacks_|. 88 void OnGetKnownContentDone(std::vector<ContentMetadata> suggestions); 89 90 // offline_pages::SuggestionsProvider: 91 void GetCurrentArticleSuggestions( 92 offline_pages::SuggestionsProvider::SuggestionCallback 93 suggestions_callback) override; 94 void ReportArticleListViewed() override; 95 void ReportArticleViewed(GURL article_url) override; 96 97 // offline_pages::OfflinePageModel::Observer: 98 void OfflinePageModelLoaded(offline_pages::OfflinePageModel* model) override; 99 void OfflinePageAdded( 100 offline_pages::OfflinePageModel* model, 101 const offline_pages::OfflinePageItem& added_page) override; 102 void OfflinePageDeleted( 103 const offline_pages::OfflinePageItem& deleted_page) override; 104 105 private: 106 // Stores the given record in |url_hash_to_id_|. If there's a conflict, the 107 // new id will overwrite the old value. 108 void CacheOfflinePageUrlAndId(const std::string& url, int64_t id); 109 110 // Removes a previously cached |id| for the given |url| if there was one. 111 void EvictOfflinePageUrl(const std::string& url); 112 113 // The following objects all outlive us, so it is safe to hold raw pointers to 114 // them. This is guaranteed by the FeedHostServiceFactory. 115 offline_pages::OfflinePageModel* offline_page_model_; 116 offline_pages::PrefetchService* prefetch_service_; 117 118 base::RepeatingClosure on_suggestion_consumed_; 119 base::RepeatingClosure on_suggestions_shown_; 120 121 // Only offlined pages that have passed through the host are stored. If there 122 // are ever no listeners to the offline host logic and OnNoListeners() is 123 // called this map is cleared. The key is the hash of the url, and the value 124 // is the offline id for the given page. 125 base::flat_map<size_t, int64_t> url_hash_to_id_; 126 127 // Starts an the async request for ContentMetadata through KnownContentApi's 128 // GetKnownContent(). Will only be invoked when there isn't already an 129 // outstanding GetKnownContent(). 130 base::RepeatingClosure trigger_get_known_content_; 131 132 // Holds all consumers of GetKnownContent(). It is assumed that there's an 133 // outstanding GetKnownContent() if and only if this vector is not empty. 134 std::vector<SuggestionsProvider::SuggestionCallback> 135 pending_known_content_callbacks_; 136 137 // Calls all OfflineStatusListeners with the updated status. 138 NotifyStatusChangeCallback notify_status_change_; 139 140 SEQUENCE_CHECKER(sequence_checker_); 141 142 base::WeakPtrFactory<FeedOfflineHost> weak_factory_{this}; 143 144 DISALLOW_COPY_AND_ASSIGN(FeedOfflineHost); 145 }; 146 147 } // namespace feed 148 149 #endif // COMPONENTS_FEED_CONTENT_FEED_OFFLINE_HOST_H_ 150