Commit d564808e authored by dewittj's avatar dewittj Committed by Commit Bot

[Offline Pages] Add a GCMAppHandler for offline page prefetch.

This does not yet react to such messages but hooks up the plumbing so that we are ready for them

Because the app handlers need to be registered before any GCM messages are received, this app handler is added upon construction of the GCMProfileService.

BUG=701939

Review-Url: https://codereview.chromium.org/2864293003
Cr-Commit-Position: refs/heads/master@{#475735}
parent 867e554d
......@@ -2182,6 +2182,8 @@ split_static_library("browser") {
"android/offline_pages/request_coordinator_factory.h",
"offline_pages/background_loader_offliner.cc",
"offline_pages/background_loader_offliner.h",
"offline_pages/prefetch/prefetch_service_factory.cc",
"offline_pages/prefetch/prefetch_service_factory.h",
]
if (is_android) {
sources += [
......@@ -2190,7 +2192,6 @@ split_static_library("browser") {
]
}
deps += [
"//components/offline_pages/content",
"//components/offline_pages/content/background_loader",
"//components/offline_pages/core",
"//components/offline_pages/core/background:background_offliner",
......
......@@ -4,9 +4,9 @@
#include "chrome/browser/android/offline_pages/prefetch/prefetch_background_task.h"
#include "chrome/browser/offline_pages/prefetch/prefetch_service_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_android.h"
#include "components/offline_pages/content/prefetch_service_factory.h"
#include "components/offline_pages/core/prefetch/prefetch_service.h"
#include "content/public/browser/browser_context.h"
#include "jni/PrefetchBackgroundTask_jni.h"
......
......@@ -3,7 +3,6 @@
// found in the LICENSE file.
#include "chrome/browser/gcm/gcm_profile_service_factory.h"
#include <memory>
#include "base/sequenced_task_runner.h"
......@@ -15,6 +14,7 @@
#include "chrome/browser/signin/signin_manager_factory.h"
#include "components/gcm_driver/gcm_profile_service.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "components/offline_pages/features/features.h"
#include "components/signin/core/browser/profile_identity_provider.h"
#include "components/signin/core/browser/signin_manager.h"
#include "content/public/browser/browser_thread.h"
......@@ -26,6 +26,12 @@
#include "components/gcm_driver/gcm_client_factory.h"
#endif
#if BUILDFLAG(ENABLE_OFFLINE_PAGES)
#include "chrome/browser/offline_pages/prefetch/prefetch_service_factory.h"
#include "components/offline_pages/core/prefetch/prefetch_gcm_app_handler.h"
#include "components/offline_pages/core/prefetch/prefetch_service.h"
#endif
namespace gcm {
// static
......@@ -53,6 +59,9 @@ GCMProfileServiceFactory::GCMProfileServiceFactory()
#if !defined(OS_ANDROID)
DependsOn(LoginUIServiceFactory::GetInstance());
#endif
#if BUILDFLAG(ENABLE_OFFLINE_PAGES)
DependsOn(offline_pages::PrefetchServiceFactory::GetInstance());
#endif // BUILDFLAG(ENABLE_OFFLINE_PAGES)
}
GCMProfileServiceFactory::~GCMProfileServiceFactory() {
......@@ -67,10 +76,12 @@ KeyedService* GCMProfileServiceFactory::BuildServiceInstanceFor(
base::CreateSequencedTaskRunnerWithTraits(
{base::MayBlock(), base::TaskPriority::BACKGROUND,
base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}));
std::unique_ptr<GCMProfileService> service = nullptr;
#if defined(OS_ANDROID)
return new GCMProfileService(profile->GetPath(), blocking_task_runner);
service = base::WrapUnique(
new GCMProfileService(profile->GetPath(), blocking_task_runner));
#else
return new GCMProfileService(
service = base::WrapUnique(new GCMProfileService(
profile->GetPrefs(), profile->GetPath(), profile->GetRequestContext(),
chrome::GetChannel(),
gcm::GetProductCategoryForSubtypes(profile->GetPrefs()),
......@@ -83,8 +94,20 @@ KeyedService* GCMProfileServiceFactory::BuildServiceInstanceFor(
content::BrowserThread::UI),
content::BrowserThread::GetTaskRunnerForThread(
content::BrowserThread::IO),
blocking_task_runner);
blocking_task_runner));
#endif
#if BUILDFLAG(ENABLE_OFFLINE_PAGES)
offline_pages::PrefetchService* prefetch_service =
offline_pages::PrefetchServiceFactory::GetForBrowserContext(context);
if (prefetch_service != nullptr) {
offline_pages::PrefetchGCMHandler* prefetch_gcm_handler =
prefetch_service->GetPrefetchGCMHandler();
service->driver()->AddAppHandler(prefetch_gcm_handler->GetAppId(),
prefetch_gcm_handler->AsGCMAppHandler());
}
#endif // BUILDFLAG(ENABLE_OFFLINE_PAGES)
return service.release();
}
content::BrowserContext* GCMProfileServiceFactory::GetBrowserContextToUse(
......
......@@ -47,6 +47,7 @@
#include "components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.h"
#include "components/ntp_snippets/sessions/tab_delegate_sync_adapter.h"
#include "components/ntp_snippets/user_classifier.h"
#include "components/offline_pages/features/features.h"
#include "components/prefs/pref_service.h"
#include "components/safe_json/safe_json_parser.h"
#include "components/signin/core/browser/profile_oauth2_token_service.h"
......@@ -62,30 +63,25 @@
#if defined(OS_ANDROID)
#include "chrome/browser/android/chrome_feature_list.h"
#include "chrome/browser/android/ntp/ntp_snippets_launcher.h"
#include "chrome/browser/android/offline_pages/offline_page_model_factory.h"
#include "chrome/browser/android/offline_pages/request_coordinator_factory.h"
#include "chrome/browser/download/download_core_service.h"
#include "chrome/browser/download/download_core_service_factory.h"
#include "chrome/browser/download/download_history.h"
#include "chrome/browser/ntp_snippets/download_suggestions_provider.h"
#include "components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.h"
#include "components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.h"
#include "components/offline_pages/content/suggested_articles_observer.h"
#include "components/physical_web/data_source/physical_web_data_source.h"
#endif
#if BUILDFLAG(ENABLE_OFFLINE_PAGES)
#include "chrome/browser/android/offline_pages/offline_page_model_factory.h"
#include "chrome/browser/android/offline_pages/request_coordinator_factory.h"
#include "chrome/browser/offline_pages/prefetch/prefetch_service_factory.h"
#include "components/ntp_snippets/offline_pages/recent_tab_suggestions_provider.h"
#include "components/offline_pages/core/background/request_coordinator.h"
#include "components/offline_pages/core/offline_page_feature.h"
#include "components/offline_pages/core/offline_page_model.h"
#include "components/offline_pages/core/prefetch/suggested_articles_observer.h"
#include "components/offline_pages/core/recent_tabs/recent_tabs_ui_adapter_delegate.h"
#include "components/physical_web/data_source/physical_web_data_source.h"
using content::DownloadManager;
using ntp_snippets::PhysicalWebPageSuggestionsProvider;
using ntp_snippets::RecentTabSuggestionsProvider;
using offline_pages::OfflinePageModel;
using offline_pages::RequestCoordinator;
using offline_pages::OfflinePageModelFactory;
using offline_pages::RequestCoordinatorFactory;
using physical_web::PhysicalWebDataSource;
#endif // OS_ANDROID
#endif
using bookmarks::BookmarkModel;
using content::BrowserThread;
......@@ -108,6 +104,20 @@ using suggestions::ImageDecoderImpl;
using syncer::SyncService;
using translate::LanguageModel;
#if defined(OS_ANDROID)
using content::DownloadManager;
using ntp_snippets::PhysicalWebPageSuggestionsProvider;
using physical_web::PhysicalWebDataSource;
#endif // OS_ANDROID
#if BUILDFLAG(ENABLE_OFFLINE_PAGES)
using ntp_snippets::RecentTabSuggestionsProvider;
using offline_pages::OfflinePageModel;
using offline_pages::RequestCoordinator;
using offline_pages::OfflinePageModelFactory;
using offline_pages::RequestCoordinatorFactory;
#endif // BUILDFLAG(ENABLE_OFFLINE_PAGES)
// For now, ContentSuggestionsService must only be instantiated on Android.
// See also crbug.com/688366.
#if defined(OS_ANDROID)
......@@ -130,7 +140,7 @@ bool IsChromeHomeEnabled() {
#endif
}
#if defined(OS_ANDROID)
#if BUILDFLAG(ENABLE_OFFLINE_PAGES)
bool IsRecentTabProviderEnabled() {
return base::FeatureList::IsEnabled(
......@@ -151,6 +161,10 @@ void RegisterRecentTabProvider(OfflinePageModel* offline_page_model,
service->RegisterProvider(std::move(provider));
}
#endif // BUILDFLAG(ENABLE_OFFLINE_PAGES)
#if defined(OS_ANDROID)
void RegisterDownloadsProvider(OfflinePageModel* offline_page_model,
DownloadManager* download_manager,
DownloadHistory* download_history,
......@@ -285,9 +299,10 @@ ContentSuggestionsServiceFactory::ContentSuggestionsServiceFactory()
DependsOn(BookmarkModelFactory::GetInstance());
DependsOn(HistoryServiceFactory::GetInstance());
DependsOn(LargeIconServiceFactory::GetInstance());
#if defined(OS_ANDROID)
#if BUILDFLAG(ENABLE_OFFLINE_PAGES)
DependsOn(OfflinePageModelFactory::GetInstance());
#endif // OS_ANDROID
DependsOn(offline_pages::PrefetchServiceFactory::GetInstance());
#endif // BUILDFLAG(ENABLE_OFFLINE_PAGES)
DependsOn(ProfileOAuth2TokenServiceFactory::GetInstance());
DependsOn(ProfileSyncServiceFactory::GetInstance());
DependsOn(SigninManagerFactory::GetInstance());
......@@ -332,7 +347,7 @@ KeyedService* ContentSuggestionsServiceFactory::BuildServiceInstanceFor(
pref_service, std::move(category_ranker), std::move(user_classifier),
std::move(scheduler));
#if defined(OS_ANDROID)
#if BUILDFLAG(ENABLE_OFFLINE_PAGES)
OfflinePageModel* offline_page_model =
OfflinePageModelFactory::GetForBrowserContext(profile);
if (IsRecentTabProviderEnabled()) {
......@@ -342,6 +357,12 @@ KeyedService* ContentSuggestionsServiceFactory::BuildServiceInstanceFor(
pref_service);
}
offline_pages::PrefetchService* prefetch_service =
offline_pages::PrefetchServiceFactory::GetForBrowserContext(profile);
prefetch_service->ObserveContentSuggestionsService(service);
#endif // BUILDFLAG(ENABLE_OFFLINE_PAGES)
#if defined(OS_ANDROID)
bool show_asset_downloads =
!IsChromeHomeEnabled() &&
base::FeatureList::IsEnabled(features::kAssetDownloadSuggestionsFeature);
......@@ -361,9 +382,6 @@ KeyedService* ContentSuggestionsServiceFactory::BuildServiceInstanceFor(
show_asset_downloads ? download_manager : nullptr, download_history,
service, pref_service);
}
offline_pages::SuggestedArticlesObserver::ObserveContentSuggestionsService(
profile, service);
#endif // OS_ANDROID
// |bookmark_model| can be null in tests.
......
......@@ -2,10 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/offline_pages/content/prefetch_service_factory.h"
#include "chrome/browser/offline_pages/prefetch/prefetch_service_factory.h"
#include "base/memory/ptr_util.h"
#include "base/memory/singleton.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "components/offline_pages/core/prefetch/prefetch_gcm_app_handler.h"
#include "components/offline_pages/core/prefetch/prefetch_service_impl.h"
#include "content/public/browser/browser_context.h"
......@@ -15,7 +17,6 @@ PrefetchServiceFactory::PrefetchServiceFactory()
: BrowserContextKeyedServiceFactory(
"OfflinePagePrefetchService",
BrowserContextDependencyManager::GetInstance()) {}
// static
PrefetchServiceFactory* PrefetchServiceFactory::GetInstance() {
return base::Singleton<PrefetchServiceFactory>::get();
......@@ -30,7 +31,7 @@ PrefetchService* PrefetchServiceFactory::GetForBrowserContext(
KeyedService* PrefetchServiceFactory::BuildServiceInstanceFor(
content::BrowserContext* context) const {
return new PrefetchServiceImpl();
return new PrefetchServiceImpl(base::MakeUnique<PrefetchGCMAppHandler>());
}
} // namespace offline_pages
......@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_OFFLINE_PAGES_CONTENT_PREFETCH_SERVICE_FACTORY_H_
#define COMPONENTS_OFFLINE_PAGES_CONTENT_PREFETCH_SERVICE_FACTORY_H_
#ifndef CHROME_BROWSER_OFFLINE_PAGES_PREFETCH_PREFETCH_SERVICE_FACTORY_H_
#define CHROME_BROWSER_OFFLINE_PAGES_PREFETCH_PREFETCH_SERVICE_FACTORY_H_
#include "base/macros.h"
#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
......@@ -40,4 +40,4 @@ class PrefetchServiceFactory : public BrowserContextKeyedServiceFactory {
} // namespace offline_pages
#endif // COMPONENTS_OFFLINE_PAGES_CONTENT_PREFETCH_SERVICE_FACTORY_H_
#endif // CHROME_BROWSER_OFFLINE_PAGES_PREFETCH_PREFETCH_SERVICE_FACTORY_H_
......@@ -195,7 +195,6 @@ test("components_unittests") {
"//components/link_header_util:unit_tests",
"//components/navigation_interception:unit_tests",
"//components/network_hints/renderer:unit_tests",
"//components/offline_pages/content:unit_tests",
"//components/offline_pages/content/background_loader:unit_tests",
"//components/offline_pages/core:unit_tests",
"//components/offline_pages/core/background:unit_tests",
......
......@@ -15,7 +15,6 @@
#include "base/observer_list.h"
#include "base/optional.h"
#include "base/scoped_observer.h"
#include "base/supports_user_data.h"
#include "base/task/cancelable_task_tracker.h"
#include "base/time/time.h"
#include "components/history/core/browser/history_service.h"
......@@ -48,7 +47,6 @@ class RemoteSuggestionsProvider;
// Retrieves suggestions from a number of ContentSuggestionsProviders and serves
// them grouped into categories. There can be at most one provider per category.
class ContentSuggestionsService : public KeyedService,
public base::SupportsUserData,
public ContentSuggestionsProvider::Observer,
public SigninManagerBase::Observer,
public history::HistoryServiceObserver {
......
# 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.
if (is_android) {
import("//build/config/android/rules.gni")
}
static_library("content") {
sources = [
"prefetch_service_factory.cc",
"prefetch_service_factory.h",
"suggested_articles_observer.cc",
"suggested_articles_observer.h",
]
deps = [
"//base",
"//components/keyed_service/content",
"//components/ntp_snippets",
"//components/offline_pages/core",
"//components/offline_pages/core:switches",
"//components/offline_pages/core/prefetch",
"//content/public/browser",
]
}
source_set("unit_tests") {
testonly = true
sources = [
"suggested_articles_observer_unittest.cc",
]
deps = [
":content",
"//base",
"//base/test:test_support",
"//components/offline_pages/core",
"//components/offline_pages/core:test_support",
"//components/offline_pages/core/prefetch",
"//content/test:test_support",
"//testing/gtest",
"//url",
]
}
include_rules = [
"+components/keyed_service/content",
"+components/ntp_snippets",
"+content/public/browser",
"+content/public/test",
]
include_rules = [
"+components/keyed_service",
"+components/gcm_driver",
"+components/ntp_snippets",
"+components/version_info",
"+net",
"+sql",
......
......@@ -16,6 +16,9 @@ static_library("prefetch") {
"prefetch_dispatcher.h",
"prefetch_dispatcher_impl.cc",
"prefetch_dispatcher_impl.h",
"prefetch_gcm_app_handler.cc",
"prefetch_gcm_app_handler.h",
"prefetch_gcm_handler.h",
"prefetch_item.cc",
"prefetch_item.h",
"prefetch_proto_utils.cc",
......@@ -27,6 +30,8 @@ static_library("prefetch") {
"prefetch_service_impl.h",
"prefetch_types.cc",
"prefetch_types.h",
"suggested_articles_observer.cc",
"suggested_articles_observer.h",
]
public_deps = [
......@@ -34,8 +39,12 @@ static_library("prefetch") {
]
deps = [
"//base",
"//components/gcm_driver",
"//components/gcm_driver/common",
"//components/keyed_service/core",
"//components/ntp_snippets",
"//components/offline_pages/core",
"//components/offline_pages/core:switches",
"//net:net",
"//url",
]
......@@ -62,11 +71,13 @@ source_set("unit_tests") {
"prefetch_request_operation_response_unittest.cc",
"prefetch_request_test_base.cc",
"prefetch_request_test_base.h",
"suggested_articles_observer_unittest.cc",
]
deps = [
":prefetch",
"//components/offline_pages/core",
"//components/offline_pages/core:test_support",
"//net:test_support",
"//testing/gmock",
"//testing/gtest",
......
// 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 "components/offline_pages/core/prefetch/prefetch_gcm_app_handler.h"
#include "base/memory/ptr_util.h"
#include "components/offline_pages/core/prefetch/prefetch_service.h"
namespace offline_pages {
namespace {
const char kPrefetchingOfflinePagesAppId[] =
"com.google.chrome.OfflinePagePrefetch";
}
PrefetchGCMAppHandler::PrefetchGCMAppHandler() {}
PrefetchGCMAppHandler::~PrefetchGCMAppHandler() = default;
void PrefetchGCMAppHandler::ShutdownHandler() {
NOTIMPLEMENTED();
}
void PrefetchGCMAppHandler::OnStoreReset() {
NOTIMPLEMENTED();
}
void PrefetchGCMAppHandler::OnMessage(const std::string& app_id,
const gcm::IncomingMessage& message) {
NOTIMPLEMENTED();
}
void PrefetchGCMAppHandler::OnMessagesDeleted(const std::string& app_id) {
NOTIMPLEMENTED();
}
void PrefetchGCMAppHandler::OnSendError(
const std::string& app_id,
const gcm::GCMClient::SendErrorDetails& send_error_details) {
NOTIMPLEMENTED();
}
void PrefetchGCMAppHandler::OnSendAcknowledged(const std::string& app_id,
const std::string& message_id) {
NOTIMPLEMENTED();
}
bool PrefetchGCMAppHandler::CanHandle(const std::string& app_id) const {
return app_id == GetAppId();
}
gcm::GCMAppHandler* PrefetchGCMAppHandler::AsGCMAppHandler() {
return (gcm::GCMAppHandler*)this;
}
std::string PrefetchGCMAppHandler::GetAppId() const {
return kPrefetchingOfflinePagesAppId;
}
} // namespace offline_pages
// 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.
#ifndef COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_PREFETCH_GCM_APP_HANDLER_H_
#define COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_PREFETCH_GCM_APP_HANDLER_H_
#include <string>
#include "components/gcm_driver/common/gcm_messages.h"
#include "components/gcm_driver/gcm_app_handler.h"
#include "components/gcm_driver/gcm_driver.h"
#include "components/gcm_driver/gcm_profile_service.h"
#include "components/offline_pages/core/prefetch/prefetch_gcm_handler.h"
#include "url/gurl.h"
namespace offline_pages {
// Receives GCM messages and other channel status messages on behalf of the
// prefetch system.
class PrefetchGCMAppHandler : public gcm::GCMAppHandler,
public PrefetchGCMHandler {
public:
PrefetchGCMAppHandler();
~PrefetchGCMAppHandler() override;
// gcm::GCMAppHandler implementation.
void ShutdownHandler() override;
void OnStoreReset() override;
void OnMessage(const std::string& app_id,
const gcm::IncomingMessage& message) override;
void OnMessagesDeleted(const std::string& app_id) override;
void OnSendError(
const std::string& app_id,
const gcm::GCMClient::SendErrorDetails& send_error_details) override;
void OnSendAcknowledged(const std::string& app_id,
const std::string& message_id) override;
bool CanHandle(const std::string& app_id) const override;
// offline_pages::PrefetchGCMHandler implementation.
gcm::GCMAppHandler* AsGCMAppHandler() override;
std::string GetAppId() const override;
private:
DISALLOW_COPY_AND_ASSIGN(PrefetchGCMAppHandler);
};
} // namespace offline_pages
#endif // COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_PREFETCH_GCM_APP_HANDLER_H_
// 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.
#ifndef COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_PREFETCH_GCM_HANDLER_H_
#define COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_PREFETCH_GCM_HANDLER_H_
#include <string>
namespace gcm {
class GCMAppHandler;
} // namespace gcm
namespace offline_pages {
class PrefetchGCMHandler;
// Main class and entry point for the Offline Pages Prefetching feature, that
// controls the lifetime of all major subcomponents of the prefetching system.
class PrefetchGCMHandler {
public:
virtual ~PrefetchGCMHandler() = default;
// Returns the GCMAppHandler for this object. Can return |nullptr| in unit
// tests.
virtual gcm::GCMAppHandler* AsGCMAppHandler() = 0;
// The app ID to register with at the GCM layer.
virtual std::string GetAppId() const = 0;
// TODO(dewittj): Add methods for acquiring an Instance ID token to this
// interface.
};
} // namespace offline_pages
#endif // COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_PREFETCH_GCM_HANDLER_H_
......@@ -7,9 +7,14 @@
#include "components/keyed_service/core/keyed_service.h"
namespace ntp_snippets {
class ContentSuggestionsService;
}
namespace offline_pages {
class PrefetchDispatcher;
class PrefetchGCMHandler;
// Main class and entry point for the Offline Pages Prefetching feature, that
// controls the lifetime of all major subcomponents of the prefetching system.
......@@ -18,6 +23,12 @@ class PrefetchService : public KeyedService {
~PrefetchService() override = default;
virtual PrefetchDispatcher* GetDispatcher() = 0;
virtual PrefetchGCMHandler* GetPrefetchGCMHandler() = 0;
// Called at construction of the ContentSuggestionsService to begin observing
// events related to incoming articles.
virtual void ObserveContentSuggestionsService(
ntp_snippets::ContentSuggestionsService* service) = 0;
};
} // namespace offline_pages
......
......@@ -11,14 +11,26 @@
namespace offline_pages {
PrefetchServiceImpl::PrefetchServiceImpl()
: dispatcher_(base::MakeUnique<PrefetchDispatcherImpl>()) {}
PrefetchServiceImpl::PrefetchServiceImpl(
std::unique_ptr<PrefetchGCMHandler> gcm_handler)
: gcm_handler_(std::move(gcm_handler)),
dispatcher_(base::MakeUnique<PrefetchDispatcherImpl>()) {}
PrefetchServiceImpl::~PrefetchServiceImpl() = default;
PrefetchGCMHandler* PrefetchServiceImpl::GetPrefetchGCMHandler() {
return gcm_handler_.get();
}
PrefetchDispatcher* PrefetchServiceImpl::GetDispatcher() {
return dispatcher_.get();
};
}
void PrefetchServiceImpl::ObserveContentSuggestionsService(
ntp_snippets::ContentSuggestionsService* service) {
suggested_articles_observer_ =
base::MakeUnique<SuggestedArticlesObserver>(service, this);
}
void PrefetchServiceImpl::Shutdown() {}
......
......@@ -8,22 +8,33 @@
#include <memory>
#include "base/macros.h"
#include "components/offline_pages/core/prefetch/prefetch_gcm_handler.h"
#include "components/offline_pages/core/prefetch/prefetch_service.h"
#include "components/offline_pages/core/prefetch/suggested_articles_observer.h"
namespace ntp_snippets {
class ContentSuggestionsService;
}
namespace offline_pages {
class PrefetchServiceImpl : public PrefetchService {
public:
PrefetchServiceImpl();
PrefetchServiceImpl(std::unique_ptr<PrefetchGCMHandler> gcm_handler);
~PrefetchServiceImpl() override;
// PrefetchService implementation:
void ObserveContentSuggestionsService(
ntp_snippets::ContentSuggestionsService* service) override;
PrefetchDispatcher* GetDispatcher() override;
PrefetchGCMHandler* GetPrefetchGCMHandler() override;
// KeyedService implementation:
void Shutdown() override;
private:
std::unique_ptr<SuggestedArticlesObserver> suggested_articles_observer_;
std::unique_ptr<PrefetchGCMHandler> gcm_handler_;
std::unique_ptr<PrefetchDispatcher> dispatcher_;
DISALLOW_COPY_AND_ASSIGN(PrefetchServiceImpl);
......
// 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 "components/offline_pages/core/prefetch/prefetch_service_impl.h"
#include "components/offline_pages/core/client_namespace_constants.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
namespace offline_pages {
TEST(PrefetchServiceTest, ServiceDoesNotCrash) {
PrefetchServiceImpl service(nullptr);
service.AddCandidatePrefetchURLs(std::vector<PrefetchService::PrefetchURL>());
service.RemoveAllUnprocessedPrefetchURLs(kSuggestedArticlesNamespace);
service.RemovePrefetchURLsByClientId({kSuggestedArticlesNamespace, "123"});
}
} // namespace offline_pages
......@@ -2,18 +2,18 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/offline_pages/content/suggested_articles_observer.h"
#include "components/offline_pages/core/prefetch/suggested_articles_observer.h"
#include <unordered_set>
#include "base/memory/ptr_util.h"
#include "components/ntp_snippets/category.h"
#include "components/ntp_snippets/category_status.h"
#include "components/offline_pages/content/prefetch_service_factory.h"
#include "components/offline_pages/core/client_namespace_constants.h"
#include "components/offline_pages/core/offline_page_feature.h"
#include "components/offline_pages/core/offline_page_item.h"
#include "components/offline_pages/core/prefetch/prefetch_dispatcher.h"
#include "components/offline_pages/core/prefetch/prefetch_service.h"
#include "components/offline_pages/core/prefetch/prefetch_service_impl.h"
using ntp_snippets::Category;
using ntp_snippets::ContentSuggestion;
......@@ -22,8 +22,6 @@ namespace offline_pages {
namespace {
int kOfflinePageSuggestedArticlesObserverUserDataKey;
const ntp_snippets::Category& ArticlesCategory() {
static ntp_snippets::Category articles =
Category::FromKnownCategory(ntp_snippets::KnownCategories::ARTICLES);
......@@ -34,57 +32,17 @@ ClientId CreateClientIDFromSuggestionId(const ContentSuggestion::ID& id) {
return ClientId(kSuggestedArticlesNamespace, id.id_within_category());
}
// The default delegate that contains external dependencies for the Offline Page
// Suggestions Observer. This is unused in tests, which implement their own
// Delegate.
class DefaultDelegate : public SuggestedArticlesObserver::Delegate {
public:
explicit DefaultDelegate(ntp_snippets::ContentSuggestionsService* service);
~DefaultDelegate() override = default;
const std::vector<ContentSuggestion>& GetSuggestions(
const Category& category) override;
PrefetchService* GetPrefetchService(
content::BrowserContext* context) override;
private:
ntp_snippets::ContentSuggestionsService* service_;
};
DefaultDelegate::DefaultDelegate(
ntp_snippets::ContentSuggestionsService* service)
: service_(service) {}
const std::vector<ContentSuggestion>& DefaultDelegate::GetSuggestions(
const Category& category) {
return service_->GetSuggestionsForCategory(category);
}
PrefetchService* DefaultDelegate::GetPrefetchService(
content::BrowserContext* context) {
return PrefetchServiceFactory::GetForBrowserContext(context);
}
} // namespace
// static
void SuggestedArticlesObserver::ObserveContentSuggestionsService(
content::BrowserContext* browser_context,
ntp_snippets::ContentSuggestionsService* service) {
if (!offline_pages::IsPrefetchingOfflinePagesEnabled())
return;
auto suggestions_observer = base::MakeUnique<SuggestedArticlesObserver>(
browser_context, base::MakeUnique<DefaultDelegate>(service));
service->AddObserver(suggestions_observer.get());
service->SetUserData(&kOfflinePageSuggestedArticlesObserverUserDataKey,
std::move(suggestions_observer));
}
SuggestedArticlesObserver::SuggestedArticlesObserver(
content::BrowserContext* browser_context,
std::unique_ptr<Delegate> delegate)
: browser_context_(browser_context), delegate_(std::move(delegate)) {}
ntp_snippets::ContentSuggestionsService* content_suggestions_service,
PrefetchService* prefetch_service)
: content_suggestions_service_(content_suggestions_service),
prefetch_service_(prefetch_service) {
// The content suggestions service can be |nullptr| in tests.
if (content_suggestions_service_)
content_suggestions_service_->AddObserver(this);
}
SuggestedArticlesObserver::~SuggestedArticlesObserver() = default;
......@@ -97,7 +55,9 @@ void SuggestedArticlesObserver::OnNewSuggestions(Category category) {
}
const std::vector<ContentSuggestion>& suggestions =
delegate_->GetSuggestions(ArticlesCategory());
test_articles_ ? *test_articles_
: content_suggestions_service_->GetSuggestionsForCategory(
ArticlesCategory());
if (suggestions.empty())
return;
......@@ -107,13 +67,7 @@ void SuggestedArticlesObserver::OnNewSuggestions(Category category) {
{CreateClientIDFromSuggestionId(suggestion.id()), suggestion.url()});
}
PrefetchService* service = delegate_->GetPrefetchService(browser_context_);
if (service == nullptr) {
DVLOG(1) << "PrefetchService unavailable to the "
"SuggestedArticlesObserver.";
return;
}
service->GetDispatcher()->AddCandidatePrefetchURLs(prefetch_urls);
prefetch_service_->GetDispatcher()->AddCandidatePrefetchURLs(prefetch_urls);
}
void SuggestedArticlesObserver::OnCategoryStatusChanged(
......@@ -128,37 +82,19 @@ void SuggestedArticlesObserver::OnCategoryStatusChanged(
ntp_snippets::CategoryStatus::CATEGORY_EXPLICITLY_DISABLED ||
category_status_ ==
ntp_snippets::CategoryStatus::ALL_SUGGESTIONS_EXPLICITLY_DISABLED) {
PrefetchService* service = delegate_->GetPrefetchService(browser_context_);
if (service == nullptr) {
DVLOG(1) << "PrefetchService unavailable to the "
"SuggestedArticlesObserver.";
return;
}
service->GetDispatcher()->RemoveAllUnprocessedPrefetchURLs(
prefetch_service_->GetDispatcher()->RemoveAllUnprocessedPrefetchURLs(
kSuggestedArticlesNamespace);
}
}
void SuggestedArticlesObserver::OnSuggestionInvalidated(
const ContentSuggestion::ID& suggestion_id) {
PrefetchService* service = delegate_->GetPrefetchService(browser_context_);
if (service == nullptr) {
DVLOG(1) << "PrefetchService unavailable to the "
"SuggestedArticlesObserver.";
return;
}
service->GetDispatcher()->RemovePrefetchURLsByClientId(
prefetch_service_->GetDispatcher()->RemovePrefetchURLsByClientId(
CreateClientIDFromSuggestionId(suggestion_id));
}
void SuggestedArticlesObserver::OnFullRefreshRequired() {
PrefetchService* service = delegate_->GetPrefetchService(browser_context_);
if (service == nullptr) {
DVLOG(1) << "PrefetchService unavailable to the "
"SuggestedArticlesObserver.";
return;
}
service->GetDispatcher()->RemoveAllUnprocessedPrefetchURLs(
prefetch_service_->GetDispatcher()->RemoveAllUnprocessedPrefetchURLs(
kSuggestedArticlesNamespace);
OnNewSuggestions(ArticlesCategory());
}
......@@ -167,4 +103,13 @@ void SuggestedArticlesObserver::ContentSuggestionsServiceShutdown() {
// No need to do anything here, we will just stop getting events.
}
std::vector<ntp_snippets::ContentSuggestion>*
SuggestedArticlesObserver::GetTestingArticles() {
if (!test_articles_) {
test_articles_ =
base::MakeUnique<std::vector<ntp_snippets::ContentSuggestion>>();
}
return test_articles_.get();
}
} // namespace offline_pages
......@@ -2,58 +2,33 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_OFFLINE_PAGES_CONTENT_SUGGESTED_ARTICLES_OBSERVER_H_
#define COMPONENTS_OFFLINE_PAGES_CONTENT_SUGGESTED_ARTICLES_OBSERVER_H_
#ifndef COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_SUGGESTED_ARTICLES_OBSERVER_H_
#define COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_SUGGESTED_ARTICLES_OBSERVER_H_
#include <memory>
#include "base/callback.h"
#include "base/memory/weak_ptr.h"
#include "components/ntp_snippets/content_suggestions_service.h"
namespace content {
class BrowserContext;
} // namespace content
#include "components/offline_pages/core/prefetch/prefetch_service.h"
namespace ntp_snippets {
class Category;
}
namespace offline_pages {
class PrefetchService;
// Observes the ContentSuggestionsService, listening for new suggestions in the
// ARTICLES category. When those suggestions arrive, it then forwards them to
// the Prefetch Service, which does not know about Content Suggestions
// specifically.
class SuggestedArticlesObserver
: public ntp_snippets::ContentSuggestionsService::Observer,
public base::SupportsUserData::Data {
: public ntp_snippets::ContentSuggestionsService::Observer {
public:
// Delegate exists to allow for dependency injection in unit tests.
// SuggestedArticlesObserver implements its own delegate, |DefaultDelegate| in
// the .cc file that forwards to the ContentSuggestionsService and the
// PrefetchServiceFactory. Code inside |DefaultDelegate| should be as simple
// as possible, since it will only be covered by instrumentation/browser
// tests.
class Delegate {
public:
virtual const std::vector<ntp_snippets::ContentSuggestion>& GetSuggestions(
const ntp_snippets::Category& category) = 0;
virtual PrefetchService* GetPrefetchService(
content::BrowserContext* context) = 0;
virtual ~Delegate() = default;
};
// This API creates a new SuggestedArticlesObserver and adds it as an
// observer to the ContentSuggestionsService provided. Its lifetime is
// managed by the ContentSuggestionsService.
static void ObserveContentSuggestionsService(
content::BrowserContext* browser_context,
ntp_snippets::ContentSuggestionsService* service);
SuggestedArticlesObserver(content::BrowserContext* browser_context,
std::unique_ptr<Delegate> delegate);
SuggestedArticlesObserver(
// This can be |nullptr| in test.
ntp_snippets::ContentSuggestionsService* content_suggestions_service,
PrefetchService* prefetch_service);
~SuggestedArticlesObserver() override;
// ContentSuggestionsService::Observer overrides.
......@@ -66,15 +41,27 @@ class SuggestedArticlesObserver
void OnFullRefreshRequired() override;
void ContentSuggestionsServiceShutdown() override;
// Returns a pointer to the list of testing articles. If there is no such
// list, allocates one before returning the list. The observer owns the list.
std::vector<ntp_snippets::ContentSuggestion>* GetTestingArticles();
private:
content::BrowserContext* browser_context_;
// Unowned, only used when we are called by observer methods (so the
// pointer will be valid).
ntp_snippets::ContentSuggestionsService* content_suggestions_service_;
// This class is owned by the prefetch service.
PrefetchService* prefetch_service_;
// Normally null, but can be set in tests to override the default behavior.
std::unique_ptr<std::vector<ntp_snippets::ContentSuggestion>> test_articles_;
ntp_snippets::CategoryStatus category_status_ =
ntp_snippets::CategoryStatus::INITIALIZING;
std::unique_ptr<Delegate> delegate_;
DISALLOW_COPY_AND_ASSIGN(SuggestedArticlesObserver);
};
} // namespace offline_pages
#endif // COMPONENTS_OFFLINE_PAGES_CONTENT_SUGGESTED_ARTICLES_OBSERVER_H_
#endif // COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_SUGGESTED_ARTICLES_OBSERVER_H_
......@@ -2,16 +2,16 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/offline_pages/content/suggested_articles_observer.h"
#include "components/offline_pages/core/prefetch/suggested_articles_observer.h"
#include "base/run_loop.h"
#include "base/test/test_simple_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "components/offline_pages/core/client_namespace_constants.h"
#include "components/offline_pages/core/prefetch/prefetch_dispatcher.h"
#include "components/offline_pages/core/prefetch/prefetch_gcm_app_handler.h"
#include "components/offline_pages/core/prefetch/prefetch_service.h"
#include "components/offline_pages/core/stub_offline_page_model.h"
#include "content/public/test/test_browser_context.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
......@@ -67,36 +67,13 @@ class TestingPrefetchService : public PrefetchService {
public:
TestingPrefetchService() = default;
PrefetchGCMHandler* GetPrefetchGCMHandler() override { return nullptr; }
PrefetchDispatcher* GetDispatcher() override { return &dispatcher; };
void ObserveContentSuggestionsService(
ntp_snippets::ContentSuggestionsService* content_suggestions_service)
override {}
TestingPrefetchDispatcher dispatcher;
};
class TestDelegate : public SuggestedArticlesObserver::Delegate {
public:
TestDelegate() = default;
~TestDelegate() override = default;
const std::vector<ContentSuggestion>& GetSuggestions(
const Category& category) override {
get_suggestions_count++;
return suggestions;
}
PrefetchService* GetPrefetchService(
content::BrowserContext* context) override {
return &prefetch_service;
}
TestingPrefetchService prefetch_service;
// Public for test manipulation.
std::vector<ContentSuggestion> suggestions;
// Signals that delegate was called.
int get_suggestions_count = 0;
};
} // namespace
class OfflinePageSuggestedArticlesObserverTest : public testing::Test {
......@@ -104,23 +81,13 @@ class OfflinePageSuggestedArticlesObserverTest : public testing::Test {
OfflinePageSuggestedArticlesObserverTest() = default;
void SetUp() override {
observer_ =
base::MakeUnique<SuggestedArticlesObserver>(&context_, MakeDelegate());
}
virtual std::unique_ptr<SuggestedArticlesObserver::Delegate> MakeDelegate() {
auto delegate_ptr = base::MakeUnique<TestDelegate>();
test_delegate_ = delegate_ptr.get();
return std::move(delegate_ptr);
observer_ = base::MakeUnique<SuggestedArticlesObserver>(
nullptr, test_prefetch_service());
}
SuggestedArticlesObserver* observer() { return observer_.get(); }
TestDelegate* test_delegate() { return test_delegate_; }
TestingPrefetchService* test_prefetch_service() {
return &(test_delegate()->prefetch_service);
}
TestingPrefetchService* test_prefetch_service() { return &prefetch_service_; }
TestingPrefetchDispatcher* test_prefetch_dispatcher() {
return &(test_prefetch_service()->dispatcher);
......@@ -129,36 +96,16 @@ class OfflinePageSuggestedArticlesObserverTest : public testing::Test {
protected:
Category category =
Category::FromKnownCategory(ntp_snippets::KnownCategories::ARTICLES);
content::TestBrowserContext context_;
private:
std::unique_ptr<SuggestedArticlesObserver> observer_;
TestDelegate* test_delegate_;
TestingPrefetchService prefetch_service_;
};
TEST_F(OfflinePageSuggestedArticlesObserverTest,
CallsDelegateOnNewSuggestions) {
// We should not do anything if the category is not loaded.
observer()->OnNewSuggestions(category);
EXPECT_EQ(0, test_delegate()->get_suggestions_count);
EXPECT_EQ(0, test_prefetch_dispatcher()->new_suggestions_count);
// Once the category becomes available, new suggestions should cause us to ask
// the delegate for suggestion URLs.
observer()->OnCategoryStatusChanged(category,
ntp_snippets::CategoryStatus::AVAILABLE);
observer()->OnNewSuggestions(category);
EXPECT_EQ(1, test_delegate()->get_suggestions_count);
// We expect that no pages were forwarded to the prefetch service since no
// pages were prepopulated.
EXPECT_EQ(0, test_prefetch_dispatcher()->new_suggestions_count);
}
TEST_F(OfflinePageSuggestedArticlesObserverTest,
ForwardsSuggestionsToPrefetchService) {
const GURL test_url_1("https://www.example.com/1");
test_delegate()->suggestions.push_back(
observer()->GetTestingArticles()->push_back(
ContentSuggestionFromTestURL(test_url_1));
observer()->OnCategoryStatusChanged(category,
......@@ -176,9 +123,9 @@ TEST_F(OfflinePageSuggestedArticlesObserverTest,
TEST_F(OfflinePageSuggestedArticlesObserverTest, RemovesAllOnBadStatus) {
const GURL test_url_1("https://www.example.com/1");
const GURL test_url_2("https://www.example.com/2");
test_delegate()->suggestions.push_back(
observer()->GetTestingArticles()->push_back(
ContentSuggestionFromTestURL(test_url_1));
test_delegate()->suggestions.push_back(
observer()->GetTestingArticles()->push_back(
ContentSuggestionFromTestURL(test_url_2));
observer()->OnCategoryStatusChanged(category,
......@@ -197,7 +144,7 @@ TEST_F(OfflinePageSuggestedArticlesObserverTest, RemovesAllOnBadStatus) {
TEST_F(OfflinePageSuggestedArticlesObserverTest, RemovesClientIdOnInvalidated) {
const GURL test_url_1("https://www.example.com/1");
test_delegate()->suggestions.push_back(
observer()->GetTestingArticles()->push_back(
ContentSuggestionFromTestURL(test_url_1));
observer()->OnCategoryStatusChanged(category,
ntp_snippets::CategoryStatus::AVAILABLE);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment