| // Copyright 2020 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef COMPONENTS_FEED_CORE_V2_FEED_STREAM_H_ |
| #define COMPONENTS_FEED_CORE_V2_FEED_STREAM_H_ |
| |
| #include <map> |
| #include <memory> |
| #include <string> |
| #include <vector> |
| |
| #include "base/containers/circular_deque.h" |
| #include "base/containers/flat_set.h" |
| #include "base/memory/raw_ptr.h" |
| #include "base/memory/scoped_refptr.h" |
| #include "base/observer_list.h" |
| #include "base/task/sequenced_task_runner.h" |
| #include "base/time/time.h" |
| #include "base/version.h" |
| #include "components/feed/core/proto/v2/ui.pb.h" |
| #include "components/feed/core/proto/v2/wire/reliability_logging_enums.pb.h" |
| #include "components/feed/core/proto/v2/wire/response.pb.h" |
| #include "components/feed/core/v2/enums.h" |
| #include "components/feed/core/v2/launch_reliability_logger.h" |
| #include "components/feed/core/v2/metrics_reporter.h" |
| #include "components/feed/core/v2/persistent_key_value_store_impl.h" |
| #include "components/feed/core/v2/protocol_translator.h" |
| #include "components/feed/core/v2/public/feed_api.h" |
| #include "components/feed/core/v2/public/logging_parameters.h" |
| #include "components/feed/core/v2/public/stream_type.h" |
| #include "components/feed/core/v2/request_throttler.h" |
| #include "components/feed/core/v2/scheduling.h" |
| #include "components/feed/core/v2/stream/info_card_tracker.h" |
| #include "components/feed/core/v2/stream/privacy_notice_card_tracker.h" |
| #include "components/feed/core/v2/stream_model.h" |
| #include "components/feed/core/v2/stream_surface_set.h" |
| #include "components/feed/core/v2/tasks/load_more_task.h" |
| #include "components/feed/core/v2/tasks/load_stream_task.h" |
| #include "components/feed/core/v2/tasks/wait_for_store_initialize_task.h" |
| #include "components/feed/core/v2/user_actions_collector.h" |
| #include "components/feed/core/v2/web_feed_subscription_coordinator.h" |
| #include "components/feed/core/v2/wire_response_translator.h" |
| #include "components/feed/core/v2/xsurface_datastore.h" |
| #include "components/offline_pages/task/task_queue.h" |
| #include "components/prefs/pref_member.h" |
| #include "third_party/abseil-cpp/absl/types/optional.h" |
| |
| class PrefService; |
| |
| namespace feed { |
| namespace feed_stream { |
| class UnreadContentNotifier; |
| } |
| class FeedNetwork; |
| class FeedStore; |
| class WebFeedSubscriptionCoordinator; |
| class ImageFetcher; |
| class MetricsReporter; |
| class RefreshTaskScheduler; |
| class PersistentKeyValueStoreImpl; |
| class StreamModel; |
| class SurfaceUpdater; |
| |
| // Implements FeedApi. |FeedStream| additionally exposes functionality |
| // needed by other classes within the Feed component. |
| class FeedStream : public FeedApi, |
| public offline_pages::TaskQueue::Delegate, |
| public MetricsReporter::Delegate, |
| public StreamModel::StoreObserver { |
| public: |
| class Delegate : public WebFeedSubscriptionCoordinator::Delegate { |
| public: |
| virtual ~Delegate() = default; |
| // Returns true if Chrome's EULA has been accepted. |
| virtual bool IsEulaAccepted() = 0; |
| // Returns true if the device is offline. |
| virtual bool IsOffline() = 0; |
| virtual DisplayMetrics GetDisplayMetrics() = 0; |
| virtual std::string GetLanguageTag() = 0; |
| virtual bool IsAutoplayEnabled() = 0; |
| virtual TabGroupEnabledState GetTabGroupEnabledState() = 0; |
| virtual void ClearAll() = 0; |
| virtual AccountInfo GetAccountInfo() = 0; |
| virtual bool IsSigninAllowed() = 0; |
| // Returns true if Sync is enabled for the user. If the user is not signed |
| // in it also returns false. |
| virtual bool IsSyncOn() = 0; |
| virtual void PrefetchImage(const GURL& url) = 0; |
| virtual void RegisterExperiments(const Experiments& experiments) = 0; |
| virtual void RegisterFeedUserSettingsFieldTrial( |
| base::StringPiece group) = 0; |
| }; |
| |
| FeedStream(RefreshTaskScheduler* refresh_task_scheduler, |
| MetricsReporter* metrics_reporter, |
| Delegate* delegate, |
| PrefService* profile_prefs, |
| FeedNetwork* feed_network, |
| ImageFetcher* image_fetcher, |
| FeedStore* feed_store, |
| PersistentKeyValueStoreImpl* persistent_key_value_store, |
| const ChromeInfo& chrome_info); |
| ~FeedStream() override; |
| |
| FeedStream(const FeedStream&) = delete; |
| FeedStream& operator=(const FeedStream&) = delete; |
| |
| // FeedApi. |
| |
| WebFeedSubscriptionCoordinator& subscriptions() override; |
| std::string GetSessionId() const override; |
| void AttachSurface(FeedStreamSurface*) override; |
| void DetachSurface(FeedStreamSurface*) override; |
| void UpdateUserProfileOnLinkClick( |
| const GURL& url, |
| const std::vector<int64_t>& entity_mids) override; |
| void AddUnreadContentObserver(const StreamType& stream_type, |
| UnreadContentObserver* observer) override; |
| void RemoveUnreadContentObserver(const StreamType& stream_type, |
| UnreadContentObserver* observer) override; |
| bool IsArticlesListVisible() override; |
| void ExecuteRefreshTask(RefreshTaskId task_id) override; |
| ImageFetchId FetchImage( |
| const GURL& url, |
| base::OnceCallback<void(NetworkResponse)> callback) override; |
| void CancelImageFetch(ImageFetchId id) override; |
| PersistentKeyValueStoreImpl& GetPersistentKeyValueStore() override; |
| void LoadMore(const FeedStreamSurface& surface, |
| base::OnceCallback<void(bool)> callback) override; |
| void ManualRefresh(const StreamType& stream_type, |
| base::OnceCallback<void(bool)> callback) override; |
| void ExecuteOperations( |
| const StreamType& stream_type, |
| std::vector<feedstore::DataOperation> operations) override; |
| EphemeralChangeId CreateEphemeralChange( |
| const StreamType& stream_type, |
| std::vector<feedstore::DataOperation> operations) override; |
| EphemeralChangeId CreateEphemeralChangeFromPackedData( |
| const StreamType& stream_type, |
| base::StringPiece data) override; |
| bool CommitEphemeralChange(const StreamType& stream_type, |
| EphemeralChangeId id) override; |
| bool RejectEphemeralChange(const StreamType& stream_type, |
| EphemeralChangeId id) override; |
| void ProcessThereAndBackAgain( |
| base::StringPiece data, |
| const LoggingParameters& logging_parameters) override; |
| void ProcessViewAction(base::StringPiece data, |
| const LoggingParameters& logging_parameters) override; |
| bool WasUrlRecentlyNavigatedFromFeed(const GURL& url) override; |
| void InvalidateContentCacheFor(StreamKind stream_kind) override; |
| void RecordContentViewed(uint64_t docid) override; |
| DebugStreamData GetDebugStreamData() override; |
| void ForceRefreshForDebugging(const StreamType& stream_type) override; |
| std::string DumpStateForDebugging() override; |
| void SetForcedStreamUpdateForDebugging( |
| const feedui::StreamUpdate& stream_update) override; |
| |
| void ReportSliceViewed(SurfaceId surface_id, |
| const StreamType& stream_type, |
| const std::string& slice_id) override; |
| void ReportFeedViewed(const StreamType& stream_type, |
| SurfaceId surface_id) override; |
| void ReportPageLoaded() override; |
| void ReportOpenAction(const GURL& url, |
| const StreamType& stream_type, |
| const std::string& slice_id, |
| OpenActionType action_type) override; |
| void ReportOpenVisitComplete(base::TimeDelta visit_time) override; |
| void ReportStreamScrolled(const StreamType& stream_type, |
| int distance_dp) override; |
| void ReportStreamScrollStart() override; |
| void ReportOtherUserAction(const StreamType& stream_type, |
| FeedUserActionType action_type) override; |
| void ReportInfoCardTrackViewStarted(const StreamType& stream_type, |
| int info_card_type) override; |
| void ReportInfoCardViewed(const StreamType& stream_type, |
| int info_card_type, |
| int minimum_view_interval_seconds) override; |
| void ReportInfoCardClicked(const StreamType& stream_type, |
| int info_card_type) override; |
| void ReportInfoCardDismissedExplicitly(const StreamType& stream_type, |
| int info_card_type) override; |
| void ResetInfoCardStates(const StreamType& stream_type, |
| int info_card_type) override; |
| void ReportContentSliceVisibleTimeForGoodVisits( |
| base::TimeDelta elapsed) override; |
| base::Time GetLastFetchTime(const StreamType& stream_type) override; |
| void SetContentOrder(const StreamType& stream_type, |
| ContentOrder content_order) override; |
| ContentOrder GetContentOrder(const StreamType& stream_type) const override; |
| ContentOrder GetContentOrderFromPrefs(const StreamType& stream_type) override; |
| void IncrementFollowedFromWebPageMenuCount() override; |
| |
| // offline_pages::TaskQueue::Delegate. |
| void OnTaskQueueIsIdle() override; |
| |
| // MetricsReporter::Delegate. |
| void SubscribedWebFeedCount(base::OnceCallback<void(int)> callback) override; |
| void RegisterFeedUserSettingsFieldTrial(base::StringPiece group) override; |
| |
| // StreamModel::StoreObserver. |
| void OnStoreChange(StreamModel::StoreUpdate update) override; |
| |
| // Event indicators. These functions are called from an external source |
| // to indicate an event. |
| |
| // Called when Chrome's EULA has been accepted. This should happen when |
| // Delegate::IsEulaAccepted() changes from false to true. |
| void OnEulaAccepted(); |
| // Invoked when Chrome is backgrounded. |
| void OnEnterBackground(); |
| // The user signed in to Chrome. |
| void OnSignedIn(); |
| // The user signed out of Chrome. |
| void OnSignedOut(); |
| // The user has deleted all browsing history. |
| void OnAllHistoryDeleted(); |
| // Chrome's cached data was cleared. |
| void OnCacheDataCleared(); |
| |
| // State shared for the sake of implementing FeedStream. Typically these |
| // functions are used by tasks. |
| |
| void LoadModel(const StreamType& stream_type, |
| std::unique_ptr<StreamModel> model); |
| |
| // Store/upload an action and update the consistency token. |callback| is |
| // called with |true| if the consistency token was written to the store. |
| void UploadAction( |
| feedwire::FeedAction action, |
| const LoggingParameters& logging_parameters, |
| bool upload_now, |
| base::OnceCallback<void(UploadActionsTask::Result)> callback); |
| |
| FeedNetwork& GetNetwork() { return *feed_network_; } |
| FeedStore& GetStore() { return *store_; } |
| RequestThrottler& GetRequestThrottler() { return request_throttler_; } |
| const feedstore::Metadata& GetMetadata() const; |
| void SetMetadata(feedstore::Metadata metadata); |
| bool SetMetadata(absl::optional<feedstore::Metadata> metadata); |
| void SetStreamStale(const StreamType& stream_type, bool is_stale); |
| |
| MetricsReporter& GetMetricsReporter() const { return *metrics_reporter_; } |
| |
| void PrefetchImage(const GURL& url); |
| |
| bool IsSigninAllowed() const { return delegate_->IsSigninAllowed(); } |
| bool IsSignedIn() const { return !delegate_->GetAccountInfo().IsEmpty(); } |
| bool IsSyncOn() const { return delegate_->IsSyncOn(); } |
| AccountInfo GetAccountInfo() const { return delegate_->GetAccountInfo(); } |
| |
| // Determines if we should attempt loading the stream or refreshing at all. |
| // Returns |LoadStreamStatus::kNoStatus| if loading may be attempted. |
| LaunchResult ShouldAttemptLoad(const StreamType& stream_type, |
| LoadType load_type, |
| bool model_loading = false); |
| |
| // Whether the last scheduled refresh was missed. |
| bool MissedLastRefresh(const StreamType& stream_type); |
| |
| // Determines if a FeedQuery request can be made. If successful, |
| // returns |LoadStreamStatus::kNoStatus| and acquires throttler quota. |
| // Otherwise returns the reason. If |consume_quota| is false, no quota is |
| // consumed. This can be used to predict the likely result on a subsequent |
| // call. |
| LaunchResult ShouldMakeFeedQueryRequest(const StreamType& stream_type, |
| LoadType load_type, |
| bool consume_quota = true); |
| |
| // Returns the Chrome sign in status |
| feedwire::ChromeSignInStatus::SignInStatus GetSignInStatus() const; |
| |
| // Unloads one stream model. Surfaces are not updated, and will remain frozen |
| // until a model load is requested. |
| void UnloadModel(const StreamType& stream_type); |
| // Unloads all stream models. |
| void UnloadModels(); |
| |
| // Triggers a stream load. The load will be aborted if |ShouldAttemptLoad()| |
| // is not true. Returns CARDS_UNSPECIFIED if loading is to proceed, or another |
| // DiscoverLaunchResult if loading will not be attempted. |
| feedwire::DiscoverLaunchResult TriggerStreamLoad( |
| const StreamType& stream_type, |
| SingleWebFeedEntryPoint entry_point = SingleWebFeedEntryPoint::kOther); |
| |
| // Only to be called by ClearAllTask. This clears other stream data stored in |
| // memory. |
| void FinishClearAll(); |
| |
| // Only to be called by ClearStreamTask. This clears other stream data stored |
| // in memory. |
| void FinishClearStream(const StreamType& stream_type); |
| |
| // Returns the model if it is loaded, or null otherwise. |
| StreamModel* GetModel(const StreamType& stream_type); |
| |
| // Gets request metadata assuming the account is signed-in. This is useful for |
| // uploading actions where stream type is not known, but sign-in status is |
| // required. |
| RequestMetadata GetSignedInRequestMetadata() const; |
| |
| // Gets request metadata, looking up if session ID or client instance ID |
| // should be used based on the login state of Chrome and the model for the |
| // appropriate Stream. |
| RequestMetadata GetRequestMetadata(const StreamType& stream_type, |
| bool is_for_next_page) const; |
| |
| bool HasUnreadContent(const StreamType& stream_type); |
| |
| bool IsOffline() const { return delegate_->IsOffline(); } |
| |
| offline_pages::TaskQueue& GetTaskQueue() { return task_queue_; } |
| |
| const WireResponseTranslator& GetWireResponseTranslator() const { |
| return *wire_response_translator_; |
| } |
| |
| LaunchReliabilityLogger& GetLaunchReliabilityLogger( |
| const StreamType& stream_type); |
| |
| XsurfaceDatastoreSlice& GetGlobalXsurfaceDatastore() { |
| return global_datastore_slice_; |
| } |
| |
| // Testing functionality. |
| offline_pages::TaskQueue& GetTaskQueueForTesting(); |
| // Loads |model|. Should be used for testing in place of typical model |
| // loading from network or storage. |
| void LoadModelForTesting(const StreamType& stream_type, |
| std::unique_ptr<StreamModel> model); |
| void SetWireResponseTranslatorForTesting( |
| const WireResponseTranslator* wire_response_translator) { |
| wire_response_translator_ = wire_response_translator; |
| } |
| void SetIdleCallbackForTesting(base::RepeatingClosure idle_callback); |
| |
| bool ClearAllInProgress() const { return clear_all_in_progress_; } |
| |
| bool IsEnabledAndVisible(); |
| |
| PrefService* profile_prefs() const { return profile_prefs_; } |
| |
| base::WeakPtr<FeedStream> GetWeakPtr() { |
| return weak_ptr_factory_.GetWeakPtr(); |
| } |
| |
| bool GetStreamPresentForTest(StreamType stream_type) { |
| return FindStream(stream_type) != nullptr; |
| } |
| |
| private: |
| using UnreadContentNotifier = feed_stream::UnreadContentNotifier; |
| |
| struct Stream { |
| explicit Stream(const StreamType& stream_type); |
| ~Stream(); |
| Stream(const Stream&) = delete; |
| Stream& operator=(const Stream&) = delete; |
| StreamType type; |
| // Whether the model is being loaded. Used to prevent multiple simultaneous |
| // attempts to load the model. |
| bool model_loading_in_progress = false; |
| StreamSurfaceSet surfaces; |
| std::unique_ptr<SurfaceUpdater> surface_updater; |
| // The stream model. Null if not yet loaded. |
| // Internally, this should only be changed by |LoadModel()| and |
| // |UnloadModel()|. |
| std::unique_ptr<StreamModel> model; |
| int unload_on_detach_sequence_number = 0; |
| ContentHashSet content_ids; |
| std::vector<UnreadContentNotifier> unread_content_notifiers; |
| std::vector<base::OnceCallback<void(bool)>> load_more_complete_callbacks; |
| std::vector<base::OnceCallback<void(bool)>> refresh_complete_callbacks; |
| bool is_activity_logging_enabled = false; |
| // Cache the list of IDs of contents that have been viewed by the user. |
| // This allows fast lookup. It is only used in for-you feed. |
| base::flat_set<uint32_t> viewed_content_hashes; |
| }; |
| |
| void InitializeComplete(WaitForStoreInitializeTask::Result result); |
| |
| void SetRequestSchedule(const StreamType& stream_type, |
| RequestSchedule schedule); |
| |
| void SetRequestSchedule(RefreshTaskId task_id, RequestSchedule schedule); |
| |
| // A single function task to delete stored feed data and force a refresh. |
| // To only be called from within a |Task|. |
| void ForceRefreshForDebuggingTask(const StreamType& stream_type); |
| void ForceRefreshTask(const StreamType& stream_type); |
| |
| void ScheduleModelUnloadIfNoSurfacesAttached(const StreamType& stream_type); |
| void AddUnloadModelIfNoSurfacesAttachedTask(const StreamType& stream_type, |
| int sequence_number); |
| void UnloadModelIfNoSurfacesAttachedTask(const StreamType& stream_type); |
| |
| void StreamLoadComplete(LoadStreamTask::Result result); |
| void LoadMoreComplete(LoadMoreTask::Result result); |
| void BackgroundRefreshComplete(LoadStreamTask::Result result); |
| void LoadTaskComplete(const LoadStreamTask::Result& result); |
| void UploadActionsComplete(UploadActionsTask::Result result); |
| void ClearAll(); |
| void ClearStream(const StreamType& stream_type, int sequence_number); |
| |
| bool IsFeedEnabledByEnterprisePolicy(); |
| bool IsFeedEnabled(); |
| |
| bool HasReachedConditionsToUploadActionsWithNoticeCard(); |
| |
| void MaybeNotifyHasUnreadContent(const StreamType& stream_type); |
| void EnabledPreferencesChanged(); |
| |
| Stream& GetStream(const StreamType& type); |
| Stream* FindStream(const StreamType& type); |
| const Stream* FindStream(const StreamType& type) const; |
| void UpdateExperiments(Experiments experiments); |
| |
| RequestMetadata GetCommonRequestMetadata(bool signed_in_request, |
| bool allow_expired_session_id) const; |
| |
| // Schedule a feed-close refresh when the user has taken some kind of action |
| // on the feed. |
| void ScheduleFeedCloseRefreshOnInteraction(const StreamType& type); |
| // Schedule a feed-close refresh when the user has viewed content for the |
| // first time. |
| void ScheduleFeedCloseRefreshOnFirstView(const StreamType& type); |
| // Internal method for scheduling the feed-close refresh. |
| void ScheduleFeedCloseRefresh(const StreamType& type); |
| |
| void CheckDuplicatedContentsOnRefresh(); |
| void AddViewedContentHashes(const feedstore::Content& content); |
| |
| // Unowned. |
| |
| raw_ptr<RefreshTaskScheduler> refresh_task_scheduler_; |
| raw_ptr<MetricsReporter> metrics_reporter_; |
| raw_ptr<Delegate> delegate_; |
| raw_ptr<PrefService> profile_prefs_; // May be null. |
| raw_ptr<FeedNetwork> feed_network_; |
| raw_ptr<ImageFetcher> image_fetcher_; |
| raw_ptr<FeedStore> store_; |
| raw_ptr<PersistentKeyValueStoreImpl> persistent_key_value_store_; |
| raw_ptr<const WireResponseTranslator> wire_response_translator_; |
| |
| StreamModel::Context stream_model_context_; |
| // For Xsurface datastore data which applies to all `StreamType`s. |
| XsurfaceDatastoreSlice global_datastore_slice_; |
| |
| ChromeInfo chrome_info_; |
| |
| offline_pages::TaskQueue task_queue_; |
| |
| std::map<StreamType, Stream> streams_; |
| |
| std::unique_ptr<WebFeedSubscriptionCoordinator> |
| web_feed_subscription_coordinator_; |
| |
| // Mutable state. |
| RequestThrottler request_throttler_; |
| |
| BooleanPrefMember has_stored_data_; |
| BooleanPrefMember snippets_enabled_by_policy_; |
| BooleanPrefMember articles_list_visible_; |
| BooleanPrefMember signin_allowed_; |
| |
| // State loaded at startup: |
| feedstore::Metadata metadata_; |
| bool metadata_populated_ = false; |
| |
| base::ObserverList<UnreadContentObserver> unread_content_observers_; |
| |
| // To allow tests to wait on task queue idle. |
| base::RepeatingClosure idle_callback_; |
| |
| // Stream update forced to use for new surfaces. This is provided in feed |
| // internals page for debugging purpose. |
| feedui::StreamUpdate forced_stream_update_for_debugging_; |
| |
| PrivacyNoticeCardTracker privacy_notice_card_tracker_; |
| |
| InfoCardTracker info_card_tracker_; |
| |
| bool clear_all_in_progress_ = false; |
| |
| std::vector<GURL> recent_feed_navigations_; |
| UserActionsCollector user_actions_collector_; |
| |
| base::TimeTicks last_refresh_scheduled_on_interaction_time_{}; |
| |
| base::WeakPtrFactory<FeedStream> weak_ptr_factory_{this}; |
| }; |
| |
| } // namespace feed |
| |
| #endif // COMPONENTS_FEED_CORE_V2_FEED_STREAM_H_ |