blob: 461a13797622c14152fb0dcb76e948a5f3ff1fe0 [file] [log] [blame]
// Copyright 2015 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.
#ifndef COMPONENTS_NTP_SNIPPETS_NTP_SNIPPETS_SERVICE_H_
#define COMPONENTS_NTP_SNIPPETS_NTP_SNIPPETS_SERVICE_H_
#include <stddef.h>
#include <string>
#include <vector>
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/sequenced_task_runner.h"
#include "base/timer/timer.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/ntp_snippets/inner_iterator.h"
#include "components/ntp_snippets/ntp_snippet.h"
#include "components/ntp_snippets/ntp_snippets_fetcher.h"
#include "components/ntp_snippets/ntp_snippets_scheduler.h"
#include "components/suggestions/suggestions_service.h"
class PrefService;
namespace base {
class FilePath;
class ListValue;
}
namespace suggestions {
class SuggestionsProfile;
}
namespace user_prefs {
class PrefRegistrySyncable;
}
namespace ntp_snippets {
class NTPSnippetsServiceObserver;
// Stores and vend fresh content data for the NTP.
class NTPSnippetsService : public KeyedService, NTPSnippetsFetcher::Observer {
public:
using NTPSnippetStorage = std::vector<scoped_ptr<NTPSnippet>>;
using const_iterator =
InnerIterator<NTPSnippetStorage::const_iterator, const NTPSnippet>;
// |application_language_code| should be a ISO 639-1 compliant string. Aka
// 'en' or 'en-US'. Note that this code should only specify the language, not
// the locale, so 'en_US' (english language with US locale) and 'en-GB_US'
// (British english person in the US) are not language code.
NTPSnippetsService(PrefService* pref_service,
suggestions::SuggestionsService* suggestions_service,
scoped_refptr<base::SequencedTaskRunner> file_task_runner,
const std::string& application_language_code,
NTPSnippetsScheduler* scheduler,
scoped_ptr<NTPSnippetsFetcher> snippets_fetcher);
~NTPSnippetsService() override;
static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
void Init(bool enabled);
// Fetches snippets from the server and adds them to the current ones.
void FetchSnippets();
// Inherited from KeyedService.
void Shutdown() override;
// True once the data is loaded in memory and available to loop over.
bool is_loaded() { return loaded_; }
// Observer accessors.
void AddObserver(NTPSnippetsServiceObserver* observer);
void RemoveObserver(NTPSnippetsServiceObserver* observer);
// Number of snippets available. Can only be called when is_loaded() is true.
NTPSnippetStorage::size_type size() {
DCHECK(loaded_);
return snippets_.size();
}
// The snippets can be iterated upon only via a const_iterator. Recommended
// way to iterate is as follows:
//
// NTPSnippetsService service; // Assume is set.
// for (auto& snippet : *service) {
// // Snippet here is a const object.
// }
const_iterator begin() {
DCHECK(loaded_);
return const_iterator(snippets_.begin());
}
const_iterator end() {
DCHECK(loaded_);
return const_iterator(snippets_.end());
}
private:
void OnSuggestionsChanged(const suggestions::SuggestionsProfile& suggestions);
void OnSnippetsDownloaded(const base::FilePath& download_path);
void OnFileReadDone(const std::string* json, bool success);
// Expects a top-level dictionary containing a "recos" list, which will be
// passed to |LoadFromJSONList|.
bool LoadFromJSONString(const std::string& str);
// Expects a list of dictionaries each containing a "contentInfo" dictionary
// with keys matching the properties of a snippet (url, title, site_title,
// etc...). The url is the only mandatory value.
bool LoadFromJSONList(const base::ListValue& list);
// TODO(treib): Investigate a better storage, maybe LevelDB or SQLite?
void LoadFromPrefs();
void StoreToPrefs();
void RemoveExpiredSnippets();
PrefService* pref_service_;
suggestions::SuggestionsService* suggestions_service_;
// True if the suggestions are loaded.
bool loaded_;
// The SequencedTaskRunner on which file system operations will be run.
scoped_refptr<base::SequencedTaskRunner> file_task_runner_;
// All the suggestions.
NTPSnippetStorage snippets_;
// The ISO 639-1 code of the language used by the application.
const std::string application_language_code_;
// The observers.
base::ObserverList<NTPSnippetsServiceObserver> observers_;
// Scheduler for fetching snippets. Not owned.
NTPSnippetsScheduler* scheduler_;
// The subscription to the SuggestionsService. When the suggestions change,
// SuggestionsService will call |OnSuggestionsChanged|, which triggers an
// update to the set of snippets.
using SuggestionsSubscription =
suggestions::SuggestionsService::ResponseCallbackList::Subscription;
scoped_ptr<SuggestionsSubscription> suggestions_service_subscription_;
// The snippets fetcher.
scoped_ptr<NTPSnippetsFetcher> snippets_fetcher_;
// The subscription to the snippets fetcher.
scoped_ptr<NTPSnippetsFetcher::SnippetsAvailableCallbackList::Subscription>
snippets_fetcher_callback_;
// Timer that calls us back when the next snippet expires.
base::OneShotTimer expiry_timer_;
base::WeakPtrFactory<NTPSnippetsService> weak_ptr_factory_;
friend class NTPSnippetsServiceTest;
FRIEND_TEST_ALL_PREFIXES(NTPSnippetsServiceTest, Loop);
FRIEND_TEST_ALL_PREFIXES(NTPSnippetsServiceTest, Full);
FRIEND_TEST_ALL_PREFIXES(NTPSnippetsServiceTest, CreationTimestampParseFail);
FRIEND_TEST_ALL_PREFIXES(NTPSnippetsServiceTest, RemoveExpiredContent);
FRIEND_TEST_ALL_PREFIXES(NTPSnippetsServiceTest, ObserverLoaded);
FRIEND_TEST_ALL_PREFIXES(NTPSnippetsServiceTest, ObserverNotLoaded);
DISALLOW_COPY_AND_ASSIGN(NTPSnippetsService);
};
class NTPSnippetsServiceObserver {
public:
// Send everytime the service loads a new set of data.
virtual void NTPSnippetsServiceLoaded(NTPSnippetsService* service) = 0;
// Send when the service is shutting down.
virtual void NTPSnippetsServiceShutdown(NTPSnippetsService* service) = 0;
protected:
virtual ~NTPSnippetsServiceObserver() {}
};
} // namespace ntp_snippets
#endif // COMPONENTS_NTP_SNIPPETS_NTP_SNIPPETS_SERVICE_H_