Chromium Code Reviews| 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" | |
|
benwells
2015/05/11 08:08:40
I don't think this include is needed now.
dominickn (DO NOT USE)
2015/05/12 07:41:31
Done.
| |
| 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" |
| 11 #include "chrome/browser/banners/app_banner_debug_log.h" | |
| 10 #include "chrome/browser/banners/app_banner_metrics.h" | 12 #include "chrome/browser/banners/app_banner_metrics.h" |
| 11 #include "chrome/browser/banners/app_banner_settings_helper.h" | 13 #include "chrome/browser/banners/app_banner_settings_helper.h" |
| 12 #include "chrome/browser/bitmap_fetcher/bitmap_fetcher.h" | 14 #include "chrome/browser/bitmap_fetcher/bitmap_fetcher.h" |
| 13 #include "chrome/browser/browser_process.h" | 15 #include "chrome/browser/browser_process.h" |
| 14 #include "chrome/browser/infobars/infobar_service.h" | 16 #include "chrome/browser/infobars/infobar_service.h" |
| 15 #include "chrome/browser/manifest/manifest_icon_selector.h" | 17 #include "chrome/browser/manifest/manifest_icon_selector.h" |
| 16 #include "chrome/browser/profiles/profile.h" | 18 #include "chrome/browser/profiles/profile.h" |
| 19 #include "chrome/common/chrome_switches.h" | |
|
benwells
2015/05/11 08:08:40
This too.
dominickn (DO NOT USE)
2015/05/12 07:41:31
Done.
| |
| 17 #include "chrome/common/render_messages.h" | 20 #include "chrome/common/render_messages.h" |
| 18 #include "components/infobars/core/infobar.h" | 21 #include "components/infobars/core/infobar.h" |
| 19 #include "components/rappor/rappor_utils.h" | 22 #include "components/rappor/rappor_utils.h" |
| 20 #include "content/public/browser/browser_context.h" | 23 #include "content/public/browser/browser_context.h" |
| 21 #include "content/public/browser/browser_thread.h" | 24 #include "content/public/browser/browser_thread.h" |
| 22 #include "content/public/browser/navigation_details.h" | 25 #include "content/public/browser/navigation_details.h" |
| 23 #include "content/public/browser/render_frame_host.h" | 26 #include "content/public/browser/render_frame_host.h" |
| 24 #include "content/public/browser/service_worker_context.h" | 27 #include "content/public/browser/service_worker_context.h" |
| 25 #include "content/public/browser/storage_partition.h" | 28 #include "content/public/browser/storage_partition.h" |
| 26 #include "net/base/load_flags.h" | 29 #include "net/base/load_flags.h" |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 65 } | 68 } |
| 66 | 69 |
| 67 AppBannerDataFetcher::AppBannerDataFetcher( | 70 AppBannerDataFetcher::AppBannerDataFetcher( |
| 68 content::WebContents* web_contents, | 71 content::WebContents* web_contents, |
| 69 base::WeakPtr<Delegate> delegate, | 72 base::WeakPtr<Delegate> delegate, |
| 70 int ideal_icon_size) | 73 int ideal_icon_size) |
| 71 : WebContentsObserver(web_contents), | 74 : WebContentsObserver(web_contents), |
| 72 ideal_icon_size_(ideal_icon_size), | 75 ideal_icon_size_(ideal_icon_size), |
| 73 weak_delegate_(delegate), | 76 weak_delegate_(delegate), |
| 74 is_active_(false), | 77 is_active_(false), |
| 78 log_err_(false), | |
| 75 event_request_id_(-1) { | 79 event_request_id_(-1) { |
| 76 } | 80 } |
| 77 | 81 |
| 78 void AppBannerDataFetcher::Start(const GURL& validated_url) { | 82 void AppBannerDataFetcher::Start(const GURL& validated_url) { |
| 79 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | 83 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 80 | 84 |
| 81 content::WebContents* web_contents = GetWebContents(); | 85 content::WebContents* web_contents = GetWebContents(); |
| 82 DCHECK(web_contents); | 86 DCHECK(web_contents); |
| 83 | 87 |
| 84 is_active_ = true; | 88 is_active_ = true; |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 133 IPC_END_MESSAGE_MAP() | 137 IPC_END_MESSAGE_MAP() |
| 134 | 138 |
| 135 return handled; | 139 return handled; |
| 136 } | 140 } |
| 137 | 141 |
| 138 void AppBannerDataFetcher::OnBannerPromptReply( | 142 void AppBannerDataFetcher::OnBannerPromptReply( |
| 139 content::RenderFrameHost* render_frame_host, | 143 content::RenderFrameHost* render_frame_host, |
| 140 int request_id, | 144 int request_id, |
| 141 blink::WebAppBannerPromptReply reply) { | 145 blink::WebAppBannerPromptReply reply) { |
| 142 content::WebContents* web_contents = GetWebContents(); | 146 content::WebContents* web_contents = GetWebContents(); |
| 143 if (!is_active_ || !web_contents || request_id != event_request_id_) { | 147 if (!CheckFetcherIsStillAlive(web_contents, "user navigated") || |
| 148 request_id != event_request_id_) { | |
| 144 Cancel(); | 149 Cancel(); |
| 145 return; | 150 return; |
| 146 } | 151 } |
| 147 | 152 |
| 148 // The renderer might have requested the prompt to be canceled. | 153 // The renderer might have requested the prompt to be canceled. |
| 149 if (reply == blink::WebAppBannerPromptReply::Cancel) { | 154 if (reply == blink::WebAppBannerPromptReply::Cancel) { |
| 155 // TODO(mlamouri,benwells): we should probably record that to behave | |
|
benwells
2015/05/11 08:08:40
This TODO has been removed, it must have come back
dominickn (DO NOT USE)
2015/05/12 07:41:31
Done.
| |
| 156 // differently with regard to showing the banner. | |
| 157 SendDebugMessage(web_contents, | |
| 158 "not shown: renderer has requested the banner prompt be cancelled"); | |
| 150 Cancel(); | 159 Cancel(); |
| 151 return; | 160 return; |
| 152 } | 161 } |
| 153 | 162 |
| 154 // Definitely going to show the banner now. | 163 // Definitely going to show the banner now. |
| 155 FOR_EACH_OBSERVER(Observer, observer_list_, | 164 FOR_EACH_OBSERVER(Observer, observer_list_, |
| 156 OnDecidedWhetherToShow(this, true)); | 165 OnDecidedWhetherToShow(this, true)); |
| 157 | 166 |
| 158 infobars::InfoBar* infobar = CreateBanner(app_icon_.get(), app_title_); | 167 infobars::InfoBar* infobar = CreateBanner(app_icon_.get(), app_title_); |
| 159 if (infobar) { | 168 if (infobar) { |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 224 GetCurrentTime()); | 233 GetCurrentTime()); |
| 225 rappor::SampleDomainAndRegistryFromGURL(g_browser_process->rappor_service(), | 234 rappor::SampleDomainAndRegistryFromGURL(g_browser_process->rappor_service(), |
| 226 event_name, | 235 event_name, |
| 227 web_contents->GetURL()); | 236 web_contents->GetURL()); |
| 228 banners::TrackDisplayEvent(DISPLAY_EVENT_CREATED); | 237 banners::TrackDisplayEvent(DISPLAY_EVENT_CREATED); |
| 229 } | 238 } |
| 230 | 239 |
| 231 void AppBannerDataFetcher::OnDidGetManifest( | 240 void AppBannerDataFetcher::OnDidGetManifest( |
| 232 const content::Manifest& manifest) { | 241 const content::Manifest& manifest) { |
| 233 content::WebContents* web_contents = GetWebContents(); | 242 content::WebContents* web_contents = GetWebContents(); |
| 234 if (!is_active_ || !web_contents || manifest.IsEmpty()) { | 243 if (!CheckFetcherIsStillAlive(web_contents, "manifest checking") || |
| 244 manifest.IsEmpty()) { | |
| 245 if (manifest.IsEmpty()) | |
|
benwells
2015/05/11 08:08:40
This is a little convoluted. It would probably be
dominickn (DO NOT USE)
2015/05/12 07:41:31
Done.
| |
| 246 SendDebugMessage(web_contents, "not shown: manifest is empty"); | |
| 235 Cancel(); | 247 Cancel(); |
| 236 return; | 248 return; |
| 237 } | 249 } |
| 238 | 250 |
| 239 if (manifest.prefer_related_applications && | 251 if (manifest.prefer_related_applications && |
| 240 manifest.related_applications.size()) { | 252 manifest.related_applications.size()) { |
| 241 for (const auto& application : manifest.related_applications) { | 253 for (const auto& application : manifest.related_applications) { |
| 242 std::string platform = base::UTF16ToUTF8(application.platform.string()); | 254 std::string platform = base::UTF16ToUTF8(application.platform.string()); |
| 243 std::string id = base::UTF16ToUTF8(application.id.string()); | 255 std::string id = base::UTF16ToUTF8(application.id.string()); |
| 244 if (weak_delegate_->HandleNonWebApp(platform, application.url, id)) | 256 if (weak_delegate_->HandleNonWebApp(platform, application.url, id)) |
| 245 return; | 257 return; |
| 246 } | 258 } |
| 247 } | 259 } |
| 248 | 260 |
| 249 if (!IsManifestValidForWebApp(manifest)) { | 261 if (!IsManifestValidForWebApp(manifest, web_contents)) { |
| 250 Cancel(); | 262 Cancel(); |
| 251 return; | 263 return; |
| 252 } | 264 } |
| 253 | 265 |
| 254 banners::TrackDisplayEvent(DISPLAY_EVENT_BANNER_REQUESTED); | 266 banners::TrackDisplayEvent(DISPLAY_EVENT_BANNER_REQUESTED); |
| 255 | 267 |
| 256 web_app_data_ = manifest; | 268 web_app_data_ = manifest; |
| 257 app_title_ = web_app_data_.name.string(); | 269 app_title_ = web_app_data_.name.string(); |
| 258 | 270 |
| 259 // Check to see if there is a single service worker controlling this page | 271 // Check to see if there is a single service worker controlling this page |
| 260 // and the manifest's start url. | 272 // and the manifest's start url. |
| 261 Profile* profile = | 273 Profile* profile = |
| 262 Profile::FromBrowserContext(web_contents->GetBrowserContext()); | 274 Profile::FromBrowserContext(web_contents->GetBrowserContext()); |
| 263 content::StoragePartition* storage_partition = | 275 content::StoragePartition* storage_partition = |
| 264 content::BrowserContext::GetStoragePartition( | 276 content::BrowserContext::GetStoragePartition( |
| 265 profile, web_contents->GetSiteInstance()); | 277 profile, web_contents->GetSiteInstance()); |
| 266 DCHECK(storage_partition); | 278 DCHECK(storage_partition); |
| 267 | 279 |
| 268 storage_partition->GetServiceWorkerContext()->CheckHasServiceWorker( | 280 storage_partition->GetServiceWorkerContext()->CheckHasServiceWorker( |
| 269 validated_url_, manifest.start_url, | 281 validated_url_, manifest.start_url, |
| 270 base::Bind(&AppBannerDataFetcher::OnDidCheckHasServiceWorker, | 282 base::Bind(&AppBannerDataFetcher::OnDidCheckHasServiceWorker, |
| 271 this)); | 283 this)); |
| 272 } | 284 } |
| 273 | 285 |
| 274 void AppBannerDataFetcher::OnDidCheckHasServiceWorker( | 286 void AppBannerDataFetcher::OnDidCheckHasServiceWorker( |
| 275 bool has_service_worker) { | 287 bool has_service_worker) { |
| 276 content::WebContents* web_contents = GetWebContents(); | 288 content::WebContents* web_contents = GetWebContents(); |
| 277 if (!is_active_ || !web_contents) { | 289 if (!CheckFetcherIsStillAlive(web_contents, "service worker checking")) { |
| 278 Cancel(); | 290 Cancel(); |
| 279 return; | 291 return; |
| 280 } | 292 } |
| 281 | 293 |
| 282 if (has_service_worker) { | 294 if (has_service_worker) { |
| 283 // Create an infobar to promote the manifest's app. | 295 // Create an infobar to promote the manifest's app. |
| 284 GURL icon_url = | 296 GURL icon_url = |
| 285 ManifestIconSelector::FindBestMatchingIcon( | 297 ManifestIconSelector::FindBestMatchingIcon( |
| 286 web_app_data_.icons, | 298 web_app_data_.icons, |
| 287 ideal_icon_size_, | 299 ideal_icon_size_, |
| 288 gfx::Screen::GetScreenFor(web_contents->GetNativeView())); | 300 gfx::Screen::GetScreenFor(web_contents->GetNativeView())); |
| 289 if (!icon_url.is_empty()) { | 301 if (!icon_url.is_empty()) { |
| 290 FetchIcon(icon_url); | 302 FetchIcon(icon_url); |
| 291 return; | 303 return; |
| 292 } | 304 } |
| 305 SendDebugMessage(web_contents, | |
| 306 "not shown: could not find icon specified in manifest"); | |
|
benwells
2015/05/11 08:08:40
I don't really understand how this could happen as
dominickn (DO NOT USE)
2015/05/12 07:41:30
Done.
| |
| 293 } else { | 307 } else { |
| 294 TrackDisplayEvent(DISPLAY_EVENT_LACKS_SERVICE_WORKER); | 308 TrackDisplayEvent(DISPLAY_EVENT_LACKS_SERVICE_WORKER); |
| 309 SendDebugMessage(web_contents, | |
| 310 "not shown: no service worker detected. You may need to " | |
| 311 "reload the page, or check that the manifest URL matches " | |
| 312 "the page URL"); | |
|
benwells
2015/05/11 08:08:40
This error is great but could still be improved. T
dominickn (DO NOT USE)
2015/05/12 07:41:31
Done.
dominickn (DO NOT USE)
2015/05/12 07:41:31
Done.
| |
| 295 } | 313 } |
| 296 | 314 |
| 297 Cancel(); | 315 Cancel(); |
| 298 } | 316 } |
| 299 | 317 |
| 300 void AppBannerDataFetcher::OnFetchComplete(const GURL& url, | 318 void AppBannerDataFetcher::OnFetchComplete(const GURL& url, |
| 301 const SkBitmap* icon) { | 319 const SkBitmap* icon) { |
| 302 if (is_active_) | 320 if (is_active_) |
| 303 ShowBanner(icon); | 321 ShowBanner(icon); |
| 304 | 322 |
| 305 Release(); | 323 Release(); |
| 306 } | 324 } |
| 307 | 325 |
| 308 void AppBannerDataFetcher::ShowBanner(const SkBitmap* icon) { | 326 void AppBannerDataFetcher::ShowBanner(const SkBitmap* icon) { |
| 309 content::WebContents* web_contents = GetWebContents(); | 327 content::WebContents* web_contents = GetWebContents(); |
| 310 if (!is_active_ || !web_contents || !icon) { | 328 if (!CheckFetcherIsStillAlive(web_contents, "banner display") || !icon) { |
| 329 if (!icon) | |
| 330 SendDebugMessage(web_contents, "not shown: no icon available to display"); | |
|
benwells
2015/05/11 08:08:40
Ditto about separating into two ifs.
dominickn (DO NOT USE)
2015/05/12 07:41:31
Done.
| |
| 311 Cancel(); | 331 Cancel(); |
| 312 return; | 332 return; |
| 313 } | 333 } |
| 314 | 334 |
| 315 RecordCouldShowBanner(); | 335 RecordCouldShowBanner(); |
| 316 if (!CheckIfShouldShowBanner()) { | 336 if (!CheckIfShouldShowBanner()) { |
| 337 SendDebugMessage(web_contents, "not shown: engagement checks failed"); | |
|
benwells
2015/05/11 08:08:40
This one is tricky. The only way a message will ge
dominickn (DO NOT USE)
2015/05/12 07:41:30
Done.
| |
| 317 Cancel(); | 338 Cancel(); |
| 318 return; | 339 return; |
| 319 } | 340 } |
| 320 | 341 |
| 342 SendDebugMessage(web_contents, "shown"); | |
|
benwells
2015/05/11 08:08:40
I don't think it is necessary to output this. This
dominickn (DO NOT USE)
2015/05/12 07:41:31
Done.
| |
| 321 app_icon_.reset(new SkBitmap(*icon)); | 343 app_icon_.reset(new SkBitmap(*icon)); |
| 322 event_request_id_ = ++gCurrentRequestID; | 344 event_request_id_ = ++gCurrentRequestID; |
| 323 web_contents->GetMainFrame()->Send( | 345 web_contents->GetMainFrame()->Send( |
| 324 new ChromeViewMsg_AppBannerPromptRequest( | 346 new ChromeViewMsg_AppBannerPromptRequest( |
| 325 web_contents->GetMainFrame()->GetRoutingID(), | 347 web_contents->GetMainFrame()->GetRoutingID(), |
| 326 event_request_id_, | 348 event_request_id_, |
| 327 GetBannerType())); | 349 GetBannerType())); |
| 328 } | 350 } |
| 329 | 351 |
| 330 void AppBannerDataFetcher::RecordCouldShowBanner() { | 352 void AppBannerDataFetcher::RecordCouldShowBanner() { |
| 331 content::WebContents* web_contents = GetWebContents(); | 353 content::WebContents* web_contents = GetWebContents(); |
| 332 DCHECK(web_contents); | 354 DCHECK(web_contents); |
| 333 | 355 |
| 334 AppBannerSettingsHelper::RecordBannerEvent( | 356 AppBannerSettingsHelper::RecordBannerEvent( |
| 335 web_contents, validated_url_, GetAppIdentifier(), | 357 web_contents, validated_url_, GetAppIdentifier(), |
| 336 AppBannerSettingsHelper::APP_BANNER_EVENT_COULD_SHOW, | 358 AppBannerSettingsHelper::APP_BANNER_EVENT_COULD_SHOW, |
| 337 GetCurrentTime()); | 359 GetCurrentTime()); |
| 338 } | 360 } |
| 339 | 361 |
| 340 bool AppBannerDataFetcher::CheckIfShouldShowBanner() { | 362 bool AppBannerDataFetcher::CheckIfShouldShowBanner() { |
| 341 content::WebContents* web_contents = GetWebContents(); | 363 content::WebContents* web_contents = GetWebContents(); |
| 342 DCHECK(web_contents); | 364 DCHECK(web_contents); |
| 343 | 365 |
| 344 return AppBannerSettingsHelper::ShouldShowBanner( | 366 return AppBannerSettingsHelper::ShouldShowBanner( |
| 345 web_contents, validated_url_, GetAppIdentifier(), GetCurrentTime()); | 367 web_contents, validated_url_, GetAppIdentifier(), GetCurrentTime()); |
| 346 } | 368 } |
| 347 | 369 |
| 370 bool AppBannerDataFetcher::CheckFetcherIsStillAlive( | |
| 371 content::WebContents* web_contents, | |
| 372 const std::string& section) { | |
| 373 if (!is_active_) { | |
| 374 SendDebugMessage(web_contents, | |
| 375 "not shown: display pipeline halted before " + section); | |
|
benwells
2015/05/11 08:08:40
This message is too detailed. Please update to som
dominickn (DO NOT USE)
2015/05/12 07:41:30
Done.
| |
| 376 return false; | |
| 377 } | |
| 378 if (!web_contents) | |
| 379 return false; | |
|
benwells
2015/05/11 08:08:40
For completeness a message here would be good, lik
dominickn (DO NOT USE)
2015/05/12 07:41:31
But if the web_contents pointer doesn't exist, we
| |
| 380 return true; | |
| 381 } | |
| 382 | |
| 348 // static | 383 // static |
| 349 bool AppBannerDataFetcher::IsManifestValidForWebApp( | 384 bool AppBannerDataFetcher::IsManifestValidForWebApp( |
| 350 const content::Manifest& manifest) { | 385 const content::Manifest& manifest, |
| 351 if (manifest.IsEmpty()) | 386 content::WebContents* web_contents) { |
| 387 if (manifest.IsEmpty()) { | |
| 388 SendDebugMessage(web_contents, "not shown: manifest is empty"); | |
| 352 return false; | 389 return false; |
| 353 if (!manifest.start_url.is_valid()) | 390 } |
| 391 if (!manifest.start_url.is_valid()) { | |
| 392 SendDebugMessage(web_contents, | |
| 393 "not shown: start URL in manifest is not valid"); | |
| 354 return false; | 394 return false; |
| 355 if (manifest.name.is_null() && manifest.short_name.is_null()) | 395 } |
| 396 if (manifest.name.is_null() && manifest.short_name.is_null()) { | |
| 397 SendDebugMessage(web_contents, | |
| 398 "not shown: manifest name and short name are missing"); | |
|
benwells
2015/05/11 08:08:40
It would be good to capture in the error that only
dominickn (DO NOT USE)
2015/05/12 07:41:31
Done.
| |
| 356 return false; | 399 return false; |
| 357 if (!DoesManifestContainRequiredIcon(manifest)) | 400 } |
| 401 if (!DoesManifestContainRequiredIcon(manifest)) { | |
| 402 SendDebugMessage(web_contents, | |
| 403 "not shown: manifest does not contain a suitable icon"); | |
|
benwells
2015/05/11 08:08:40
It would be good to capture more details about wha
dominickn (DO NOT USE)
2015/05/12 07:41:31
Done.
| |
| 358 return false; | 404 return false; |
| 405 } | |
| 359 return true; | 406 return true; |
| 360 } | 407 } |
| 361 | 408 |
| 362 } // namespace banners | 409 } // namespace banners |
| OLD | NEW |