| Index: chrome/browser/banners/app_banner_data_fetcher.cc
|
| diff --git a/chrome/browser/banners/app_banner_data_fetcher.cc b/chrome/browser/banners/app_banner_data_fetcher.cc
|
| deleted file mode 100644
|
| index 3cc28110a712364b55f59d0882d320ef6c75e952..0000000000000000000000000000000000000000
|
| --- a/chrome/browser/banners/app_banner_data_fetcher.cc
|
| +++ /dev/null
|
| @@ -1,496 +0,0 @@
|
| -// Copyright 2015 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "chrome/browser/banners/app_banner_data_fetcher.h"
|
| -
|
| -#include "base/bind.h"
|
| -#include "base/command_line.h"
|
| -#include "base/lazy_instance.h"
|
| -#include "base/strings/string_number_conversions.h"
|
| -#include "base/strings/string_util.h"
|
| -#include "base/strings/utf_string_conversions.h"
|
| -#include "chrome/browser/banners/app_banner_debug_log.h"
|
| -#include "chrome/browser/banners/app_banner_metrics.h"
|
| -#include "chrome/browser/banners/app_banner_settings_helper.h"
|
| -#include "chrome/browser/browser_process.h"
|
| -#include "chrome/browser/manifest/manifest_icon_downloader.h"
|
| -#include "chrome/browser/manifest/manifest_icon_selector.h"
|
| -#include "chrome/browser/profiles/profile.h"
|
| -#include "chrome/common/chrome_switches.h"
|
| -#include "chrome/common/render_messages.h"
|
| -#include "components/rappor/rappor_utils.h"
|
| -#include "content/public/browser/browser_context.h"
|
| -#include "content/public/browser/browser_thread.h"
|
| -#include "content/public/browser/navigation_details.h"
|
| -#include "content/public/browser/render_frame_host.h"
|
| -#include "content/public/browser/service_worker_context.h"
|
| -#include "content/public/browser/storage_partition.h"
|
| -#include "net/base/load_flags.h"
|
| -#include "third_party/WebKit/public/platform/WebDisplayMode.h"
|
| -#include "third_party/WebKit/public/platform/modules/app_banner/WebAppBannerPromptReply.h"
|
| -
|
| -namespace {
|
| -
|
| -base::LazyInstance<base::TimeDelta> gTimeDeltaForTesting =
|
| - LAZY_INSTANCE_INITIALIZER;
|
| -int gCurrentRequestID = -1;
|
| -const char kPngExtension[] = ".png";
|
| -
|
| -// The requirement for now is an image/png that is at least 144x144.
|
| -const int kIconMinimumSize = 144;
|
| -bool DoesManifestContainRequiredIcon(const content::Manifest& manifest) {
|
| - for (const auto& icon : manifest.icons) {
|
| - // The type field is optional. If it isn't present, fall back on checking
|
| - // the src extension, and allow the icon if the extension ends with png.
|
| - if (!base::EqualsASCII(icon.type.string(), "image/png") &&
|
| - !(icon.type.is_null() &&
|
| - base::EndsWith(icon.src.ExtractFileName(), kPngExtension,
|
| - base::CompareCase::INSENSITIVE_ASCII)))
|
| - continue;
|
| -
|
| - for (const auto& size : icon.sizes) {
|
| - if (size.IsEmpty()) // "any"
|
| - return true;
|
| - if (size.width() >= kIconMinimumSize && size.height() >= kIconMinimumSize)
|
| - return true;
|
| - }
|
| - }
|
| -
|
| - return false;
|
| -}
|
| -
|
| -} // anonymous namespace
|
| -
|
| -namespace banners {
|
| -
|
| -// static
|
| -base::Time AppBannerDataFetcher::GetCurrentTime() {
|
| - return base::Time::Now() + gTimeDeltaForTesting.Get();
|
| -}
|
| -
|
| -// static
|
| -void AppBannerDataFetcher::SetTimeDeltaForTesting(int days) {
|
| - gTimeDeltaForTesting.Get() = base::TimeDelta::FromDays(days);
|
| -}
|
| -
|
| -AppBannerDataFetcher::AppBannerDataFetcher(content::WebContents* web_contents,
|
| - base::WeakPtr<Delegate> delegate,
|
| - int ideal_icon_size_in_dp,
|
| - int minimum_icon_size_in_dp,
|
| - bool is_debug_mode)
|
| - : WebContentsObserver(web_contents),
|
| - weak_delegate_(delegate),
|
| - ideal_icon_size_in_dp_(ideal_icon_size_in_dp),
|
| - minimum_icon_size_in_dp_(minimum_icon_size_in_dp),
|
| - is_active_(false),
|
| - was_canceled_by_page_(false),
|
| - page_requested_prompt_(false),
|
| - is_debug_mode_(is_debug_mode ||
|
| - base::CommandLine::ForCurrentProcess()->HasSwitch(
|
| - switches::kBypassAppBannerEngagementChecks)),
|
| - event_request_id_(-1) {
|
| - DCHECK(minimum_icon_size_in_dp <= ideal_icon_size_in_dp);
|
| -}
|
| -
|
| -void AppBannerDataFetcher::Start(const GURL& validated_url,
|
| - ui::PageTransition transition_type) {
|
| - DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
| -
|
| - content::WebContents* web_contents = GetWebContents();
|
| - DCHECK(web_contents);
|
| -
|
| - is_active_ = true;
|
| - was_canceled_by_page_ = false;
|
| - page_requested_prompt_ = false;
|
| - transition_type_ = transition_type;
|
| - validated_url_ = validated_url;
|
| - referrer_.erase();
|
| - web_contents->GetManifest(
|
| - base::Bind(&AppBannerDataFetcher::OnDidGetManifest, this));
|
| -}
|
| -
|
| -void AppBannerDataFetcher::Cancel() {
|
| - DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
|
| - if (is_active_) {
|
| - FOR_EACH_OBSERVER(Observer, observer_list_,
|
| - OnDecidedWhetherToShow(this, false));
|
| - if (was_canceled_by_page_ && !page_requested_prompt_) {
|
| - TrackBeforeInstallEvent(
|
| - BEFORE_INSTALL_EVENT_PROMPT_NOT_CALLED_AFTER_PREVENT_DEFAULT);
|
| - }
|
| -
|
| - is_active_ = false;
|
| - was_canceled_by_page_ = false;
|
| - page_requested_prompt_ = false;
|
| - referrer_.erase();
|
| - }
|
| -}
|
| -
|
| -void AppBannerDataFetcher::ReplaceWebContents(
|
| - content::WebContents* web_contents) {
|
| - Observe(web_contents);
|
| -}
|
| -
|
| -void AppBannerDataFetcher::AddObserverForTesting(Observer* observer) {
|
| - observer_list_.AddObserver(observer);
|
| -}
|
| -
|
| -void AppBannerDataFetcher::RemoveObserverForTesting(Observer* observer) {
|
| - observer_list_.RemoveObserver(observer);
|
| -}
|
| -
|
| -void AppBannerDataFetcher::WebContentsDestroyed() {
|
| - Cancel();
|
| - Observe(nullptr);
|
| -}
|
| -
|
| -void AppBannerDataFetcher::DidNavigateMainFrame(
|
| - const content::LoadCommittedDetails& details,
|
| - const content::FrameNavigateParams& params) {
|
| - if (!details.is_in_page)
|
| - Cancel();
|
| -}
|
| -
|
| -bool AppBannerDataFetcher::OnMessageReceived(
|
| - const IPC::Message& message, content::RenderFrameHost* render_frame_host) {
|
| - bool handled = true;
|
| -
|
| - IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(AppBannerDataFetcher, message,
|
| - render_frame_host)
|
| - IPC_MESSAGE_HANDLER(ChromeViewHostMsg_AppBannerPromptReply,
|
| - OnBannerPromptReply)
|
| - IPC_MESSAGE_HANDLER(ChromeViewHostMsg_RequestShowAppBanner,
|
| - OnRequestShowAppBanner)
|
| - IPC_MESSAGE_UNHANDLED(handled = false)
|
| - IPC_END_MESSAGE_MAP()
|
| -
|
| - return handled;
|
| -}
|
| -
|
| -void AppBannerDataFetcher::OnBannerPromptReply(
|
| - content::RenderFrameHost* render_frame_host,
|
| - int request_id,
|
| - blink::WebAppBannerPromptReply reply,
|
| - std::string referrer) {
|
| - content::WebContents* web_contents = GetWebContents();
|
| - if (!CheckFetcherIsStillAlive(web_contents) ||
|
| - request_id != event_request_id_) {
|
| - Cancel();
|
| - return;
|
| - }
|
| -
|
| - // The renderer might have requested the prompt to be canceled.
|
| - // They may request that it is redisplayed later, so don't Cancel() here.
|
| - // However, log that the cancelation was requested, so Cancel() can be
|
| - // called if a redisplay isn't asked for.
|
| - //
|
| - // The redisplay request may be received before the Cancel prompt reply
|
| - // *after* if it is made before the beforeinstallprompt event handler
|
| - // concludes (e.g. in the event handler itself), so allow the pipeline
|
| - // to continue in this case.
|
| - //
|
| - // Stash the referrer for the case where the banner is redisplayed.
|
| - if (reply == blink::WebAppBannerPromptReply::Cancel &&
|
| - !page_requested_prompt_) {
|
| - TrackBeforeInstallEvent(BEFORE_INSTALL_EVENT_PREVENT_DEFAULT_CALLED);
|
| - was_canceled_by_page_ = true;
|
| - referrer_ = referrer;
|
| - OutputDeveloperNotShownMessage(web_contents, kRendererRequestCancel,
|
| - is_debug_mode_);
|
| - return;
|
| - }
|
| -
|
| - // If we haven't yet returned, but either of |was_canceled_by_page_| or
|
| - // |page_requested_prompt_| is true, the page has requested a delayed showing
|
| - // of the prompt. Otherwise, the prompt was never canceled by the page.
|
| - if (was_canceled_by_page_ || page_requested_prompt_) {
|
| - TrackBeforeInstallEvent(
|
| - BEFORE_INSTALL_EVENT_PROMPT_CALLED_AFTER_PREVENT_DEFAULT);
|
| - was_canceled_by_page_ = false;
|
| - } else {
|
| - TrackBeforeInstallEvent(BEFORE_INSTALL_EVENT_NO_ACTION);
|
| - }
|
| -
|
| - AppBannerSettingsHelper::RecordMinutesFromFirstVisitToShow(
|
| - web_contents, validated_url_, GetAppIdentifier(), GetCurrentTime());
|
| -
|
| - // Definitely going to show the banner now.
|
| - FOR_EACH_OBSERVER(Observer, observer_list_,
|
| - OnDecidedWhetherToShow(this, true));
|
| -
|
| - TrackBeforeInstallEvent(BEFORE_INSTALL_EVENT_COMPLETE);
|
| - ShowBanner(app_icon_url_, app_icon_.get(), app_title_, referrer);
|
| - is_active_ = false;
|
| -}
|
| -
|
| -void AppBannerDataFetcher::OnRequestShowAppBanner(
|
| - content::RenderFrameHost* render_frame_host,
|
| - int request_id) {
|
| - if (was_canceled_by_page_) {
|
| - // Simulate an "OK" from the website to restart the banner display pipeline.
|
| - // Don't reset |was_canceled_by_page_| yet for metrics purposes.
|
| - OnBannerPromptReply(render_frame_host, request_id,
|
| - blink::WebAppBannerPromptReply::None, referrer_);
|
| - } else {
|
| - // Log that the prompt request was made for when we get the prompt reply.
|
| - page_requested_prompt_ = true;
|
| - }
|
| -}
|
| -
|
| -AppBannerDataFetcher::~AppBannerDataFetcher() {
|
| - FOR_EACH_OBSERVER(Observer, observer_list_, OnFetcherDestroyed(this));
|
| -}
|
| -
|
| -std::string AppBannerDataFetcher::GetBannerType() {
|
| - return "web";
|
| -}
|
| -
|
| -content::WebContents* AppBannerDataFetcher::GetWebContents() {
|
| - if (!web_contents() || web_contents()->IsBeingDestroyed())
|
| - return nullptr;
|
| - return web_contents();
|
| -}
|
| -
|
| -std::string AppBannerDataFetcher::GetAppIdentifier() {
|
| - DCHECK(!manifest_.IsEmpty());
|
| - return manifest_.start_url.spec();
|
| -}
|
| -
|
| -void AppBannerDataFetcher::RecordDidShowBanner(const std::string& event_name) {
|
| - content::WebContents* web_contents = GetWebContents();
|
| - DCHECK(web_contents);
|
| -
|
| - AppBannerSettingsHelper::RecordBannerEvent(
|
| - web_contents, validated_url_, GetAppIdentifier(),
|
| - AppBannerSettingsHelper::APP_BANNER_EVENT_DID_SHOW,
|
| - GetCurrentTime());
|
| - rappor::SampleDomainAndRegistryFromGURL(g_browser_process->rappor_service(),
|
| - event_name,
|
| - web_contents->GetURL());
|
| -}
|
| -
|
| -void AppBannerDataFetcher::OnDidGetManifest(
|
| - const GURL& manifest_url,
|
| - const content::Manifest& manifest) {
|
| - content::WebContents* web_contents = GetWebContents();
|
| - if (!CheckFetcherIsStillAlive(web_contents)) {
|
| - Cancel();
|
| - return;
|
| - }
|
| - if (manifest_url.is_empty()) {
|
| - OutputDeveloperNotShownMessage(web_contents, kNoManifest, is_debug_mode_);
|
| - Cancel();
|
| - return;
|
| - }
|
| - if (manifest.IsEmpty()) {
|
| - OutputDeveloperNotShownMessage(web_contents, kManifestEmpty,
|
| - is_debug_mode_);
|
| - Cancel();
|
| - return;
|
| - }
|
| -
|
| - if (manifest.prefer_related_applications &&
|
| - manifest.related_applications.size()) {
|
| - for (const auto& application : manifest.related_applications) {
|
| - std::string platform = base::UTF16ToUTF8(application.platform.string());
|
| - std::string id = base::UTF16ToUTF8(application.id.string());
|
| - if (weak_delegate_->HandleNonWebApp(platform, application.url, id,
|
| - is_debug_mode_))
|
| - return;
|
| - }
|
| - }
|
| -
|
| - if (!IsManifestValidForWebApp(manifest, web_contents, is_debug_mode_)) {
|
| - Cancel();
|
| - return;
|
| - }
|
| -
|
| - // Since the manifest is valid, one of short name or name must be non-null.
|
| - // Prefer name if it isn't null.
|
| - manifest_url_ = manifest_url;
|
| - manifest_ = manifest;
|
| - app_title_ = (manifest_.name.is_null()) ? manifest_.short_name.string()
|
| - : manifest_.name.string();
|
| -
|
| - if (IsWebAppInstalled(web_contents->GetBrowserContext(),
|
| - manifest.start_url) &&
|
| - !is_debug_mode_) {
|
| - Cancel();
|
| - return;
|
| - }
|
| -
|
| - banners::TrackDisplayEvent(DISPLAY_EVENT_WEB_APP_BANNER_REQUESTED);
|
| -
|
| - // Check to see if there is a single service worker controlling this page
|
| - // and the manifest's start url.
|
| - Profile* profile =
|
| - Profile::FromBrowserContext(web_contents->GetBrowserContext());
|
| - content::StoragePartition* storage_partition =
|
| - content::BrowserContext::GetStoragePartition(
|
| - profile, web_contents->GetSiteInstance());
|
| - DCHECK(storage_partition);
|
| -
|
| - storage_partition->GetServiceWorkerContext()->CheckHasServiceWorker(
|
| - validated_url_, manifest.start_url,
|
| - base::Bind(&AppBannerDataFetcher::OnDidCheckHasServiceWorker,
|
| - this));
|
| -}
|
| -
|
| -void AppBannerDataFetcher::OnDidCheckHasServiceWorker(
|
| - bool has_service_worker) {
|
| - content::WebContents* web_contents = GetWebContents();
|
| - if (!CheckFetcherIsStillAlive(web_contents)) {
|
| - Cancel();
|
| - return;
|
| - }
|
| -
|
| - if (!has_service_worker) {
|
| - TrackDisplayEvent(DISPLAY_EVENT_LACKS_SERVICE_WORKER);
|
| - OutputDeveloperNotShownMessage(web_contents, kNoMatchingServiceWorker,
|
| - is_debug_mode_);
|
| - Cancel();
|
| - return;
|
| - }
|
| -
|
| - OnHasServiceWorker(web_contents);
|
| -}
|
| -
|
| -void AppBannerDataFetcher::OnHasServiceWorker(
|
| - content::WebContents* web_contents) {
|
| - GURL icon_url = ManifestIconSelector::FindBestMatchingIcon(
|
| - manifest_.icons, ideal_icon_size_in_dp_, minimum_icon_size_in_dp_);
|
| -
|
| - if (icon_url.is_empty()) {
|
| - OutputDeveloperNotShownMessage(
|
| - web_contents,
|
| - kNoIconMatchingRequirements,
|
| - base::IntToString(ManifestIconSelector::ConvertIconSizeFromDpToPx(
|
| - minimum_icon_size_in_dp_)),
|
| - is_debug_mode_);
|
| - Cancel();
|
| - } else if (!FetchAppIcon(web_contents, icon_url)) {
|
| - OutputDeveloperNotShownMessage(web_contents, kCannotDownloadIcon,
|
| - is_debug_mode_);
|
| - Cancel();
|
| - }
|
| -}
|
| -
|
| -bool AppBannerDataFetcher::FetchAppIcon(content::WebContents* web_contents,
|
| - const GURL& icon_url) {
|
| - app_icon_url_ = icon_url;
|
| - return ManifestIconDownloader::Download(
|
| - web_contents, icon_url, ideal_icon_size_in_dp_, minimum_icon_size_in_dp_,
|
| - base::Bind(&AppBannerDataFetcher::OnAppIconFetched, this));
|
| -}
|
| -
|
| -void AppBannerDataFetcher::OnAppIconFetched(const SkBitmap& bitmap) {
|
| - if (!is_active_) return;
|
| -
|
| - content::WebContents* web_contents = GetWebContents();
|
| - if (!CheckFetcherIsStillAlive(web_contents)) {
|
| - Cancel();
|
| - return;
|
| - }
|
| - if (bitmap.drawsNothing()) {
|
| - OutputDeveloperNotShownMessage(web_contents, kNoIconAvailable,
|
| - is_debug_mode_);
|
| - Cancel();
|
| - return;
|
| - }
|
| -
|
| - RecordCouldShowBanner();
|
| - if (!is_debug_mode_ && !CheckIfShouldShowBanner()) {
|
| - // At this point, the only possible case is that the banner has been added
|
| - // to the homescreen, given all of the other checks that have been made.
|
| - Cancel();
|
| - return;
|
| - }
|
| -
|
| - app_icon_.reset(new SkBitmap(bitmap));
|
| - event_request_id_ = ++gCurrentRequestID;
|
| -
|
| - TrackBeforeInstallEvent(BEFORE_INSTALL_EVENT_CREATED);
|
| - web_contents->GetMainFrame()->Send(
|
| - new ChromeViewMsg_AppBannerPromptRequest(
|
| - web_contents->GetMainFrame()->GetRoutingID(),
|
| - event_request_id_,
|
| - GetBannerType()));
|
| -}
|
| -
|
| -bool AppBannerDataFetcher::IsWebAppInstalled(
|
| - content::BrowserContext* browser_context,
|
| - const GURL& start_url) {
|
| - return false;
|
| -}
|
| -
|
| -void AppBannerDataFetcher::RecordCouldShowBanner() {
|
| - content::WebContents* web_contents = GetWebContents();
|
| - DCHECK(web_contents);
|
| -
|
| - AppBannerSettingsHelper::RecordBannerCouldShowEvent(
|
| - web_contents, validated_url_, GetAppIdentifier(),
|
| - GetCurrentTime(), transition_type_);
|
| -}
|
| -
|
| -bool AppBannerDataFetcher::CheckIfShouldShowBanner() {
|
| - content::WebContents* web_contents = GetWebContents();
|
| - DCHECK(web_contents);
|
| -
|
| - return AppBannerSettingsHelper::ShouldShowBanner(
|
| - web_contents, validated_url_, GetAppIdentifier(), GetCurrentTime());
|
| -}
|
| -
|
| -bool AppBannerDataFetcher::CheckFetcherIsStillAlive(
|
| - content::WebContents* web_contents) {
|
| - if (!is_active_) {
|
| - OutputDeveloperNotShownMessage(
|
| - web_contents, kUserNavigatedBeforeBannerShown, is_debug_mode_);
|
| - return false;
|
| - }
|
| - if (!web_contents) {
|
| - return false; // We cannot show a message if |web_contents| is null
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -// static
|
| -bool AppBannerDataFetcher::IsManifestValidForWebApp(
|
| - const content::Manifest& manifest,
|
| - content::WebContents* web_contents,
|
| - bool is_debug_mode) {
|
| - if (manifest.IsEmpty()) {
|
| - OutputDeveloperNotShownMessage(web_contents, kManifestEmpty, is_debug_mode);
|
| - return false;
|
| - }
|
| - if (!manifest.start_url.is_valid()) {
|
| - OutputDeveloperNotShownMessage(web_contents, kStartURLNotValid,
|
| - is_debug_mode);
|
| - return false;
|
| - }
|
| - if ((manifest.name.is_null() || manifest.name.string().empty()) &&
|
| - (manifest.short_name.is_null() || manifest.short_name.string().empty())) {
|
| - OutputDeveloperNotShownMessage(
|
| - web_contents, kManifestMissingNameOrShortName, is_debug_mode);
|
| - return false;
|
| - }
|
| -
|
| - // TODO(dominickn,mlamouri): when Chrome supports "minimal-ui", it should be
|
| - // accepted. If we accept it today, it would fallback to "browser" and make
|
| - // this check moot. See https://crbug.com/604390
|
| - if (manifest.display != blink::WebDisplayModeStandalone &&
|
| - manifest.display != blink::WebDisplayModeFullscreen) {
|
| - OutputDeveloperNotShownMessage(
|
| - web_contents, kManifestDisplayStandaloneFullscreen, is_debug_mode);
|
| - return false;
|
| - }
|
| -
|
| - if (!DoesManifestContainRequiredIcon(manifest)) {
|
| - OutputDeveloperNotShownMessage(web_contents, kManifestMissingSuitableIcon,
|
| - is_debug_mode);
|
| - return false;
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -} // namespace banners
|
|
|