blob: 7dfb2645795e69b1575955e1673bf04d88bcd414 [file] [log] [blame]
// Copyright 2017 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 "ios/chrome/browser/ntp_snippets/ios_chrome_content_suggestions_service_factory_util.h"
#include <string>
#include <utility>
#include "base/bind.h"
#include "base/feature_list.h"
#include "base/files/file_path.h"
#include "base/json/json_reader.h"
#include "base/task/post_task.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/default_clock.h"
#include "base/timer/timer.h"
#include "base/values.h"
#include "components/image_fetcher/core/image_decoder.h"
#include "components/image_fetcher/core/image_fetcher.h"
#include "components/image_fetcher/core/image_fetcher_impl.h"
#include "components/image_fetcher/ios/ios_image_decoder_impl.h"
#include "components/keyed_service/core/service_access_type.h"
#include "components/keyed_service/ios/browser_state_dependency_manager.h"
#include "components/ntp_snippets/breaking_news/breaking_news_listener.h"
#include "components/ntp_snippets/category_rankers/category_ranker.h"
#include "components/ntp_snippets/category_rankers/click_based_category_ranker.h"
#include "components/ntp_snippets/category_rankers/constant_category_ranker.h"
#include "components/ntp_snippets/content_suggestions_service.h"
#include "components/ntp_snippets/features.h"
#include "components/ntp_snippets/logger.h"
#include "components/ntp_snippets/ntp_snippets_constants.h"
#include "components/ntp_snippets/remote/persistent_scheduler.h"
#include "components/ntp_snippets/remote/remote_suggestions_database.h"
#include "components/ntp_snippets/remote/remote_suggestions_fetcher_impl.h"
#include "components/ntp_snippets/remote/remote_suggestions_provider_impl.h"
#include "components/ntp_snippets/remote/remote_suggestions_scheduler_impl.h"
#include "components/ntp_snippets/remote/remote_suggestions_status_service_impl.h"
#include "components/ntp_snippets/user_classifier.h"
#include "components/version_info/version_info.h"
#include "google_apis/google_api_keys.h"
#include "ios/chrome/browser/application_context.h"
#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
#include "ios/chrome/browser/favicon/ios_chrome_large_icon_service_factory.h"
#include "ios/chrome/browser/history/history_service_factory.h"
#include "ios/chrome/browser/pref_names.h"
#include "ios/chrome/browser/signin/identity_manager_factory.h"
#include "ios/chrome/browser/ui/util/ui_util.h"
#include "ios/chrome/common/channel_info.h"
#include "ios/web/public/browser_state.h"
#include "net/url_request/url_request_context_getter.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
using history::HistoryService;
using image_fetcher::CreateIOSImageDecoder;
using image_fetcher::ImageFetcherImpl;
using ntp_snippets::ContentSuggestionsService;
using ntp_snippets::GetFetchEndpoint;
using ntp_snippets::Logger;
using ntp_snippets::PersistentScheduler;
using ntp_snippets::RemoteSuggestionsDatabase;
using ntp_snippets::RemoteSuggestionsFetcherImpl;
using ntp_snippets::RemoteSuggestionsProviderImpl;
using ntp_snippets::RemoteSuggestionsSchedulerImpl;
using ntp_snippets::RemoteSuggestionsStatusServiceImpl;
using ntp_snippets::UserClassifier;
namespace {
void ParseJson(const std::string& json,
const ntp_snippets::SuccessCallback& success_callback,
const ntp_snippets::ErrorCallback& error_callback) {
base::JSONReader json_reader;
std::unique_ptr<base::Value> value = json_reader.ReadToValue(json);
if (value) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind(success_callback, base::Passed(&value)));
} else {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::Bind(error_callback, json_reader.GetErrorMessage()));
}
}
} // namespace
namespace ntp_snippets {
std::unique_ptr<KeyedService>
CreateChromeContentSuggestionsServiceWithProviders(
web::BrowserState* browser_state) {
auto service =
ntp_snippets::CreateChromeContentSuggestionsService(browser_state);
ContentSuggestionsService* suggestions_service =
static_cast<ContentSuggestionsService*>(service.get());
if (base::FeatureList::IsEnabled(ntp_snippets::kArticleSuggestionsFeature)) {
ntp_snippets::RegisterRemoteSuggestionsProvider(suggestions_service,
browser_state);
}
return service;
}
std::unique_ptr<KeyedService> CreateChromeContentSuggestionsService(
web::BrowserState* browser_state) {
using State = ContentSuggestionsService::State;
ios::ChromeBrowserState* chrome_browser_state =
ios::ChromeBrowserState::FromBrowserState(browser_state);
DCHECK(!browser_state->IsOffTheRecord());
PrefService* prefs = chrome_browser_state->GetPrefs();
auto user_classifier = std::make_unique<UserClassifier>(
prefs, base::DefaultClock::GetInstance());
auto debug_logger = std::make_unique<Logger>();
// TODO(crbug.com/676249): Implement a persistent scheduler for iOS.
auto scheduler = std::make_unique<RemoteSuggestionsSchedulerImpl>(
/*persistent_scheduler=*/nullptr, user_classifier.get(), prefs,
GetApplicationContext()->GetLocalState(),
base::DefaultClock::GetInstance(), debug_logger.get());
// Create the ContentSuggestionsService.
identity::IdentityManager* identity_manager =
IdentityManagerFactory::GetForBrowserState(chrome_browser_state);
HistoryService* history_service =
ios::HistoryServiceFactory::GetForBrowserState(
chrome_browser_state, ServiceAccessType::EXPLICIT_ACCESS);
favicon::LargeIconService* large_icon_service =
IOSChromeLargeIconServiceFactory::GetForBrowserState(
chrome_browser_state);
std::unique_ptr<ntp_snippets::CategoryRanker> category_ranker =
ntp_snippets::BuildSelectedCategoryRanker(
prefs, base::DefaultClock::GetInstance(),
/*is_chrome_home_enabled=*/false);
return std::make_unique<ContentSuggestionsService>(
State::ENABLED, identity_manager, history_service, large_icon_service,
prefs, std::move(category_ranker), std::move(user_classifier),
std::move(scheduler), std::move(debug_logger));
}
void RegisterRemoteSuggestionsProvider(ContentSuggestionsService* service,
web::BrowserState* browser_state) {
ios::ChromeBrowserState* chrome_browser_state =
ios::ChromeBrowserState::FromBrowserState(browser_state);
PrefService* prefs = chrome_browser_state->GetPrefs();
identity::IdentityManager* identity_manager =
IdentityManagerFactory::GetForBrowserState(chrome_browser_state);
scoped_refptr<net::URLRequestContextGetter> request_context =
browser_state->GetRequestContext();
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory =
browser_state->GetSharedURLLoaderFactory();
base::FilePath database_dir(
browser_state->GetStatePath().Append(ntp_snippets::kDatabaseFolder));
std::string api_key;
// This API needs whitelisted API keys. Get the key only if it is not a
// dummy key.
if (google_apis::HasAPIKeyConfigured()) {
bool is_stable_channel = GetChannel() == version_info::Channel::STABLE;
api_key = is_stable_channel ? google_apis::GetAPIKey()
: google_apis::GetNonStableAPIKey();
}
auto suggestions_fetcher = std::make_unique<RemoteSuggestionsFetcherImpl>(
identity_manager, url_loader_factory, prefs, nullptr,
base::BindRepeating(&ParseJson), GetFetchEndpoint(), api_key,
service->user_classifier());
// This pref is also used for logging. If it is changed, change it in the
// other places.
std::string pref_name = prefs::kArticlesForYouEnabled;
auto provider = std::make_unique<RemoteSuggestionsProviderImpl>(
service, prefs, GetApplicationContext()->GetApplicationLocale(),
service->category_ranker(), service->remote_suggestions_scheduler(),
std::move(suggestions_fetcher),
std::make_unique<ImageFetcherImpl>(
CreateIOSImageDecoder(), browser_state->GetSharedURLLoaderFactory()),
std::make_unique<RemoteSuggestionsDatabase>(database_dir),
std::make_unique<RemoteSuggestionsStatusServiceImpl>(
identity_manager->HasPrimaryAccount(), prefs, pref_name),
/*prefetched_pages_tracker=*/nullptr,
/*breaking_news_raw_data_provider*/ nullptr, service->debug_logger(),
std::make_unique<base::OneShotTimer>());
service->remote_suggestions_scheduler()->SetProvider(provider.get());
service->set_remote_suggestions_provider(provider.get());
service->RegisterProvider(std::move(provider));
}
} // namespace ntp_snippets