Commit 84895c02 authored by Dan Harrington's avatar Dan Harrington Committed by Commit Bot

Track when the auto-fetch in progress notification should be shown

Watch for navigations and request coordinator changes to determine when
the in-progress notification should be shown.

A follow-up CL will introduce an instrumentation test to supplement the
unit tests here.

Bug: 883486

RELAND: This is a reland for https://chromium-review.googlesource.com/c/1381233
Changes to OfflinePageBridge were removed.

TBR=petewil@chromium.org
  This is the same patch, but without the base CL. The base CL was unintentially
  submitted previously.

Change-Id: I8e6988edcc0e8ca810f99c1961c9cdb9f730ba40
Reviewed-on: https://chromium-review.googlesource.com/c/1406939
Commit-Queue: Dan H <harringtond@google.com>
Reviewed-by: default avatarDan H <harringtond@google.com>
Cr-Commit-Position: refs/heads/master@{#622047}
parent 2e5acea4
......@@ -12,60 +12,175 @@
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "components/offline_pages/core/auto_fetch.h"
#include "components/offline_pages/core/background/request_coordinator.h"
#include "components/offline_pages/core/client_id.h"
#include "url/gurl.h"
namespace content {
class WebContents;
class NavigationHandle;
} // namespace content
namespace offline_pages {
class SavePageRequest;
class RequestCoordinator;
// Cancels active auto fetch requests if a page loads.
class AutoFetchPageLoadWatcher : public RequestCoordinator::Observer {
// Manages showing the in-progress notification.
class AutoFetchNotifier {
public:
static void CreateForWebContents(content::WebContents* web_contents);
virtual ~AutoFetchNotifier() {}
// Ensures that the in-progress notification is showing with the appropriate
// request count.
virtual void NotifyInProgress(int in_flight_count) {}
// Update the request count if the in-progress notification is already
// showing. This won't trigger showing the notification if it's not already
// shown. If |in_flight_count| is 0, the notification will be hidden.
virtual void InProgressCountChanged(int in_flight_count) {}
};
explicit AutoFetchPageLoadWatcher(RequestCoordinator* request_coordinator);
~AutoFetchPageLoadWatcher() override;
// Types and functions internal to AutoFetchPageLoadWatcher. Included in the
// header for testing.
namespace auto_fetch_internal {
// RequestCoordinator::Observer methods. These keep
// |live_auto_fetch_requests_| in sync with the state of RequestCoordinator.
void OnAdded(const SavePageRequest& request) override;
void OnCompleted(const SavePageRequest& request,
RequestNotifier::BackgroundSavePageResult status) override;
void OnChanged(const SavePageRequest& request) override {}
void OnNetworkProgress(const SavePageRequest& request,
int64_t received_bytes) override {}
// Information about an Android browser tab.
struct TabInfo {
int android_tab_id = 0;
GURL current_url;
};
protected:
class NavigationObserver;
// Interface to Android tabs used by |AutoFetchPageLoadWatcher|. This is the
// real implementation, methods are virtual for testing only.
class AndroidTabFinder {
public:
virtual ~AndroidTabFinder();
// Returns a mapping of Android tab ID to TabInfo.
virtual std::map<int, TabInfo> FindAndroidTabs(
std::vector<int> android_tab_ids);
virtual base::Optional<TabInfo> FindNavigationTab(
content::WebContents* web_contents);
};
// Information about an auto-fetch |SavePageRequest|.
struct RequestInfo {
int64_t request_id;
GURL url;
SavePageRequest::AutoFetchNotificationState notification_state;
auto_fetch::ClientIdMetadata metadata;
};
base::Optional<RequestInfo> MakeRequestInfo(const SavePageRequest& request);
// |AutoFetchPageLoadWatcher|'s more unit-testable internal implementation.
// This class was designed to have few dependencies to make testing more
// tractable. Events are communicated to |InternalImpl| through its public
// member functions, and functions are injected through |AutoFetchNotifier|,
// |Delegate|, and |AndroidTabFinder|.
class InternalImpl {
public:
// Injected functions, implemented by |AutoFetchPageLoadWatcher|.
// We need this because we can't call these functions directly.
class Delegate {
public:
virtual ~Delegate() {}
// Sets the notification state of a request to
// |SavePageRequest::AutoFetchNotificationState::kShown|. Results in a call
// to |SetNotificationStateComplete|.
virtual void SetNotificationStateToShown(int64_t request_id) {}
// Removes all |SavePageRequest|s with the given IDs.
virtual void RemoveRequests(const std::vector<int64_t>& request_ids) {}
};
InternalImpl(AutoFetchNotifier* notifier,
Delegate* delegate,
std::unique_ptr<AndroidTabFinder> tab_finder);
~InternalImpl();
// Request state change methods.
void RequestListInitialized(std::vector<RequestInfo> requests);
void RequestAdded(RequestInfo info);
void RequestRemoved(RequestInfo info);
void SetNotificationStateComplete(int64_t request_id, bool success);
// Navigation methods.
void SuccessfulPageNavigation(const GURL& url);
void NavigationFrom(const GURL& previous_url,
content::WebContents* web_contents);
base::WeakPtr<InternalImpl> GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
private:
void SetNotificationStateToShown(int64_t request_id);
AutoFetchNotifier* notifier_;
Delegate* delegate_;
std::unique_ptr<AndroidTabFinder> tab_finder_;
std::vector<RequestInfo> requests_;
// Tracks whether |RequestListInitialized| has been called. If false,
// |RequestAdded| and |RequestRemoved| should be ignored, as per the
// documentation in |RequestCoordinator::Observer|.
bool requests_initialized_ = false;
std::vector<GURL> pages_loaded_before_observer_ready_;
// Virtual for testing only.
virtual void RemoveRequests(const std::vector<int64_t>& request_ids);
base::WeakPtrFactory<InternalImpl> weak_ptr_factory_{this};
};
// Called when navigation completes. Triggers cancellation of any
// in-flight auto fetch requests that match a successful navigation.
void HandlePageNavigation(const GURL& url);
} // namespace auto_fetch_internal
// Watches for page loads and |RequestCoordinator| requests.
// Given an active auto-fetch request for <tab, URL>:
// - If URL is loaded successfully on tab, cancel the auto-fetch request.
// - If a different URL is loaded successfully on tab, trigger the in-progress
// notification.
// - If an auto-fetch request is removed, update the in-progress notification's
// displayed request count.
//
// Implementation note:
// This class simply observes events and passes them down to |InternalImpl|
// for processing. All code here is run on the UI thread.
class AutoFetchPageLoadWatcher
: public RequestCoordinator::Observer,
public auto_fetch_internal::InternalImpl::Delegate {
public:
using AndroidTabFinder = auto_fetch_internal::AndroidTabFinder;
void ObserverInitialize(
std::vector<std::unique_ptr<SavePageRequest>> all_requests);
static void CreateForWebContents(content::WebContents* web_contents);
offline_pages::RequestCoordinator* GetRequestCoordinator();
AutoFetchPageLoadWatcher(AutoFetchNotifier* notifier,
RequestCoordinator* request_coordinator,
std::unique_ptr<AndroidTabFinder> tab_finder);
// Whether ObserverInitialize has been called.
bool observer_ready_ = false;
~AutoFetchPageLoadWatcher() override;
RequestCoordinator* request_coordinator_;
std::vector<GURL> pages_loaded_before_observer_ready_;
// Called when navigation completes, even on errors. This is only called
// once per navigation.
void HandleNavigation(content::NavigationHandle* navigation_handle);
private:
class NavigationObserver;
base::WeakPtr<AutoFetchPageLoadWatcher> GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
// This represents the set of auto fetch request IDs currently in the
// RequestCoordinator's queue, mapped by URL.
std::map<GURL, std::vector<int64_t>> live_auto_fetch_requests_;
void InitializeRequestList(
std::vector<std::unique_ptr<SavePageRequest>> requests);
// InternalImpl::Delegate.
void SetNotificationStateToShown(int64_t request_id) override;
void RemoveRequests(const std::vector<int64_t>& request_ids) override;
// RequestCoordinator::Observer.
void OnAdded(const SavePageRequest& request) override;
void OnCompleted(const SavePageRequest& request,
RequestNotifier::BackgroundSavePageResult status) override;
void OnChanged(const SavePageRequest& request) override {}
void OnNetworkProgress(const SavePageRequest& request,
int64_t received_bytes) override {}
RequestCoordinator* request_coordinator_; // Not owned.
auto_fetch_internal::InternalImpl impl_;
base::WeakPtrFactory<AutoFetchPageLoadWatcher> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(AutoFetchPageLoadWatcher);
......
......@@ -7,12 +7,9 @@
#include <string>
#include <utility>
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/optional.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "chrome/browser/offline_pages/request_coordinator_factory.h"
#include "components/offline_pages/core/auto_fetch.h"
......@@ -77,7 +74,11 @@ OfflinePageAutoFetcherService::OfflinePageAutoFetcherService(
RequestCoordinator* request_coordinator,
OfflinePageModel* offline_page_model,
Delegate* delegate)
: page_load_watcher_(request_coordinator),
: notifier_(std::make_unique<AutoFetchNotifier>()),
page_load_watcher_(
notifier_.get(),
request_coordinator,
std::make_unique<AutoFetchPageLoadWatcher::AndroidTabFinder>()),
request_coordinator_(request_coordinator),
offline_page_model_(offline_page_model),
delegate_(delegate) {
......@@ -159,6 +160,7 @@ void OfflinePageAutoFetcherService::TryScheduleStep2(
return;
}
}
// Finally, schedule a new request, and proceed to step 3.
RequestCoordinator::SavePageLaterParams params;
params.url = url;
......
......@@ -6,6 +6,7 @@
#define CHROME_BROWSER_OFFLINE_PAGES_ANDROID_OFFLINE_PAGE_AUTO_FETCHER_SERVICE_H_
#include <memory>
#include <queue>
#include <utility>
#include <vector>
......@@ -146,6 +147,7 @@ class OfflinePageAutoFetcherService : public KeyedService,
void AutoFetchComplete(const OfflinePageItem* page);
std::unique_ptr<AutoFetchNotifier> notifier_;
AutoFetchPageLoadWatcher page_load_watcher_;
RequestCoordinator* request_coordinator_;
OfflinePageModel* offline_page_model_;
......
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