File: auto_fetch_page_load_watcher.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (209 lines) | stat: -rw-r--r-- 7,672 bytes parent folder | download | duplicates (6)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_OFFLINE_PAGES_ANDROID_AUTO_FETCH_PAGE_LOAD_WATCHER_H_
#define CHROME_BROWSER_OFFLINE_PAGES_ANDROID_AUTO_FETCH_PAGE_LOAD_WATCHER_H_

#include <map>
#include <memory>
#include <set>
#include <vector>

#include "base/memory/raw_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/client_id.h"
#include "url/gurl.h"

namespace content {
class WebContents;
class NavigationHandle;
}  // namespace content

namespace offline_pages {
class SavePageRequest;
class RequestCoordinator;

// Manages showing the in-progress notification.
class AutoFetchNotifier {
 public:
  virtual ~AutoFetchNotifier() = default;
  // 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) {}
};

// Types and functions internal to AutoFetchPageLoadWatcher. Included in the
// header for testing.
namespace auto_fetch_internal {

// Information about an Android browser tab.
struct TabInfo {
  int android_tab_id = 0;
  GURL current_url;
};

// 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 std::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;
};

std::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() = default;
    // 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);

  // Tab event methods.
  void TabClosed(int android_tab_id);
  void TabModelReady();

  base::WeakPtr<InternalImpl> GetWeakPtr() {
    return weak_ptr_factory_.GetWeakPtr();
  }

  std::vector<GURL>& pages_loaded_before_observer_ready_for_testing() {
    return pages_loaded_before_observer_ready_;
  }

 private:
  void SetNotificationStateToShown(int64_t request_id);
  void UpdateNotificationStateForAllRequests();

  raw_ptr<AutoFetchNotifier> notifier_;
  raw_ptr<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;
  bool tab_model_ready_ = false;
  std::vector<GURL> pages_loaded_before_observer_ready_;

  base::WeakPtrFactory<InternalImpl> weak_ptr_factory_{this};
};

}  // 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 tab is closed, 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;

  static void CreateForWebContents(content::WebContents* web_contents);

  AutoFetchPageLoadWatcher(AutoFetchNotifier* notifier,
                           RequestCoordinator* request_coordinator,
                           std::unique_ptr<AndroidTabFinder> tab_finder);

  AutoFetchPageLoadWatcher(const AutoFetchPageLoadWatcher&) = delete;
  AutoFetchPageLoadWatcher& operator=(const AutoFetchPageLoadWatcher&) = delete;

  ~AutoFetchPageLoadWatcher() override;

  // Called when navigation completes, even on errors. This is only called
  // once per navigation.
  void HandleNavigation(content::NavigationHandle* navigation_handle);

  std::vector<GURL>& loaded_pages_for_testing() {
    return impl_.pages_loaded_before_observer_ready_for_testing();
  }

 private:
  class NavigationObserver;
  class TabWatcher;
  base::WeakPtr<AutoFetchPageLoadWatcher> GetWeakPtr() {
    return weak_ptr_factory_.GetWeakPtr();
  }

  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 {}

  raw_ptr<RequestCoordinator> request_coordinator_;  // Not owned.
  auto_fetch_internal::InternalImpl impl_;
  std::unique_ptr<TabWatcher> tab_watcher_;
  base::WeakPtrFactory<AutoFetchPageLoadWatcher> weak_ptr_factory_{this};
};

}  // namespace offline_pages

#endif  // CHROME_BROWSER_OFFLINE_PAGES_ANDROID_AUTO_FETCH_PAGE_LOAD_WATCHER_H_