OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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/banners/app_banner_data_fetcher.h" | 5 #include "chrome/browser/banners/app_banner_data_fetcher.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/command_line.h" | |
8 #include "base/strings/string_util.h" | 9 #include "base/strings/string_util.h" |
9 #include "base/strings/utf_string_conversions.h" | 10 #include "base/strings/utf_string_conversions.h" |
10 #include "chrome/browser/banners/app_banner_metrics.h" | 11 #include "chrome/browser/banners/app_banner_metrics.h" |
11 #include "chrome/browser/banners/app_banner_settings_helper.h" | 12 #include "chrome/browser/banners/app_banner_settings_helper.h" |
12 #include "chrome/browser/bitmap_fetcher/bitmap_fetcher.h" | 13 #include "chrome/browser/bitmap_fetcher/bitmap_fetcher.h" |
13 #include "chrome/browser/browser_process.h" | 14 #include "chrome/browser/browser_process.h" |
14 #include "chrome/browser/infobars/infobar_service.h" | 15 #include "chrome/browser/infobars/infobar_service.h" |
15 #include "chrome/browser/manifest/manifest_icon_selector.h" | 16 #include "chrome/browser/manifest/manifest_icon_selector.h" |
16 #include "chrome/browser/profiles/profile.h" | 17 #include "chrome/browser/profiles/profile.h" |
18 #include "chrome/common/chrome_switches.h" | |
17 #include "chrome/common/render_messages.h" | 19 #include "chrome/common/render_messages.h" |
18 #include "components/infobars/core/infobar.h" | 20 #include "components/infobars/core/infobar.h" |
19 #include "components/rappor/rappor_utils.h" | 21 #include "components/rappor/rappor_utils.h" |
20 #include "content/public/browser/browser_context.h" | 22 #include "content/public/browser/browser_context.h" |
21 #include "content/public/browser/browser_thread.h" | 23 #include "content/public/browser/browser_thread.h" |
22 #include "content/public/browser/navigation_details.h" | 24 #include "content/public/browser/navigation_details.h" |
23 #include "content/public/browser/render_frame_host.h" | 25 #include "content/public/browser/render_frame_host.h" |
24 #include "content/public/browser/service_worker_context.h" | 26 #include "content/public/browser/service_worker_context.h" |
25 #include "content/public/browser/storage_partition.h" | 27 #include "content/public/browser/storage_partition.h" |
26 #include "net/base/load_flags.h" | 28 #include "net/base/load_flags.h" |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
64 gTimeDeltaForTesting = base::TimeDelta::FromDays(days); | 66 gTimeDeltaForTesting = base::TimeDelta::FromDays(days); |
65 } | 67 } |
66 | 68 |
67 AppBannerDataFetcher::AppBannerDataFetcher( | 69 AppBannerDataFetcher::AppBannerDataFetcher( |
68 content::WebContents* web_contents, | 70 content::WebContents* web_contents, |
69 base::WeakPtr<Delegate> delegate, | 71 base::WeakPtr<Delegate> delegate, |
70 int ideal_icon_size) | 72 int ideal_icon_size) |
71 : WebContentsObserver(web_contents), | 73 : WebContentsObserver(web_contents), |
72 ideal_icon_size_(ideal_icon_size), | 74 ideal_icon_size_(ideal_icon_size), |
73 weak_delegate_(delegate), | 75 weak_delegate_(delegate), |
74 is_active_(false) { | 76 is_active_(false), |
77 log_err_(false) { | |
75 } | 78 } |
76 | 79 |
77 void AppBannerDataFetcher::Start(const GURL& validated_url) { | 80 void AppBannerDataFetcher::Start(const GURL& validated_url) { |
78 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 81 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
79 | 82 |
80 content::WebContents* web_contents = GetWebContents(); | 83 content::WebContents* web_contents = GetWebContents(); |
81 DCHECK(web_contents); | 84 DCHECK(web_contents); |
82 | 85 |
83 is_active_ = true; | 86 is_active_ = true; |
87 log_err_ = base::CommandLine::ForCurrentProcess()->HasSwitch( | |
88 switches::kBypassAppBannerEngagementChecks); | |
benwells
2015/05/07 01:57:20
Nit: I think this indenting isn't quite right.
Th
dominickn (DO NOT USE)
2015/05/07 05:37:24
Done.
| |
84 validated_url_ = validated_url; | 89 validated_url_ = validated_url; |
85 web_contents->GetManifest( | 90 web_contents->GetManifest( |
86 base::Bind(&AppBannerDataFetcher::OnDidGetManifest, this)); | 91 base::Bind(&AppBannerDataFetcher::OnDidGetManifest, this)); |
87 } | 92 } |
88 | 93 |
89 void AppBannerDataFetcher::Cancel() { | 94 void AppBannerDataFetcher::Cancel() { |
90 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 95 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
91 if (is_active_) { | 96 if (is_active_) { |
92 FOR_EACH_OBSERVER(Observer, observer_list_, | 97 FOR_EACH_OBSERVER(Observer, observer_list_, |
93 OnDecidedWhetherToShow(this, false)); | 98 OnDecidedWhetherToShow(this, false)); |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
133 | 138 |
134 return handled; | 139 return handled; |
135 } | 140 } |
136 | 141 |
137 void AppBannerDataFetcher::OnBannerPromptReply( | 142 void AppBannerDataFetcher::OnBannerPromptReply( |
138 content::RenderFrameHost* render_frame_host, | 143 content::RenderFrameHost* render_frame_host, |
139 int request_id, | 144 int request_id, |
140 blink::WebAppBannerPromptReply reply) { | 145 blink::WebAppBannerPromptReply reply) { |
141 content::WebContents* web_contents = GetWebContents(); | 146 content::WebContents* web_contents = GetWebContents(); |
142 if (!is_active_ || !web_contents || request_id != gCurrentRequestID) { | 147 if (!is_active_ || !web_contents || request_id != gCurrentRequestID) { |
148 if (!is_active_) | |
benwells
2015/05/07 01:57:20
Nit: you need braces around all these statements a
dominickn (DO NOT USE)
2015/05/07 05:37:24
Done.
| |
149 SendDebugMessage( | |
150 "Banner not shown: display pipeline halted before " | |
benwells
2015/05/07 01:57:20
I think 'Banner not shown' is probably a touch too
dominickn (DO NOT USE)
2015/05/07 05:37:24
Done.
| |
151 "prompt reply checking."); | |
benwells
2015/05/07 01:57:20
For this error I think something like 'user naviga
dominickn (DO NOT USE)
2015/05/07 05:37:24
Done.
| |
152 else if (!web_contents) | |
153 SendDebugMessage( | |
154 "Banner not shown: no web content available for banner display."); | |
benwells
2015/05/07 01:57:19
Something like 'web contents closed.' would be goo
dominickn (DO NOT USE)
2015/05/07 05:37:24
Done.
| |
155 else if (request_id != gCurrentRequestID) | |
156 SendDebugMessage("Banner not shown: incorrect request id."); | |
benwells
2015/05/07 01:57:19
We shouldn't show the error in this case. This mea
dominickn (DO NOT USE)
2015/05/07 05:37:24
Done.
| |
143 Cancel(); | 157 Cancel(); |
144 return; | 158 return; |
145 } | 159 } |
146 | 160 |
147 // The renderer might have requested the prompt to be canceled. | 161 // The renderer might have requested the prompt to be canceled. |
148 if (reply == blink::WebAppBannerPromptReply::Cancel) { | 162 if (reply == blink::WebAppBannerPromptReply::Cancel) { |
149 // TODO(mlamouri,benwells): we should probably record that to behave | 163 // TODO(mlamouri,benwells): we should probably record that to behave |
150 // differently with regard to showing the banner. | 164 // differently with regard to showing the banner. |
165 SendDebugMessage("Banner not shown: renderer has requested the banner " | |
166 "prompt be cancelled."); | |
benwells
2015/05/07 01:57:20
Nit: indenting here is also off.
dominickn (DO NOT USE)
2015/05/07 05:37:24
Done.
| |
151 Cancel(); | 167 Cancel(); |
152 return; | 168 return; |
153 } | 169 } |
154 | 170 |
155 // Definitely going to show the banner now. | 171 // Definitely going to show the banner now. |
156 FOR_EACH_OBSERVER(Observer, observer_list_, | 172 FOR_EACH_OBSERVER(Observer, observer_list_, |
157 OnDecidedWhetherToShow(this, true)); | 173 OnDecidedWhetherToShow(this, true)); |
158 | 174 |
159 infobars::InfoBar* infobar = CreateBanner(app_icon_.get(), app_title_); | 175 infobars::InfoBar* infobar = CreateBanner(app_icon_.get(), app_title_); |
160 if (infobar) { | 176 if (infobar) { |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
226 rappor::SampleDomainAndRegistryFromGURL(g_browser_process->rappor_service(), | 242 rappor::SampleDomainAndRegistryFromGURL(g_browser_process->rappor_service(), |
227 event_name, | 243 event_name, |
228 web_contents->GetURL()); | 244 web_contents->GetURL()); |
229 banners::TrackDisplayEvent(DISPLAY_EVENT_CREATED); | 245 banners::TrackDisplayEvent(DISPLAY_EVENT_CREATED); |
230 } | 246 } |
231 | 247 |
232 void AppBannerDataFetcher::OnDidGetManifest( | 248 void AppBannerDataFetcher::OnDidGetManifest( |
233 const content::Manifest& manifest) { | 249 const content::Manifest& manifest) { |
234 content::WebContents* web_contents = GetWebContents(); | 250 content::WebContents* web_contents = GetWebContents(); |
235 if (!is_active_ || !web_contents || manifest.IsEmpty()) { | 251 if (!is_active_ || !web_contents || manifest.IsEmpty()) { |
252 if (!is_active_) | |
253 SendDebugMessage("Banner not shown: display pipeline halted before " | |
254 "manifest checking."); | |
255 else if (!web_contents) | |
256 SendDebugMessage( | |
257 "Banner not shown: no web content available for banner display."); | |
258 else if (manifest.IsEmpty()) | |
259 SendDebugMessage("Banner not shown: manifest is empty."); | |
236 Cancel(); | 260 Cancel(); |
237 return; | 261 return; |
238 } | 262 } |
239 | 263 |
240 if (manifest.prefer_related_applications && | 264 if (manifest.prefer_related_applications && |
241 manifest.related_applications.size()) { | 265 manifest.related_applications.size()) { |
242 for (const auto& application : manifest.related_applications) { | 266 for (const auto& application : manifest.related_applications) { |
243 std::string platform = base::UTF16ToUTF8(application.platform.string()); | 267 std::string platform = base::UTF16ToUTF8(application.platform.string()); |
244 std::string id = base::UTF16ToUTF8(application.id.string()); | 268 std::string id = base::UTF16ToUTF8(application.id.string()); |
245 if (weak_delegate_->HandleNonWebApp(platform, application.url, id)) | 269 if (weak_delegate_->HandleNonWebApp(platform, application.url, id)) |
246 return; | 270 return; |
247 } | 271 } |
248 } | 272 } |
249 | 273 |
250 if (!IsManifestValidForWebApp(manifest)) { | 274 if (!IsManifestValidForWebApp(manifest)) { |
275 SendDebugMessage("Banner not shown: invalid manifest."); | |
benwells
2015/05/07 01:57:20
Can we move this output into IsManifestValidForWeb
dominickn (DO NOT USE)
2015/05/07 05:37:24
Done.
| |
251 Cancel(); | 276 Cancel(); |
252 return; | 277 return; |
253 } | 278 } |
254 | 279 |
255 banners::TrackDisplayEvent(DISPLAY_EVENT_BANNER_REQUESTED); | 280 banners::TrackDisplayEvent(DISPLAY_EVENT_BANNER_REQUESTED); |
256 | 281 |
257 web_app_data_ = manifest; | 282 web_app_data_ = manifest; |
258 app_title_ = web_app_data_.name.string(); | 283 app_title_ = web_app_data_.name.string(); |
259 | 284 |
260 // Check to see if there is a single service worker controlling this page | 285 // Check to see if there is a single service worker controlling this page |
261 // and the manifest's start url. | 286 // and the manifest's start url. |
262 Profile* profile = | 287 Profile* profile = |
263 Profile::FromBrowserContext(web_contents->GetBrowserContext()); | 288 Profile::FromBrowserContext(web_contents->GetBrowserContext()); |
264 content::StoragePartition* storage_partition = | 289 content::StoragePartition* storage_partition = |
265 content::BrowserContext::GetStoragePartition( | 290 content::BrowserContext::GetStoragePartition( |
266 profile, web_contents->GetSiteInstance()); | 291 profile, web_contents->GetSiteInstance()); |
267 DCHECK(storage_partition); | 292 DCHECK(storage_partition); |
268 | 293 |
269 storage_partition->GetServiceWorkerContext()->CheckHasServiceWorker( | 294 storage_partition->GetServiceWorkerContext()->CheckHasServiceWorker( |
270 validated_url_, manifest.start_url, | 295 validated_url_, manifest.start_url, |
271 base::Bind(&AppBannerDataFetcher::OnDidCheckHasServiceWorker, | 296 base::Bind(&AppBannerDataFetcher::OnDidCheckHasServiceWorker, |
272 this)); | 297 this)); |
273 } | 298 } |
274 | 299 |
275 void AppBannerDataFetcher::OnDidCheckHasServiceWorker( | 300 void AppBannerDataFetcher::OnDidCheckHasServiceWorker( |
276 bool has_service_worker) { | 301 bool has_service_worker) { |
277 content::WebContents* web_contents = GetWebContents(); | 302 content::WebContents* web_contents = GetWebContents(); |
278 if (!is_active_ || !web_contents) { | 303 if (!is_active_ || !web_contents) { |
304 if (!is_active_) | |
305 SendDebugMessage("Banner not shown: display pipeline halted before " | |
306 "manifest checking."); | |
benwells
2015/05/07 01:57:20
This code block is repeated a few times. Would be
dominickn (DO NOT USE)
2015/05/07 05:37:24
Done.
| |
307 else if (!web_contents) | |
308 SendDebugMessage( | |
309 "Banner not shown: no web content available for banner display."); | |
279 Cancel(); | 310 Cancel(); |
280 return; | 311 return; |
281 } | 312 } |
282 | 313 |
283 if (has_service_worker) { | 314 if (has_service_worker) { |
284 // Create an infobar to promote the manifest's app. | 315 // Create an infobar to promote the manifest's app. |
285 GURL icon_url = | 316 GURL icon_url = |
286 ManifestIconSelector::FindBestMatchingIcon( | 317 ManifestIconSelector::FindBestMatchingIcon( |
287 web_app_data_.icons, | 318 web_app_data_.icons, |
288 ideal_icon_size_, | 319 ideal_icon_size_, |
289 gfx::Screen::GetScreenFor(web_contents->GetNativeView())); | 320 gfx::Screen::GetScreenFor(web_contents->GetNativeView())); |
290 if (!icon_url.is_empty()) { | 321 if (!icon_url.is_empty()) { |
291 FetchIcon(icon_url); | 322 FetchIcon(icon_url); |
292 return; | 323 return; |
293 } | 324 } |
325 SendDebugMessage( | |
326 "Banner not shownL could not find icon specified in manifest"); | |
294 } else { | 327 } else { |
295 TrackDisplayEvent(DISPLAY_EVENT_LACKS_SERVICE_WORKER); | 328 TrackDisplayEvent(DISPLAY_EVENT_LACKS_SERVICE_WORKER); |
296 } | 329 } |
297 | 330 |
331 SendDebugMessage("Banner not shown: no service worker detected."); | |
benwells
2015/05/07 01:57:20
A common cause of this will be that the site is no
dominickn (DO NOT USE)
2015/05/07 05:37:24
Done.
| |
298 Cancel(); | 332 Cancel(); |
299 } | 333 } |
300 | 334 |
301 void AppBannerDataFetcher::OnFetchComplete(const GURL& url, | 335 void AppBannerDataFetcher::OnFetchComplete(const GURL& url, |
302 const SkBitmap* icon) { | 336 const SkBitmap* icon) { |
303 if (is_active_) | 337 if (is_active_) |
304 ShowBanner(icon); | 338 ShowBanner(icon); |
305 | 339 |
306 Release(); | 340 Release(); |
307 } | 341 } |
308 | 342 |
309 void AppBannerDataFetcher::ShowBanner(const SkBitmap* icon) { | 343 void AppBannerDataFetcher::ShowBanner(const SkBitmap* icon) { |
310 content::WebContents* web_contents = GetWebContents(); | 344 content::WebContents* web_contents = GetWebContents(); |
311 if (!is_active_ || !web_contents || !icon) { | 345 if (!is_active_ || !web_contents || !icon) { |
346 if (!is_active_) | |
347 SendDebugMessage( | |
348 "Banner not shown: display pipeline halted before banner display."); | |
349 else if (!web_contents) | |
350 SendDebugMessage( | |
351 "Banner not shown: no web content available for banner display."); | |
352 else if (!icon) | |
353 SendDebugMessage("Banner not shown: no icon available to display."); | |
312 Cancel(); | 354 Cancel(); |
313 return; | 355 return; |
314 } | 356 } |
315 | 357 |
316 RecordCouldShowBanner(); | 358 RecordCouldShowBanner(); |
317 if (!CheckIfShouldShowBanner()) { | 359 if (!CheckIfShouldShowBanner()) { |
360 SendDebugMessage("Banner not shown: engagement checks failed."); | |
318 Cancel(); | 361 Cancel(); |
319 return; | 362 return; |
320 } | 363 } |
321 | 364 |
365 SendDebugMessage("Showing banner."); | |
322 app_icon_.reset(new SkBitmap(*icon)); | 366 app_icon_.reset(new SkBitmap(*icon)); |
323 web_contents->GetMainFrame()->Send( | 367 web_contents->GetMainFrame()->Send( |
324 new ChromeViewMsg_AppBannerPromptRequest( | 368 new ChromeViewMsg_AppBannerPromptRequest( |
325 web_contents->GetMainFrame()->GetRoutingID(), | 369 web_contents->GetMainFrame()->GetRoutingID(), |
326 ++gCurrentRequestID, | 370 ++gCurrentRequestID, |
327 GetBannerType())); | 371 GetBannerType())); |
328 } | 372 } |
329 | 373 |
330 void AppBannerDataFetcher::RecordCouldShowBanner() { | 374 void AppBannerDataFetcher::RecordCouldShowBanner() { |
331 content::WebContents* web_contents = GetWebContents(); | 375 content::WebContents* web_contents = GetWebContents(); |
332 DCHECK(web_contents); | 376 DCHECK(web_contents); |
333 | 377 |
334 AppBannerSettingsHelper::RecordBannerEvent( | 378 AppBannerSettingsHelper::RecordBannerEvent( |
335 web_contents, validated_url_, GetAppIdentifier(), | 379 web_contents, validated_url_, GetAppIdentifier(), |
336 AppBannerSettingsHelper::APP_BANNER_EVENT_COULD_SHOW, | 380 AppBannerSettingsHelper::APP_BANNER_EVENT_COULD_SHOW, |
337 GetCurrentTime()); | 381 GetCurrentTime()); |
338 } | 382 } |
339 | 383 |
340 bool AppBannerDataFetcher::CheckIfShouldShowBanner() { | 384 bool AppBannerDataFetcher::CheckIfShouldShowBanner() { |
341 content::WebContents* web_contents = GetWebContents(); | 385 content::WebContents* web_contents = GetWebContents(); |
342 DCHECK(web_contents); | 386 DCHECK(web_contents); |
343 | 387 |
344 return AppBannerSettingsHelper::ShouldShowBanner( | 388 return AppBannerSettingsHelper::ShouldShowBanner( |
345 web_contents, validated_url_, GetAppIdentifier(), GetCurrentTime()); | 389 web_contents, validated_url_, GetAppIdentifier(), GetCurrentTime()); |
346 } | 390 } |
347 | 391 |
392 void AppBannerDataFetcher::SendDebugMessage(const std::string& message) { | |
393 if (log_err_) { | |
394 content::WebContents* web_contents = GetWebContents(); | |
395 if (web_contents) { | |
396 web_contents->GetMainFrame()->Send( | |
397 new ChromeViewMsg_AppBannerDebugMessageRequest( | |
398 web_contents->GetMainFrame()->GetRoutingID(), message)); | |
399 } | |
400 } | |
401 } | |
402 | |
348 // static | 403 // static |
349 bool AppBannerDataFetcher::IsManifestValidForWebApp( | 404 bool AppBannerDataFetcher::IsManifestValidForWebApp( |
350 const content::Manifest& manifest) { | 405 const content::Manifest& manifest) { |
351 if (manifest.IsEmpty()) | 406 if (manifest.IsEmpty()) |
352 return false; | 407 return false; |
353 if (!manifest.start_url.is_valid()) | 408 if (!manifest.start_url.is_valid()) |
354 return false; | 409 return false; |
355 if (manifest.name.is_null() && manifest.short_name.is_null()) | 410 if (manifest.name.is_null() && manifest.short_name.is_null()) |
356 return false; | 411 return false; |
357 if (!DoesManifestContainRequiredIcon(manifest)) | 412 if (!DoesManifestContainRequiredIcon(manifest)) |
358 return false; | 413 return false; |
359 return true; | 414 return true; |
360 } | 415 } |
361 | 416 |
362 } // namespace banners | 417 } // namespace banners |
OLD | NEW |