| 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_manager.h" | 5 #include "chrome/browser/banners/app_banner_manager.h" |
| 6 | 6 |
| 7 #include <algorithm> |
| 8 |
| 7 #include "base/bind.h" | 9 #include "base/bind.h" |
| 8 #include "base/callback.h" | 10 #include "base/callback.h" |
| 9 #include "base/command_line.h" | 11 #include "base/command_line.h" |
| 10 #include "base/strings/string_number_conversions.h" | 12 #include "base/strings/string_number_conversions.h" |
| 11 #include "base/time/time.h" | 13 #include "base/time/time.h" |
| 12 #include "chrome/browser/banners/app_banner_metrics.h" | 14 #include "chrome/browser/banners/app_banner_metrics.h" |
| 13 #include "chrome/browser/banners/app_banner_settings_helper.h" | 15 #include "chrome/browser/banners/app_banner_settings_helper.h" |
| 14 #include "chrome/browser/browser_process.h" | 16 #include "chrome/browser/browser_process.h" |
| 15 #include "chrome/browser/engagement/site_engagement_service.h" | 17 #include "chrome/browser/engagement/site_engagement_service.h" |
| 16 #include "chrome/browser/installable/installable_logging.h" | |
| 17 #include "chrome/browser/installable/installable_manager.h" | |
| 18 #include "chrome/browser/profiles/profile.h" | 18 #include "chrome/browser/profiles/profile.h" |
| 19 #include "chrome/common/chrome_switches.h" | 19 #include "chrome/common/chrome_switches.h" |
| 20 #include "chrome/common/render_messages.h" | |
| 21 #include "components/rappor/rappor_utils.h" | 20 #include "components/rappor/rappor_utils.h" |
| 22 #include "content/public/browser/navigation_handle.h" | 21 #include "content/public/browser/navigation_handle.h" |
| 23 #include "content/public/browser/render_frame_host.h" | 22 #include "content/public/browser/render_frame_host.h" |
| 24 #include "content/public/browser/web_contents.h" | 23 #include "content/public/browser/web_contents.h" |
| 25 #include "content/public/common/origin_util.h" | 24 #include "content/public/common/origin_util.h" |
| 26 #include "third_party/WebKit/public/platform/modules/app_banner/WebAppBannerProm
ptReply.h" | 25 #include "services/service_manager/public/cpp/interface_provider.h" |
| 27 #include "third_party/skia/include/core/SkBitmap.h" | 26 #include "third_party/skia/include/core/SkBitmap.h" |
| 28 #include "ui/display/display.h" | 27 #include "ui/display/display.h" |
| 29 #include "ui/display/screen.h" | 28 #include "ui/display/screen.h" |
| 30 | 29 |
| 31 namespace { | 30 namespace { |
| 32 | 31 |
| 33 bool gDisableSecureCheckForTesting = false; | 32 bool gDisableSecureCheckForTesting = false; |
| 34 int gCurrentRequestID = -1; | 33 int gCurrentRequestID = -1; |
| 35 base::LazyInstance<base::TimeDelta> gTimeDeltaForTesting = | 34 int gTimeDeltaInDaysForTesting = 0; |
| 36 LAZY_INSTANCE_INITIALIZER; | |
| 37 | 35 |
| 38 // Returns |size_in_px| in dp, i.e. divided by the current device scale factor. | 36 // Returns |size_in_px| in dp, i.e. divided by the current device scale factor. |
| 39 int ConvertIconSizeFromPxToDp(int size_in_px) { | 37 int ConvertIconSizeFromPxToDp(int size_in_px) { |
| 40 return size_in_px / | 38 return size_in_px / |
| 41 display::Screen::GetScreen()->GetPrimaryDisplay().device_scale_factor(); | 39 display::Screen::GetScreen()->GetPrimaryDisplay().device_scale_factor(); |
| 42 } | 40 } |
| 43 | 41 |
| 44 InstallableParams ParamsToGetManifest() { | 42 InstallableParams ParamsToGetManifest() { |
| 45 return InstallableParams(); | 43 return InstallableParams(); |
| 46 } | 44 } |
| (...skipping 15 matching lines...) Expand all Loading... |
| 62 | 60 |
| 63 namespace banners { | 61 namespace banners { |
| 64 | 62 |
| 65 // static | 63 // static |
| 66 void AppBannerManager::DisableSecureSchemeCheckForTesting() { | 64 void AppBannerManager::DisableSecureSchemeCheckForTesting() { |
| 67 gDisableSecureCheckForTesting = true; | 65 gDisableSecureCheckForTesting = true; |
| 68 } | 66 } |
| 69 | 67 |
| 70 // static | 68 // static |
| 71 base::Time AppBannerManager::GetCurrentTime() { | 69 base::Time AppBannerManager::GetCurrentTime() { |
| 72 return base::Time::Now() + gTimeDeltaForTesting.Get(); | 70 return base::Time::Now() + |
| 71 base::TimeDelta::FromDays(gTimeDeltaInDaysForTesting); |
| 73 } | 72 } |
| 74 | 73 |
| 75 // static | 74 // static |
| 76 void AppBannerManager::SetTimeDeltaForTesting(int days) { | 75 void AppBannerManager::SetTimeDeltaForTesting(int days) { |
| 77 gTimeDeltaForTesting.Get() = base::TimeDelta::FromDays(days); | 76 gTimeDeltaInDaysForTesting = days; |
| 78 } | 77 } |
| 79 | 78 |
| 80 // static | 79 // static |
| 81 void AppBannerManager::SetEngagementWeights(double direct_engagement, | 80 void AppBannerManager::SetEngagementWeights(double direct_engagement, |
| 82 double indirect_engagement) { | 81 double indirect_engagement) { |
| 83 AppBannerSettingsHelper::SetEngagementWeights(direct_engagement, | 82 AppBannerSettingsHelper::SetEngagementWeights(direct_engagement, |
| 84 indirect_engagement); | 83 indirect_engagement); |
| 85 } | 84 } |
| 86 | 85 |
| 87 // static | 86 // static |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 122 if (!content::IsOriginSecure(validated_url) && | 121 if (!content::IsOriginSecure(validated_url) && |
| 123 !gDisableSecureCheckForTesting) { | 122 !gDisableSecureCheckForTesting) { |
| 124 ReportStatus(contents, NOT_FROM_SECURE_ORIGIN); | 123 ReportStatus(contents, NOT_FROM_SECURE_ORIGIN); |
| 125 Stop(); | 124 Stop(); |
| 126 return; | 125 return; |
| 127 } | 126 } |
| 128 | 127 |
| 129 if (validated_url_.is_empty()) | 128 if (validated_url_.is_empty()) |
| 130 validated_url_ = validated_url; | 129 validated_url_ = validated_url; |
| 131 | 130 |
| 131 // Any existing binding is invalid when we request a new banner. |
| 132 if (binding_.is_bound()) |
| 133 binding_.Close(); |
| 134 |
| 132 manager_->GetData( | 135 manager_->GetData( |
| 133 ParamsToGetManifest(), | 136 ParamsToGetManifest(), |
| 134 base::Bind(&AppBannerManager::OnDidGetManifest, GetWeakPtr())); | 137 base::Bind(&AppBannerManager::OnDidGetManifest, GetWeakPtr())); |
| 135 } | 138 } |
| 136 | 139 |
| 140 void AppBannerManager::SendBannerAccepted(int request_id) { |
| 141 if (request_id != gCurrentRequestID) |
| 142 return; |
| 143 |
| 144 DCHECK(event_.is_bound()); |
| 145 event_->BannerAccepted(GetBannerType()); |
| 146 } |
| 147 |
| 148 void AppBannerManager::SendBannerDismissed(int request_id) { |
| 149 if (request_id != gCurrentRequestID) |
| 150 return; |
| 151 |
| 152 DCHECK(event_.is_bound()); |
| 153 event_->BannerDismissed(); |
| 154 } |
| 155 |
| 137 base::Closure AppBannerManager::FetchWebappSplashScreenImageCallback( | 156 base::Closure AppBannerManager::FetchWebappSplashScreenImageCallback( |
| 138 const std::string& webapp_id) { | 157 const std::string& webapp_id) { |
| 139 return base::Closure(); | 158 return base::Closure(); |
| 140 } | 159 } |
| 141 | 160 |
| 142 AppBannerManager::AppBannerManager(content::WebContents* web_contents) | 161 AppBannerManager::AppBannerManager(content::WebContents* web_contents) |
| 143 : content::WebContentsObserver(web_contents), | 162 : content::WebContentsObserver(web_contents), |
| 144 SiteEngagementObserver(nullptr), | 163 SiteEngagementObserver(nullptr), |
| 145 manager_(nullptr), | 164 manager_(nullptr), |
| 146 event_request_id_(-1), | 165 event_request_id_(-1), |
| 166 binding_(this), |
| 147 is_active_(false), | 167 is_active_(false), |
| 148 banner_request_queued_(false), | 168 banner_request_queued_(false), |
| 149 load_finished_(false), | 169 load_finished_(false), |
| 150 was_canceled_by_page_(false), | 170 was_canceled_by_page_(false), |
| 151 page_requested_prompt_(false), | 171 page_requested_prompt_(false), |
| 152 is_debug_mode_(false), | 172 is_debug_mode_(false), |
| 153 need_to_log_status_(false), | 173 need_to_log_status_(false), |
| 154 weak_factory_(this) { | 174 weak_factory_(this) { |
| 155 // Ensure the InstallableManager exists since we have a hard dependency on it. | 175 // Ensure the InstallableManager exists since we have a hard dependency on it. |
| 156 InstallableManager::CreateForWebContents(web_contents); | 176 InstallableManager::CreateForWebContents(web_contents); |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 302 } | 322 } |
| 303 | 323 |
| 304 // In every non-debug run through the banner pipeline, we should have called | 324 // In every non-debug run through the banner pipeline, we should have called |
| 305 // ReportStatus() and set need_to_log_status_ to false. The only case where | 325 // ReportStatus() and set need_to_log_status_ to false. The only case where |
| 306 // we don't is if we're still active and waiting for a callback from the | 326 // we don't is if we're still active and waiting for a callback from the |
| 307 // InstallableManager (e.g. the renderer crashes or the browser is shutting | 327 // InstallableManager (e.g. the renderer crashes or the browser is shutting |
| 308 // down). These situations are explicitly not logged. | 328 // down). These situations are explicitly not logged. |
| 309 DCHECK(!need_to_log_status_ || is_active_); | 329 DCHECK(!need_to_log_status_ || is_active_); |
| 310 | 330 |
| 311 weak_factory_.InvalidateWeakPtrs(); | 331 weak_factory_.InvalidateWeakPtrs(); |
| 332 binding_.Close(); |
| 333 controller_.reset(); |
| 334 event_.reset(); |
| 335 |
| 312 is_active_ = false; | 336 is_active_ = false; |
| 313 was_canceled_by_page_ = false; | 337 was_canceled_by_page_ = false; |
| 314 page_requested_prompt_ = false; | 338 page_requested_prompt_ = false; |
| 315 need_to_log_status_ = false; | 339 need_to_log_status_ = false; |
| 316 validated_url_ = GURL(); | 340 validated_url_ = GURL(); |
| 317 referrer_.erase(); | 341 referrer_.erase(); |
| 318 } | 342 } |
| 319 | 343 |
| 320 void AppBannerManager::SendBannerPromptRequest() { | 344 void AppBannerManager::SendBannerPromptRequest() { |
| 321 RecordCouldShowBanner(); | 345 RecordCouldShowBanner(); |
| 322 | 346 |
| 323 // Given all of the other checks that have been made, the only possible reason | 347 // Given all of the other checks that have been made, the only possible reason |
| 324 // for stopping now is that the app has been added to the homescreen. | 348 // for stopping now is that the app has been added to the homescreen. |
| 325 if (!IsDebugMode() && !CheckIfShouldShowBanner()) { | 349 if (!IsDebugMode() && !CheckIfShouldShowBanner()) { |
| 326 Stop(); | 350 Stop(); |
| 327 return; | 351 return; |
| 328 } | 352 } |
| 329 | 353 |
| 330 TrackBeforeInstallEvent(BEFORE_INSTALL_EVENT_CREATED); | 354 TrackBeforeInstallEvent(BEFORE_INSTALL_EVENT_CREATED); |
| 331 event_request_id_ = ++gCurrentRequestID; | 355 event_request_id_ = ++gCurrentRequestID; |
| 332 content::RenderFrameHost* frame = web_contents()->GetMainFrame(); | 356 |
| 333 frame->Send(new ChromeViewMsg_AppBannerPromptRequest( | 357 web_contents()->GetMainFrame()->GetRemoteInterfaces()->GetInterface( |
| 334 frame->GetRoutingID(), event_request_id_, GetBannerType())); | 358 mojo::GetProxy(&controller_)); |
| 359 |
| 360 controller_->BannerPromptRequest( |
| 361 binding_.CreateInterfacePtrAndBind(), mojo::GetProxy(&event_), |
| 362 {GetBannerType()}, |
| 363 base::Bind(&AppBannerManager::OnBannerPromptReply, GetWeakPtr())); |
| 335 } | 364 } |
| 336 | 365 |
| 337 void AppBannerManager::DidStartNavigation(content::NavigationHandle* handle) { | 366 void AppBannerManager::DidStartNavigation(content::NavigationHandle* handle) { |
| 338 if (!handle->IsInMainFrame()) | 367 if (!handle->IsInMainFrame()) |
| 339 return; | 368 return; |
| 340 | 369 |
| 341 load_finished_ = false; | 370 load_finished_ = false; |
| 342 if (AppBannerSettingsHelper::ShouldUseSiteEngagementScore() && | 371 if (AppBannerSettingsHelper::ShouldUseSiteEngagementScore() && |
| 343 GetSiteEngagementService() == nullptr) { | 372 GetSiteEngagementService() == nullptr) { |
| 344 // Ensure that we are observing the site engagement service on navigation | 373 // Ensure that we are observing the site engagement service on navigation |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 453 } | 482 } |
| 454 | 483 |
| 455 // If we are in debug mode, AppBannerSettingsHelper::ShouldShowBanner must | 484 // If we are in debug mode, AppBannerSettingsHelper::ShouldShowBanner must |
| 456 // return NO_ERROR_DETECTED (bypass flag is set) or we must not have entered | 485 // return NO_ERROR_DETECTED (bypass flag is set) or we must not have entered |
| 457 // this method. | 486 // this method. |
| 458 DCHECK(!IsDebugMode()); | 487 DCHECK(!IsDebugMode()); |
| 459 ReportStatus(web_contents(), code); | 488 ReportStatus(web_contents(), code); |
| 460 return false; | 489 return false; |
| 461 } | 490 } |
| 462 | 491 |
| 463 bool AppBannerManager::OnMessageReceived( | |
| 464 const IPC::Message& message, | |
| 465 content::RenderFrameHost* render_frame_host) { | |
| 466 bool handled = true; | |
| 467 | |
| 468 IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(AppBannerManager, message, render_frame_host) | |
| 469 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_AppBannerPromptReply, | |
| 470 OnBannerPromptReply) | |
| 471 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_RequestShowAppBanner, | |
| 472 OnRequestShowAppBanner) | |
| 473 IPC_MESSAGE_UNHANDLED(handled = false) | |
| 474 IPC_END_MESSAGE_MAP() | |
| 475 | |
| 476 return handled; | |
| 477 } | |
| 478 | |
| 479 void AppBannerManager::OnBannerPromptReply( | 492 void AppBannerManager::OnBannerPromptReply( |
| 480 content::RenderFrameHost* render_frame_host, | 493 blink::mojom::AppBannerPromptReply reply, |
| 481 int request_id, | 494 const std::string& referrer) { |
| 482 blink::WebAppBannerPromptReply reply, | 495 // We don't need the controller any more, so reset it so the Blink-side object |
| 483 std::string referrer) { | 496 // is destroyed. |
| 497 controller_.reset(); |
| 484 content::WebContents* contents = web_contents(); | 498 content::WebContents* contents = web_contents(); |
| 485 if (request_id != event_request_id_) | |
| 486 return; | |
| 487 | 499 |
| 488 // The renderer might have requested the prompt to be canceled. | 500 // The renderer might have requested the prompt to be canceled. |
| 489 // They may request that it is redisplayed later, so don't Stop() here. | 501 // They may request that it is redisplayed later, so don't Stop() here. |
| 490 // However, log that the cancelation was requested, so Stop() can be | 502 // However, log that the cancelation was requested, so Stop() can be |
| 491 // called if a redisplay isn't asked for. | 503 // called if a redisplay isn't asked for. |
| 492 // | 504 // |
| 493 // We use the additional page_requested_prompt_ variable because the redisplay | 505 // We use the additional page_requested_prompt_ variable because the redisplay |
| 494 // request may be received *before* the Cancel prompt reply (e.g. if redisplay | 506 // request may be received *before* the Cancel prompt reply (e.g. if redisplay |
| 495 // is requested in the beforeinstallprompt event handler). | 507 // is requested in the beforeinstallprompt event handler). |
| 496 referrer_ = referrer; | 508 referrer_ = referrer; |
| 497 if (reply == blink::WebAppBannerPromptReply::Cancel && | 509 if (reply == blink::mojom::AppBannerPromptReply::CANCEL && |
| 498 !page_requested_prompt_) { | 510 !page_requested_prompt_) { |
| 499 TrackBeforeInstallEvent(BEFORE_INSTALL_EVENT_PREVENT_DEFAULT_CALLED); | 511 TrackBeforeInstallEvent(BEFORE_INSTALL_EVENT_PREVENT_DEFAULT_CALLED); |
| 500 was_canceled_by_page_ = true; | 512 was_canceled_by_page_ = true; |
| 501 return; | 513 return; |
| 502 } | 514 } |
| 503 | 515 |
| 504 // If we haven't yet returned, but either of |was_canceled_by_page_| or | 516 // If we haven't yet returned, but either of |was_canceled_by_page_| or |
| 505 // |page_requested_prompt_| is true, the page has requested a delayed showing | 517 // |page_requested_prompt_| is true, the page has requested a delayed showing |
| 506 // of the prompt. Otherwise, the prompt was never canceled by the page. | 518 // of the prompt. Otherwise, the prompt was never canceled by the page. |
| 507 if (was_canceled_by_page_ || page_requested_prompt_) { | 519 if (was_canceled_by_page_ || page_requested_prompt_) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 518 DCHECK(!manifest_url_.is_empty()); | 530 DCHECK(!manifest_url_.is_empty()); |
| 519 DCHECK(!manifest_.IsEmpty()); | 531 DCHECK(!manifest_.IsEmpty()); |
| 520 DCHECK(!icon_url_.is_empty()); | 532 DCHECK(!icon_url_.is_empty()); |
| 521 DCHECK(icon_.get()); | 533 DCHECK(icon_.get()); |
| 522 | 534 |
| 523 TrackBeforeInstallEvent(BEFORE_INSTALL_EVENT_COMPLETE); | 535 TrackBeforeInstallEvent(BEFORE_INSTALL_EVENT_COMPLETE); |
| 524 ShowBanner(); | 536 ShowBanner(); |
| 525 is_active_ = false; | 537 is_active_ = false; |
| 526 } | 538 } |
| 527 | 539 |
| 528 void AppBannerManager::OnRequestShowAppBanner( | 540 void AppBannerManager::DisplayAppBanner() { |
| 529 content::RenderFrameHost* render_frame_host, | |
| 530 int request_id) { | |
| 531 if (was_canceled_by_page_) { | 541 if (was_canceled_by_page_) { |
| 532 // Simulate a non-canceled OnBannerPromptReply to show the delayed banner. | 542 // Simulate a non-canceled OnBannerPromptReply to show the delayed banner. |
| 533 // Don't reset |was_canceled_by_page_| yet for metrics purposes. | 543 // Don't reset |was_canceled_by_page_| yet for metrics purposes. |
| 534 OnBannerPromptReply(render_frame_host, request_id, | 544 OnBannerPromptReply(blink::mojom::AppBannerPromptReply::NONE, referrer_); |
| 535 blink::WebAppBannerPromptReply::None, referrer_); | |
| 536 } else { | 545 } else { |
| 537 // Log that the prompt request was made for when we get the prompt reply. | 546 // Log that the prompt request was made for when we get the prompt reply. |
| 538 page_requested_prompt_ = true; | 547 page_requested_prompt_ = true; |
| 539 } | 548 } |
| 540 } | 549 } |
| 541 | 550 |
| 542 } // namespace banners | 551 } // namespace banners |
| OLD | NEW |