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 @@ ...@@ -12,60 +12,175 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/weak_ptr.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/background/request_coordinator.h"
#include "components/offline_pages/core/client_id.h" #include "components/offline_pages/core/client_id.h"
#include "url/gurl.h" #include "url/gurl.h"
namespace content { namespace content {
class WebContents; class WebContents;
class NavigationHandle;
} // namespace content } // namespace content
namespace offline_pages { namespace offline_pages {
class SavePageRequest; class SavePageRequest;
class RequestCoordinator; class RequestCoordinator;
// Cancels active auto fetch requests if a page loads. // Manages showing the in-progress notification.
class AutoFetchPageLoadWatcher : public RequestCoordinator::Observer { class AutoFetchNotifier {
public: 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); // Types and functions internal to AutoFetchPageLoadWatcher. Included in the
~AutoFetchPageLoadWatcher() override; // header for testing.
namespace auto_fetch_internal {
// RequestCoordinator::Observer methods. These keep // Information about an Android browser tab.
// |live_auto_fetch_requests_| in sync with the state of RequestCoordinator. struct TabInfo {
void OnAdded(const SavePageRequest& request) override; int android_tab_id = 0;
void OnCompleted(const SavePageRequest& request, GURL current_url;
RequestNotifier::BackgroundSavePageResult status) override; };
void OnChanged(const SavePageRequest& request) override {}
void OnNetworkProgress(const SavePageRequest& request,
int64_t received_bytes) override {}
protected: // Interface to Android tabs used by |AutoFetchPageLoadWatcher|. This is the
class NavigationObserver; // 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. base::WeakPtrFactory<InternalImpl> weak_ptr_factory_{this};
virtual void RemoveRequests(const std::vector<int64_t>& request_ids); };
// Called when navigation completes. Triggers cancellation of any } // namespace auto_fetch_internal
// in-flight auto fetch requests that match a successful navigation.
void HandlePageNavigation(const GURL& url); // 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( static void CreateForWebContents(content::WebContents* web_contents);
std::vector<std::unique_ptr<SavePageRequest>> all_requests);
offline_pages::RequestCoordinator* GetRequestCoordinator(); AutoFetchPageLoadWatcher(AutoFetchNotifier* notifier,
RequestCoordinator* request_coordinator,
std::unique_ptr<AndroidTabFinder> tab_finder);
// Whether ObserverInitialize has been called. ~AutoFetchPageLoadWatcher() override;
bool observer_ready_ = false;
RequestCoordinator* request_coordinator_; // Called when navigation completes, even on errors. This is only called
std::vector<GURL> pages_loaded_before_observer_ready_; // 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 void InitializeRequestList(
// RequestCoordinator's queue, mapped by URL. std::vector<std::unique_ptr<SavePageRequest>> requests);
std::map<GURL, std::vector<int64_t>> live_auto_fetch_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}; base::WeakPtrFactory<AutoFetchPageLoadWatcher> weak_ptr_factory_{this};
DISALLOW_COPY_AND_ASSIGN(AutoFetchPageLoadWatcher); DISALLOW_COPY_AND_ASSIGN(AutoFetchPageLoadWatcher);
......
...@@ -7,12 +7,9 @@ ...@@ -7,12 +7,9 @@
#include <string> #include <string>
#include <utility> #include <utility>
#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/optional.h" #include "base/optional.h"
#include "base/strings/strcat.h" #include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "chrome/browser/offline_pages/request_coordinator_factory.h" #include "chrome/browser/offline_pages/request_coordinator_factory.h"
#include "components/offline_pages/core/auto_fetch.h" #include "components/offline_pages/core/auto_fetch.h"
...@@ -77,7 +74,11 @@ OfflinePageAutoFetcherService::OfflinePageAutoFetcherService( ...@@ -77,7 +74,11 @@ OfflinePageAutoFetcherService::OfflinePageAutoFetcherService(
RequestCoordinator* request_coordinator, RequestCoordinator* request_coordinator,
OfflinePageModel* offline_page_model, OfflinePageModel* offline_page_model,
Delegate* delegate) 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), request_coordinator_(request_coordinator),
offline_page_model_(offline_page_model), offline_page_model_(offline_page_model),
delegate_(delegate) { delegate_(delegate) {
...@@ -159,6 +160,7 @@ void OfflinePageAutoFetcherService::TryScheduleStep2( ...@@ -159,6 +160,7 @@ void OfflinePageAutoFetcherService::TryScheduleStep2(
return; return;
} }
} }
// Finally, schedule a new request, and proceed to step 3. // Finally, schedule a new request, and proceed to step 3.
RequestCoordinator::SavePageLaterParams params; RequestCoordinator::SavePageLaterParams params;
params.url = url; params.url = url;
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define CHROME_BROWSER_OFFLINE_PAGES_ANDROID_OFFLINE_PAGE_AUTO_FETCHER_SERVICE_H_ #define CHROME_BROWSER_OFFLINE_PAGES_ANDROID_OFFLINE_PAGE_AUTO_FETCHER_SERVICE_H_
#include <memory> #include <memory>
#include <queue>
#include <utility> #include <utility>
#include <vector> #include <vector>
...@@ -146,6 +147,7 @@ class OfflinePageAutoFetcherService : public KeyedService, ...@@ -146,6 +147,7 @@ class OfflinePageAutoFetcherService : public KeyedService,
void AutoFetchComplete(const OfflinePageItem* page); void AutoFetchComplete(const OfflinePageItem* page);
std::unique_ptr<AutoFetchNotifier> notifier_;
AutoFetchPageLoadWatcher page_load_watcher_; AutoFetchPageLoadWatcher page_load_watcher_;
RequestCoordinator* request_coordinator_; RequestCoordinator* request_coordinator_;
OfflinePageModel* offline_page_model_; 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