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

Unified Diff: chrome/browser/banners/app_banner_manager.cc

Issue 2957063002: Update app banner state machine to use more states. (Closed)
Patch Set: Feedback Created 3 years, 5 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/banners/app_banner_manager.cc
diff --git a/chrome/browser/banners/app_banner_manager.cc b/chrome/browser/banners/app_banner_manager.cc
index b9675ac71bf97201f1a3dc0af7ee0d12472215e9..59e0a228f8f206dba2a22d20119da8a92dffe624 100644
--- a/chrome/browser/banners/app_banner_manager.cc
+++ b/chrome/browser/banners/app_banner_manager.cc
@@ -62,14 +62,13 @@ void AppBannerManager::RequestAppBanner(const GURL& validated_url,
// The only time we should start the pipeline while it is already running is
// if it's been triggered from devtools.
- if (is_active_or_pending()) {
+ if (state_ != State::INACTIVE) {
DCHECK(is_debug_mode);
ResetBindings();
}
UpdateState(State::ACTIVE);
triggered_by_devtools_ = is_debug_mode;
- page_requested_prompt_ = false;
// We only need to call ReportStatus if we aren't in debug mode (this avoids
// skew from testing).
@@ -100,7 +99,7 @@ void AppBannerManager::RequestAppBanner(const GURL& validated_url,
if (binding_.is_bound())
binding_.Close();
- UpdateState(State::PENDING_MANIFEST);
+ UpdateState(State::FETCHING_MANIFEST);
manager_->GetData(
ParamsToGetManifest(),
base::Bind(&AppBannerManager::OnDidGetManifest, GetWeakPtr()));
@@ -137,7 +136,6 @@ AppBannerManager::AppBannerManager(content::WebContents* web_contents)
binding_(this),
has_sufficient_engagement_(false),
load_finished_(false),
- page_requested_prompt_(false),
triggered_by_devtools_(false),
need_to_log_status_(false),
weak_factory_(this) {
@@ -298,12 +296,10 @@ void AppBannerManager::Stop() {
// Record the status if we are currently waiting for data.
InstallableStatusCode code = NO_ERROR_DETECTED;
switch (state_) {
- case State::PENDING_EVENT:
- if (!page_requested_prompt_) {
- TrackBeforeInstallEvent(
- BEFORE_INSTALL_EVENT_PROMPT_NOT_CALLED_AFTER_PREVENT_DEFAULT);
- code = RENDERER_CANCELLED;
- }
+ case State::PENDING_PROMPT:
+ TrackBeforeInstallEvent(
+ BEFORE_INSTALL_EVENT_PROMPT_NOT_CALLED_AFTER_PREVENT_DEFAULT);
+ code = RENDERER_CANCELLED;
break;
case State::PENDING_ENGAGEMENT:
if (!has_sufficient_engagement_) {
@@ -311,13 +307,15 @@ void AppBannerManager::Stop() {
code = INSUFFICIENT_ENGAGEMENT;
}
break;
- case State::PENDING_MANIFEST:
+ case State::FETCHING_MANIFEST:
code = WAITING_FOR_MANIFEST;
break;
case State::PENDING_INSTALLABLE_CHECK:
code = WAITING_FOR_INSTALLABLE_CHECK;
break;
case State::ACTIVE:
+ case State::SENDING_EVENT:
+ case State::SENDING_EVENT_GOT_EARLY_PROMPT:
case State::INACTIVE:
case State::COMPLETE:
break;
@@ -328,9 +326,11 @@ void AppBannerManager::Stop() {
// In every non-debug run through the banner pipeline, we should have called
// ReportStatus() and set need_to_log_status_ to false. The only case where
- // we don't is if we're still active and waiting for native app data, which is
- // explicitly not logged.
- DCHECK(!need_to_log_status_ || is_active());
+ // we don't is if we're still running and aren't blocked on the network. When
+ // running and blocked on the network the state should be logged.
+ // TODO(dominickn): log when the pipeline is fetching native app banner
+ // details.
+ DCHECK(!need_to_log_status_ || (IsRunning() && !IsWaitingForData()));
ResetBindings();
UpdateState(State::COMPLETE);
@@ -340,6 +340,8 @@ void AppBannerManager::Stop() {
void AppBannerManager::SendBannerPromptRequest() {
RecordCouldShowBanner();
+
+ UpdateState(State::SENDING_EVENT);
TrackBeforeInstallEvent(BEFORE_INSTALL_EVENT_CREATED);
web_contents()->GetMainFrame()->GetRemoteInterfaces()->GetInterface(
@@ -354,21 +356,17 @@ void AppBannerManager::SendBannerPromptRequest() {
void AppBannerManager::UpdateState(State state) {
state_ = state;
-
- // If we are PENDING_EVENT, we must have sufficient engagement.
- DCHECK(!is_pending_event() || has_sufficient_engagement_);
}
void AppBannerManager::DidStartNavigation(content::NavigationHandle* handle) {
if (!handle->IsInMainFrame() || handle->IsSameDocument())
return;
- if (is_active_or_pending())
+ if (state_ != State::COMPLETE && state_ != State::INACTIVE)
Stop();
UpdateState(State::INACTIVE);
load_finished_ = false;
has_sufficient_engagement_ = false;
- page_requested_prompt_ = false;
}
void AppBannerManager::DidFinishNavigation(content::NavigationHandle* handle) {
@@ -401,7 +399,7 @@ void AppBannerManager::DidFinishLoad(
// Start the pipeline immediately if we pass (or bypass) the engagement check,
// or if the feature to run the installability check on page load is enabled.
- if (!is_active_or_pending() &&
+ if (state_ == State::INACTIVE &&
(has_sufficient_engagement_ ||
base::FeatureList::IsEnabled(
features::kCheckInstallabilityForBannerOnLoad))) {
@@ -428,12 +426,6 @@ void AppBannerManager::WebContentsDestroyed() {
void AppBannerManager::OnEngagementIncreased(content::WebContents* contents,
const GURL& url,
double score) {
- // In the ACTIVE state, we may have triggered the installability check, but
- // not checked engagement yet. In the INACTIVE or PENDING_ENGAGEMENT states,
- // we are waiting for an engagement signal to trigger the pipeline.
- if (is_complete() || is_pending_event())
- return;
-
// Only trigger a banner using site engagement if:
// 1. engagement increased for the web contents which we are attached to; and
// 2. there are no currently active media players; and
@@ -447,7 +439,7 @@ void AppBannerManager::OnEngagementIncreased(content::WebContents* contents,
// directly to sending the banner prompt request.
UpdateState(State::ACTIVE);
SendBannerPromptRequest();
- } else if (load_finished_ && !is_active_or_pending()) {
+ } else if (load_finished_ && state_ == State::INACTIVE) {
// This performs some simple tests and starts async checks to test
// installability. It should be safe to start in response to user input.
// Don't call if we're already working on processing a banner request.
@@ -456,6 +448,28 @@ void AppBannerManager::OnEngagementIncreased(content::WebContents* contents,
}
}
+bool AppBannerManager::IsRunning() const {
+ switch (state_) {
+ case State::INACTIVE:
+ case State::PENDING_PROMPT:
+ case State::PENDING_ENGAGEMENT:
+ case State::COMPLETE:
+ return false;
+ case State::ACTIVE:
+ case State::FETCHING_MANIFEST:
+ case State::PENDING_INSTALLABLE_CHECK:
+ case State::SENDING_EVENT:
+ case State::SENDING_EVENT_GOT_EARLY_PROMPT:
+ return true;
+ }
+ return false;
+}
+
+bool AppBannerManager::IsWaitingForData() const {
+ return (state_ == State::FETCHING_MANIFEST ||
+ state_ == State::PENDING_INSTALLABLE_CHECK);
+}
+
void AppBannerManager::ResetBindings() {
weak_factory_.InvalidateWeakPtrs();
binding_.Close();
@@ -525,26 +539,28 @@ void AppBannerManager::OnBannerPromptReply(
// that the cancelation was requested, so Stop() can be called if a redisplay
// isn't asked for.
//
- // We use the additional page_requested_prompt_ variable because the redisplay
- // request may be received *before* the Cancel prompt reply (e.g. if redisplay
- // is requested in the beforeinstallprompt event handler).
+ // If the redisplay request has not been received already, we stop here and
+ // wait for the prompt function to be called. If the redisplay request has
+ // already been received before cancel was sent (e.g. if redisplay was
+ // requested in the beforeinstallprompt event handler), we keep going and show
+ // the banner immediately.
referrer_ = referrer;
if (reply == blink::mojom::AppBannerPromptReply::CANCEL) {
- UpdateState(State::PENDING_EVENT);
TrackBeforeInstallEvent(BEFORE_INSTALL_EVENT_PREVENT_DEFAULT_CALLED);
- if (!page_requested_prompt_)
+ if (state_ == State::SENDING_EVENT) {
+ UpdateState(State::PENDING_PROMPT);
return;
+ }
+ DCHECK_EQ(State::SENDING_EVENT_GOT_EARLY_PROMPT, state_);
}
- // If we haven't yet returned, but we're in the PENDING_EVENT state 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 (is_pending_event()) {
+ // If we are still in the SENDING_EVENT state, the prompt was never canceled
+ // by the page. Otherwise the page requested a delayed showing of the prompt.
+ if (state_ == State::SENDING_EVENT) {
+ TrackBeforeInstallEvent(BEFORE_INSTALL_EVENT_NO_ACTION);
+ } else {
TrackBeforeInstallEvent(
BEFORE_INSTALL_EVENT_PROMPT_CALLED_AFTER_PREVENT_DEFAULT);
- UpdateState(State::ACTIVE);
- } else {
- TrackBeforeInstallEvent(BEFORE_INSTALL_EVENT_NO_ACTION);
}
AppBannerSettingsHelper::RecordMinutesFromFirstVisitToShow(
@@ -561,12 +577,11 @@ void AppBannerManager::OnBannerPromptReply(
}
void AppBannerManager::DisplayAppBanner(bool user_gesture) {
- if (is_pending_event()) {
+ if (state_ == State::PENDING_PROMPT) {
// Simulate a non-canceled OnBannerPromptReply to show the delayed banner.
OnBannerPromptReply(blink::mojom::AppBannerPromptReply::NONE, referrer_);
- } else {
- // Log that the prompt request was made for when we get the prompt reply.
- page_requested_prompt_ = true;
+ } else if (state_ == State::SENDING_EVENT) {
+ UpdateState(State::SENDING_EVENT_GOT_EARLY_PROMPT);
}
}
« no previous file with comments | « chrome/browser/banners/app_banner_manager.h ('k') | chrome/browser/banners/app_banner_manager_browsertest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698