Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(32)

Side by Side Diff: chrome/browser/android/offline_pages/recent_tab_helper.cc

Issue 2602473004: Offline Page Cache uses user interaction triggers for saving pages. (Closed)
Patch Set: Rebased and added the other missing histogram.xml entry... Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2016 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/android/offline_pages/recent_tab_helper.h" 5 #include "chrome/browser/android/offline_pages/recent_tab_helper.h"
6 6
7 #include <queue> 7 #include <queue>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
49 bool GetTabId(content::WebContents* web_contents, int* tab_id) override { 49 bool GetTabId(content::WebContents* web_contents, int* tab_id) override {
50 return offline_pages::OfflinePageUtils::GetTabId(web_contents, tab_id); 50 return offline_pages::OfflinePageUtils::GetTabId(web_contents, tab_id);
51 } 51 }
52 }; 52 };
53 } // namespace 53 } // namespace
54 54
55 namespace offline_pages { 55 namespace offline_pages {
56 56
57 RecentTabHelper::RecentTabHelper(content::WebContents* web_contents) 57 RecentTabHelper::RecentTabHelper(content::WebContents* web_contents)
58 : content::WebContentsObserver(web_contents), 58 : content::WebContentsObserver(web_contents),
59 page_model_(nullptr),
60 snapshots_enabled_(false),
61 is_page_ready_for_snapshot_(false),
62 delegate_(new DefaultDelegate()), 59 delegate_(new DefaultDelegate()),
63 weak_ptr_factory_(this) { 60 weak_ptr_factory_(this) {
64 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 61 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
65 } 62 }
66 63
67 RecentTabHelper::~RecentTabHelper() { 64 RecentTabHelper::~RecentTabHelper() {
68 } 65 }
69 66
70 void RecentTabHelper::SetDelegate( 67 void RecentTabHelper::SetDelegate(
71 std::unique_ptr<RecentTabHelper::Delegate> delegate) { 68 std::unique_ptr<RecentTabHelper::Delegate> delegate) {
72 DCHECK(delegate); 69 DCHECK(delegate);
73 delegate_ = std::move(delegate); 70 delegate_ = std::move(delegate);
74 } 71 }
75 72
76 void RecentTabHelper::ObserveAndDownloadCurrentPage( 73 void RecentTabHelper::ObserveAndDownloadCurrentPage(
77 const ClientId& client_id, int64_t request_id) { 74 const ClientId& client_id, int64_t request_id) {
78 EnsureInitialized(); 75 EnsureInitialized();
79 download_info_ = base::MakeUnique<DownloadPageInfo>(client_id, request_id); 76 download_info_ = base::MakeUnique<DownloadPageInfo>(client_id, request_id);
80 77
81 // If this tab helper is not enabled, immediately give the job back to 78 // If this tab helper is not enabled, immediately give the job back to
82 // RequestCoordinator. 79 // RequestCoordinator.
83 if (!snapshots_enabled_ || !page_model_) { 80 if (!snapshots_enabled_ || !page_model_) {
84 ReportDownloadStatusToRequestCoordinator(); 81 ReportDownloadStatusToRequestCoordinator();
82 weak_ptr_factory_.InvalidateWeakPtrs();
carlosk 2017/01/04 20:52:48 This change is what justifies the change of if-che
Dmitry Titov 2017/01/05 21:50:03 Acknowledged.
85 download_info_.reset(); 83 download_info_.reset();
86 return; 84 return;
87 } 85 }
88 86
89 // No snapshots yet happened on the current page - return and wait for some. 87 // No snapshots yet happened on the current page - return and wait for some.
90 if (!is_page_ready_for_snapshot_) 88 if (!is_page_ready_for_snapshot_)
91 return; 89 return;
92 90
93 // If snapshot already happened and we missed it, go ahead and snapshot now. 91 // If snapshot already happened and we missed it, go ahead and snapshot now.
94 OfflinePageModel::SavePageParams save_page_params; 92 OfflinePageModel::SavePageParams save_page_params;
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
127 if (!snapshots_enabled_) 125 if (!snapshots_enabled_)
128 return; 126 return;
129 127
130 page_model_ = OfflinePageModelFactory::GetForBrowserContext( 128 page_model_ = OfflinePageModelFactory::GetForBrowserContext(
131 web_contents()->GetBrowserContext()); 129 web_contents()->GetBrowserContext());
132 } 130 }
133 131
134 void RecentTabHelper::DidFinishNavigation( 132 void RecentTabHelper::DidFinishNavigation(
135 content::NavigationHandle* navigation_handle) { 133 content::NavigationHandle* navigation_handle) {
136 if (!navigation_handle->IsInMainFrame() || 134 if (!navigation_handle->IsInMainFrame() ||
137 !navigation_handle->HasCommitted()) { 135 navigation_handle->IsExternalProtocol() ||
136 navigation_handle->IsSamePage() || !navigation_handle->HasCommitted()) {
carlosk 2017/01/04 20:52:48 IsExternalProtocol: if a navigation is handled ext
dewittj 2017/01/07 00:50:09 This change should probably be extracted into a sm
carlosk 2017/01/17 23:16:27 Moved this and many others to a new CL: https://cr
138 return; 137 return;
139 } 138 }
139 EnsureInitialized();
140 if (!snapshots_enabled_)
141 return;
carlosk 2017/01/04 20:52:48 It might be better to move this up even further. I
Dmitry Titov 2017/01/05 21:50:03 Acknowledged.
140 142
141 // Cancel tasks in flight that relate to the previous page. 143 // Cancel tasks in flight that relate to the previous page.
142 weak_ptr_factory_.InvalidateWeakPtrs(); 144 weak_ptr_factory_.InvalidateWeakPtrs();
143 145
144 EnsureInitialized();
145 if (!snapshots_enabled_)
146 return;
147
148 // We navigated to a different page, lets report progress to Background 146 // We navigated to a different page, lets report progress to Background
149 // Offliner. 147 // Offliner.
150 if (download_info_ && !navigation_handle->IsSamePage()) { 148 ReportDownloadStatusToRequestCoordinator();
151 ReportDownloadStatusToRequestCoordinator();
152 }
carlosk 2017/01/04 20:52:48 The same page check now happens earlier and the do
Dmitry Titov 2017/01/05 21:50:03 Acknowledged.
153
154 if (offline_pages::IsOffliningRecentPagesEnabled()) {
155 download_info_ = base::MakeUnique<DownloadPageInfo>(
156 GetRecentPagesClientId(), OfflinePageModel::kInvalidOfflineId);
157 } else {
158 download_info_.reset();
159 }
160 149
161 is_page_ready_for_snapshot_ = false; 150 is_page_ready_for_snapshot_ = false;
162 151
163 // New navigation, new snapshot session. 152 // New navigation, new snapshot session.
164 snapshot_url_ = web_contents()->GetLastCommittedURL(); 153 snapshot_url_ = web_contents()->GetLastCommittedURL();
165 154
166 // Check for conditions that would cause us not to snapshot. 155 // Check for conditions that would cause us not to snapshot.
167 bool can_save = !navigation_handle->IsErrorPage() && 156 bool can_save = !navigation_handle->IsErrorPage() &&
168 OfflinePageModel::CanSaveURL(snapshot_url_) && 157 OfflinePageModel::CanSaveURL(snapshot_url_) &&
169 OfflinePageUtils::GetOfflinePageFromWebContents( 158 OfflinePageUtils::GetOfflinePageFromWebContents(
170 web_contents()) == nullptr; 159 web_contents()) == nullptr;
171 160
172 UMA_HISTOGRAM_BOOLEAN("OfflinePages.CanSaveRecentPage", can_save); 161 UMA_HISTOGRAM_BOOLEAN("OfflinePages.CanSaveRecentPage", can_save);
173 162
174 // Always reset so that posted tasks get canceled. 163 // Always reset so that posted tasks get canceled.
175 snapshot_controller_->Reset(); 164 snapshot_controller_->Reset();
176 165
177 if (!can_save) 166 if (can_save) {
167 // When last_n is using navigation triggers |download_info_| will always be
168 // set for a page being that can be saved. Otherwise, when using user
169 // interaction triggers, it is only set while a page is being saved.
170 if (IsOffliningRecentPagesUsingNavigationTriggers()) {
171 download_info_ = base::MakeUnique<DownloadPageInfo>(
172 GetRecentPagesClientId(), OfflinePageModel::kInvalidOfflineId);
173 } else if (IsOffliningRecentPagesUsingInteractionTriggers()) {
174 last_n_listen_to_tab_hidden_ = true;
175 last_n_saved_quality_ = PageQuality::POOR;
176 }
177 } else {
178 last_n_listen_to_tab_hidden_ = false;
179 download_info_.reset();
Dmitry Titov 2017/01/05 21:50:03 I think this reset() should happen unconditionally
carlosk 2017/01/17 23:16:27 Done. Indeed, every time we invalidate pointers we
178 snapshot_controller_->Stop(); 180 snapshot_controller_->Stop();
181 }
179 } 182 }
180 183
181 void RecentTabHelper::DocumentAvailableInMainFrame() { 184 void RecentTabHelper::DocumentAvailableInMainFrame() {
182 EnsureInitialized(); 185 EnsureInitialized();
183 snapshot_controller_->DocumentAvailableInMainFrame(); 186 snapshot_controller_->DocumentAvailableInMainFrame();
184 } 187 }
185 188
186 void RecentTabHelper::DocumentOnLoadCompletedInMainFrame() { 189 void RecentTabHelper::DocumentOnLoadCompletedInMainFrame() {
187 EnsureInitialized(); 190 EnsureInitialized();
188 snapshot_controller_->DocumentOnLoadCompletedInMainFrame(); 191 snapshot_controller_->DocumentOnLoadCompletedInMainFrame();
189 } 192 }
190 193
191 void RecentTabHelper::WebContentsDestroyed() { 194 void RecentTabHelper::WebContentsDestroyed() {
192 // WebContents (and maybe Tab) is destroyed, report status to Offliner. 195 // WebContents (and maybe Tab) is destroyed, report status to Offliner.
193 if (!download_info_) 196 if (!download_info_)
194 return; 197 return;
195 ReportDownloadStatusToRequestCoordinator(); 198 ReportDownloadStatusToRequestCoordinator();
196 } 199 }
197 200
201 void RecentTabHelper::WasHidden() {
202 if (!IsOffliningRecentPagesUsingInteractionTriggers())
203 return;
204
205 // Return immediately if any of these are true last_n is not listening to tab
206 // hidden events or if a snapshot is currently being saved.
207 if (!last_n_listen_to_tab_hidden_ || download_info_)
208 return;
209
210 // Do not save if page quality is too low or if we already have a save with
211 // the current quality level.
212 // Note: we assume page quality for a page can only increase.
213 PageQuality current_quality = snapshot_controller_->current_page_quality();
214 if (current_quality == PageQuality::POOR ||
215 current_quality == last_n_saved_quality_) {
216 return;
217 }
218
219 download_info_ = base::MakeUnique<DownloadPageInfo>(
220 GetRecentPagesClientId(), OfflinePageModel::kInvalidOfflineId);
221 StartSnapshotInternal();
222 }
198 223
199 // This starts a sequence of async operations chained through callbacks: 224 // This starts a sequence of async operations chained through callbacks:
200 // - compute the set of old 'last_n' pages that have to be purged 225 // - compute the set of old 'last_n' pages that have to be purged
201 // - delete the pages found in the previous step 226 // - delete the pages found in the previous step
202 // - snapshot the current web contents 227 // - snapshot the current web contents
203 // Along the chain, the original URL is passed and compared, to detect 228 // Along the chain, the original URL is passed and compared, to detect
204 // possible navigation and cancel snapshot in that case. 229 // possible navigation and cancel snapshot in that case.
205 void RecentTabHelper::StartSnapshot() { 230 void RecentTabHelper::StartSnapshot() {
206 is_page_ready_for_snapshot_ = true; 231 is_page_ready_for_snapshot_ = true;
207 232
208 if (!snapshots_enabled_ || 233 // This is a navigation based snapshot trigger: before proceeding we must
209 !page_model_ || 234 // verify we should proceed.
210 !download_info_) { 235 bool should_save = snapshots_enabled_ && page_model_ && download_info_;
211 ReportSnapshotCompleted(); 236
212 return; 237 // If navigation triggers are disabled for last_n, don't proceed if this is
238 // not save requested by downloads.
239 if (IsOffliningRecentPagesUsingInteractionTriggers())
240 should_save &= !isSnapshottingForLastN();
241
242 if (should_save) {
243 StartSnapshotInternal();
244 } else {
245 // We're not calling ReportSnapshotCompleted here because we don't want to
246 // mix up signals of this with a last_n save being completed.
247 snapshot_controller_->PendingSnapshotCompleted();
248 ReportDownloadStatusToRequestCoordinator();
213 } 249 }
250 }
214 251
252 void RecentTabHelper::StartSnapshotInternal() {
253 DCHECK(snapshots_enabled_);
254 DCHECK(download_info_);
215 // Remove previously captured pages for this tab. 255 // Remove previously captured pages for this tab.
216 page_model_->GetOfflineIdsForClientId( 256 page_model_->GetOfflineIdsForClientId(
217 GetRecentPagesClientId(), 257 GetRecentPagesClientId(),
218 base::Bind(&RecentTabHelper::ContinueSnapshotWithIdsToPurge, 258 base::Bind(&RecentTabHelper::ContinueSnapshotWithIdsToPurge,
219 weak_ptr_factory_.GetWeakPtr())); 259 weak_ptr_factory_.GetWeakPtr()));
220 } 260 }
221 261
222 void RecentTabHelper::ContinueSnapshotWithIdsToPurge( 262 void RecentTabHelper::ContinueSnapshotWithIdsToPurge(
223 const std::vector<int64_t>& page_ids) { 263 const std::vector<int64_t>& page_ids) {
224 if (!download_info_) 264 DCHECK(download_info_);
225 return;
226 265
227 // Also remove the download page if this is not a first snapshot. 266 // Also remove the download page if this is not a first snapshot.
228 std::vector<int64_t> ids(page_ids); 267 std::vector<int64_t> ids(page_ids);
229 ids.push_back(download_info_->request_id_); 268 ids.push_back(download_info_->request_id_);
230 269
231 page_model_->DeletePagesByOfflineId( 270 page_model_->DeletePagesByOfflineId(
232 ids, base::Bind(&RecentTabHelper::ContinueSnapshotAfterPurge, 271 ids, base::Bind(&RecentTabHelper::ContinueSnapshotAfterPurge,
233 weak_ptr_factory_.GetWeakPtr())); 272 weak_ptr_factory_.GetWeakPtr()));
234 } 273 }
235 274
236 void RecentTabHelper::ContinueSnapshotAfterPurge( 275 void RecentTabHelper::ContinueSnapshotAfterPurge(
237 OfflinePageModel::DeletePageResult result) { 276 OfflinePageModel::DeletePageResult result) {
238 if (!download_info_ || 277 DCHECK(download_info_);
239 result != OfflinePageModel::DeletePageResult::SUCCESS || 278 if (result != OfflinePageModel::DeletePageResult::SUCCESS) {
240 !IsSamePage()) {
241 ReportSnapshotCompleted(); 279 ReportSnapshotCompleted();
242 return; 280 return;
243 } 281 }
244 282
283 page_quality_on_save_start_ = snapshot_controller_->current_page_quality();
284
245 OfflinePageModel::SavePageParams save_page_params; 285 OfflinePageModel::SavePageParams save_page_params;
246 save_page_params.url = snapshot_url_; 286 save_page_params.url = snapshot_url_;
247 save_page_params.client_id = download_info_->client_id_; 287 save_page_params.client_id = download_info_->client_id_;
248 save_page_params.proposed_offline_id = download_info_->request_id_; 288 save_page_params.proposed_offline_id = download_info_->request_id_;
249 page_model_->SavePage(save_page_params, 289 page_model_->SavePage(save_page_params,
250 delegate_->CreatePageArchiver(web_contents()), 290 delegate_->CreatePageArchiver(web_contents()),
251 base::Bind(&RecentTabHelper::SavePageCallback, 291 base::Bind(&RecentTabHelper::SavePageCallback,
252 weak_ptr_factory_.GetWeakPtr())); 292 weak_ptr_factory_.GetWeakPtr()));
253 } 293 }
254 294
255 void RecentTabHelper::SavePageCallback(OfflinePageModel::SavePageResult result, 295 void RecentTabHelper::SavePageCallback(OfflinePageModel::SavePageResult result,
256 int64_t offline_id) { 296 int64_t offline_id) {
257 if (!download_info_) 297 DCHECK(download_info_);
258 return;
259 download_info_->page_snapshot_completed_ = 298 download_info_->page_snapshot_completed_ =
260 (result == SavePageResult::SUCCESS); 299 (result == SavePageResult::SUCCESS);
261 ReportSnapshotCompleted(); 300 ReportSnapshotCompleted();
262 } 301 }
263 302
264 void RecentTabHelper::ReportSnapshotCompleted() { 303 void RecentTabHelper::ReportSnapshotCompleted() {
304 if (IsOffliningRecentPagesUsingInteractionTriggers() &&
305 isSnapshottingForLastN()) {
306 // This was a last_n save triggered by the tab being hidden.
307 if (download_info_->page_snapshot_completed_)
308 last_n_saved_quality_ = page_quality_on_save_start_;
309 download_info_.reset();
310 return;
311 }
312
265 snapshot_controller_->PendingSnapshotCompleted(); 313 snapshot_controller_->PendingSnapshotCompleted();
266 // Tell RequestCoordinator how the request should be processed further. 314 // Tell RequestCoordinator how the request should be processed further.
267 ReportDownloadStatusToRequestCoordinator(); 315 ReportDownloadStatusToRequestCoordinator();
268 } 316 }
269 317
270 void RecentTabHelper::ReportDownloadStatusToRequestCoordinator() { 318 void RecentTabHelper::ReportDownloadStatusToRequestCoordinator() {
271 if (!download_info_) 319 if (!download_info_ || isSnapshottingForLastN())
272 return;
273
274 if (download_info_->request_id_ == OfflinePageModel::kInvalidOfflineId)
275 return; 320 return;
276 321
277 RequestCoordinator* request_coordinator = 322 RequestCoordinator* request_coordinator =
278 RequestCoordinatorFactory::GetForBrowserContext( 323 RequestCoordinatorFactory::GetForBrowserContext(
279 web_contents()->GetBrowserContext()); 324 web_contents()->GetBrowserContext());
280 if (!request_coordinator) 325 if (!request_coordinator)
281 return; 326 return;
282 327
283 // It is OK to call these methods more then once, depending on 328 // It is OK to call these methods more then once, depending on
284 // number of snapshots attempted in this tab helper. If the request_id is not 329 // number of snapshots attempted in this tab helper. If the request_id is not
285 // in the list of RequestCoordinator, these calls have no effect. 330 // in the list of RequestCoordinator, these calls have no effect.
286 if (download_info_->page_snapshot_completed_) 331 if (download_info_->page_snapshot_completed_)
287 request_coordinator->MarkRequestCompleted(download_info_->request_id_); 332 request_coordinator->MarkRequestCompleted(download_info_->request_id_);
288 else 333 else
289 request_coordinator->EnableForOffliner(download_info_->request_id_, 334 request_coordinator->EnableForOffliner(download_info_->request_id_,
290 download_info_->client_id_); 335 download_info_->client_id_);
291 } 336 }
292 337
293 bool RecentTabHelper::IsSamePage() const {
294 return web_contents() &&
295 (web_contents()->GetLastCommittedURL() == snapshot_url_);
296 }
297
298 ClientId RecentTabHelper::GetRecentPagesClientId() const { 338 ClientId RecentTabHelper::GetRecentPagesClientId() const {
299 return ClientId(kLastNNamespace, tab_id_); 339 return ClientId(kLastNNamespace, tab_id_);
300 } 340 }
301 341
342 bool RecentTabHelper::isSnapshottingForLastN() const {
343 // For a snapshot to be executing for a last_n save download_info_ must be set
344 // and it must have an invalid request id.
345 // Note that at any point in time the download_info_ can be replaced with one
346 // created for a download snapshot request.
347 return download_info_ &&
348 download_info_->request_id_ == OfflinePageModel::kInvalidOfflineId;
349 }
350
302 } // namespace offline_pages 351 } // namespace offline_pages
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698