Commit 4d2a7a01 authored by Sebastien Marchand's avatar Sebastien Marchand Committed by Commit Bot

RC: Ignore some feature usage happening right after loading/bg-ing

- Ignore the title/favicon changes happening during the first few seconds
  following the transition to the loaded state for a tab, some sites seems
  update their favicon immediately after loading (e.g. cs.chromium.org)
  without this being an attempt to communicate with the user. The grace
  period is controlled by the "TitleOrFaviconChangeGracePeriod" variation
  of the "SiteCharacteristicsDatabase" feature.
- Ignore the audio usage happening during the first few seconds after
  backgrounding a page: this is something that can happen if a user start
  some media (e.g. a video on YouTube) and switch to a different tab before
  the video has actually started to play. The grace period is controlled by
  the "AudioUsageGracePeriod" variation of the "SiteCharacteristicsDatabase"
  feature.

Bug: 773382
Change-Id: I4790fa976add5840bdb9cb5d78c402cba8577669
Reviewed-on: https://chromium-review.googlesource.com/1145707
Commit-Queue: Sébastien Marchand <sebmarchand@chromium.org>
Reviewed-by: default avatarChris Hamilton <chrisha@chromium.org>
Cr-Commit-Position: refs/heads/master@{#577300}
parent 02847f8b
...@@ -61,6 +61,14 @@ base::TimeDelta GetLongestObservationWindow() { ...@@ -61,6 +61,14 @@ base::TimeDelta GetLongestObservationWindow() {
params.notifications_usage_observation_window}); params.notifications_usage_observation_window});
} }
// Returns the longest grace period.
base::TimeDelta GetLongestGracePeriod() {
const SiteCharacteristicsDatabaseParams& params =
GetStaticSiteCharacteristicsDatabaseParams();
return std::max({params.title_or_favicon_change_grace_period,
params.audio_usage_grace_period});
}
// Returns the SiteCharacteristicsProto that backs |reader|. // Returns the SiteCharacteristicsProto that backs |reader|.
const SiteCharacteristicsProto* GetSiteCharacteristicsProtoFromReader( const SiteCharacteristicsProto* GetSiteCharacteristicsProtoFromReader(
SiteCharacteristicsDataReader* reader) { SiteCharacteristicsDataReader* reader) {
...@@ -209,6 +217,8 @@ class LocalSiteCharacteristicsDatabaseTest : public InProcessBrowserTest { ...@@ -209,6 +217,8 @@ class LocalSiteCharacteristicsDatabaseTest : public InProcessBrowserTest {
// Background the tab and reload it so the audio will stop playing if it's // Background the tab and reload it so the audio will stop playing if it's
// still playing. // still playing.
GetActiveWebContents()->WasHidden(); GetActiveWebContents()->WasHidden();
test_clock_.Advance(
GetStaticSiteCharacteristicsDatabaseParams().audio_usage_grace_period);
} }
// Ensure that the current tab is allowed to display non-persistent // Ensure that the current tab is allowed to display non-persistent
...@@ -222,6 +232,11 @@ class LocalSiteCharacteristicsDatabaseTest : public InProcessBrowserTest { ...@@ -222,6 +232,11 @@ class LocalSiteCharacteristicsDatabaseTest : public InProcessBrowserTest {
ExecuteScriptInMainFrame("RequestNotificationsPermission();"); ExecuteScriptInMainFrame("RequestNotificationsPermission();");
} }
void ExpireTitleOrFaviconGracePeriod() {
test_clock_.Advance(GetStaticSiteCharacteristicsDatabaseParams()
.title_or_favicon_change_grace_period);
}
base::SimpleTestTickClock& test_clock() { return test_clock_; } base::SimpleTestTickClock& test_clock() { return test_clock_; }
net::test_server::EmbeddedTestServer& test_server() { return test_server_; } net::test_server::EmbeddedTestServer& test_server() { return test_server_; }
...@@ -410,7 +425,10 @@ IN_PROC_BROWSER_TEST_F(LocalSiteCharacteristicsDatabaseTest, ...@@ -410,7 +425,10 @@ IN_PROC_BROWSER_TEST_F(LocalSiteCharacteristicsDatabaseTest,
&SiteCharacteristicsDataReader::UpdatesTitleInBackground, &SiteCharacteristicsDataReader::UpdatesTitleInBackground,
base::BindRepeating( base::BindRepeating(
&LocalSiteCharacteristicsDatabaseTest::ChangeTitleOfActiveWebContents, &LocalSiteCharacteristicsDatabaseTest::ChangeTitleOfActiveWebContents,
base::Unretained(this))); base::Unretained(this)),
base::BindRepeating(&LocalSiteCharacteristicsDatabaseTest::
ExpireTitleOrFaviconGracePeriod,
base::Unretained(this)));
} }
// Test that the favicon update feature usage in background gets detected // Test that the favicon update feature usage in background gets detected
...@@ -421,6 +439,9 @@ IN_PROC_BROWSER_TEST_F(LocalSiteCharacteristicsDatabaseTest, ...@@ -421,6 +439,9 @@ IN_PROC_BROWSER_TEST_F(LocalSiteCharacteristicsDatabaseTest,
&SiteCharacteristicsDataReader::UpdatesFaviconInBackground, &SiteCharacteristicsDataReader::UpdatesFaviconInBackground,
base::BindRepeating(&LocalSiteCharacteristicsDatabaseTest:: base::BindRepeating(&LocalSiteCharacteristicsDatabaseTest::
ChangeFaviconOfActiveWebContents, ChangeFaviconOfActiveWebContents,
base::Unretained(this)),
base::BindRepeating(&LocalSiteCharacteristicsDatabaseTest::
ExpireTitleOrFaviconGracePeriod,
base::Unretained(this))); base::Unretained(this)));
} }
...@@ -497,6 +518,8 @@ IN_PROC_BROWSER_TEST_F(LocalSiteCharacteristicsDatabaseTest, ...@@ -497,6 +518,8 @@ IN_PROC_BROWSER_TEST_F(LocalSiteCharacteristicsDatabaseTest,
WaitForTransitionToLoaded(GetActiveWebContents()); WaitForTransitionToLoaded(GetActiveWebContents());
GetActiveWebContents()->WasHidden(); GetActiveWebContents()->WasHidden();
test_clock().Advance(GetLongestGracePeriod());
// Cause the "title update in background" feature to be used. // Cause the "title update in background" feature to be used.
ChangeTitleOfActiveWebContents(); ChangeTitleOfActiveWebContents();
...@@ -536,6 +559,8 @@ IN_PROC_BROWSER_TEST_F(LocalSiteCharacteristicsDatabaseTest, PRE_ClearHistory) { ...@@ -536,6 +559,8 @@ IN_PROC_BROWSER_TEST_F(LocalSiteCharacteristicsDatabaseTest, PRE_ClearHistory) {
WaitForTransitionToLoaded(GetActiveWebContents()); WaitForTransitionToLoaded(GetActiveWebContents());
GetActiveWebContents()->WasHidden(); GetActiveWebContents()->WasHidden();
test_clock().Advance(GetLongestGracePeriod());
// Cause the "title update in background" feature to be used. // Cause the "title update in background" feature to be used.
ChangeTitleOfActiveWebContents(); ChangeTitleOfActiveWebContents();
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "chrome/browser/resource_coordinator/local_site_characteristics_data_store_factory.h" #include "chrome/browser/resource_coordinator/local_site_characteristics_data_store_factory.h"
#include "chrome/browser/resource_coordinator/time.h"
#include "chrome/browser/resource_coordinator/utils.h" #include "chrome/browser/resource_coordinator/utils.h"
#include "content/public/browser/navigation_handle.h" #include "content/public/browser/navigation_handle.h"
#include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents.h"
...@@ -60,6 +61,7 @@ void LocalSiteCharacteristicsWebContentsObserver::OnVisibilityChanged( ...@@ -60,6 +61,7 @@ void LocalSiteCharacteristicsWebContentsObserver::OnVisibilityChanged(
return; return;
auto rc_visibility = ContentVisibilityToRCVisibility(visibility); auto rc_visibility = ContentVisibilityToRCVisibility(visibility);
UpdateBackgroundedTime(rc_visibility);
writer_->NotifySiteVisibilityChanged(rc_visibility); writer_->NotifySiteVisibilityChanged(rc_visibility);
} }
...@@ -109,14 +111,15 @@ void LocalSiteCharacteristicsWebContentsObserver::DidFinishNavigation( ...@@ -109,14 +111,15 @@ void LocalSiteCharacteristicsWebContentsObserver::DidFinishNavigation(
SiteCharacteristicsDataStore* data_store = SiteCharacteristicsDataStore* data_store =
LocalSiteCharacteristicsDataStoreFactory::GetForProfile(profile); LocalSiteCharacteristicsDataStoreFactory::GetForProfile(profile);
DCHECK(data_store); DCHECK(data_store);
writer_ = data_store->GetWriterForOrigin( auto rc_visibility =
new_origin, ContentVisibilityToRCVisibility(web_contents()->GetVisibility());
ContentVisibilityToRCVisibility(web_contents()->GetVisibility())); writer_ = data_store->GetWriterForOrigin(new_origin, rc_visibility);
UpdateBackgroundedTime(rc_visibility);
// The writer is initially in an unloaded state, load it if necessary. // The writer is initially in an unloaded state, load it if necessary.
if (TabLoadTracker::Get()->GetLoadingState(web_contents()) == if (TabLoadTracker::Get()->GetLoadingState(web_contents()) ==
LoadingState::LOADED) { LoadingState::LOADED) {
writer_->NotifySiteLoaded(); OnSiteLoaded();
} }
writer_origin_ = new_origin; writer_origin_ = new_origin;
...@@ -134,7 +137,8 @@ void LocalSiteCharacteristicsWebContentsObserver::TitleWasSet( ...@@ -134,7 +137,8 @@ void LocalSiteCharacteristicsWebContentsObserver::TitleWasSet(
} }
MaybeNotifyBackgroundFeatureUsage( MaybeNotifyBackgroundFeatureUsage(
&SiteCharacteristicsDataWriter::NotifyUpdatesTitleInBackground); &SiteCharacteristicsDataWriter::NotifyUpdatesTitleInBackground,
FeatureType::kTitleChange);
} }
void LocalSiteCharacteristicsWebContentsObserver::DidUpdateFaviconURL( void LocalSiteCharacteristicsWebContentsObserver::DidUpdateFaviconURL(
...@@ -147,7 +151,8 @@ void LocalSiteCharacteristicsWebContentsObserver::DidUpdateFaviconURL( ...@@ -147,7 +151,8 @@ void LocalSiteCharacteristicsWebContentsObserver::DidUpdateFaviconURL(
} }
MaybeNotifyBackgroundFeatureUsage( MaybeNotifyBackgroundFeatureUsage(
&SiteCharacteristicsDataWriter::NotifyUpdatesFaviconInBackground); &SiteCharacteristicsDataWriter::NotifyUpdatesFaviconInBackground,
FeatureType::kFaviconChange);
} }
void LocalSiteCharacteristicsWebContentsObserver::OnAudioStateChanged( void LocalSiteCharacteristicsWebContentsObserver::OnAudioStateChanged(
...@@ -158,7 +163,8 @@ void LocalSiteCharacteristicsWebContentsObserver::OnAudioStateChanged( ...@@ -158,7 +163,8 @@ void LocalSiteCharacteristicsWebContentsObserver::OnAudioStateChanged(
return; return;
MaybeNotifyBackgroundFeatureUsage( MaybeNotifyBackgroundFeatureUsage(
&SiteCharacteristicsDataWriter::NotifyUsesAudioInBackground); &SiteCharacteristicsDataWriter::NotifyUsesAudioInBackground,
FeatureType::kAudioUsage);
} }
void LocalSiteCharacteristicsWebContentsObserver::OnLoadingStateChange( void LocalSiteCharacteristicsWebContentsObserver::OnLoadingStateChange(
...@@ -174,9 +180,10 @@ void LocalSiteCharacteristicsWebContentsObserver::OnLoadingStateChange( ...@@ -174,9 +180,10 @@ void LocalSiteCharacteristicsWebContentsObserver::OnLoadingStateChange(
// Ignore the transitions from/to an UNLOADED state. // Ignore the transitions from/to an UNLOADED state.
if (new_loading_state == LoadingState::LOADED) { if (new_loading_state == LoadingState::LOADED) {
writer_->NotifySiteLoaded(); OnSiteLoaded();
} else if (old_loading_state == LoadingState::LOADED) { } else if (old_loading_state == LoadingState::LOADED) {
writer_->NotifySiteUnloaded(); writer_->NotifySiteUnloaded();
loaded_time_ = base::TimeTicks();
} }
} }
...@@ -197,38 +204,73 @@ void LocalSiteCharacteristicsWebContentsObserver:: ...@@ -197,38 +204,73 @@ void LocalSiteCharacteristicsWebContentsObserver::
url::Origin::Create(GURL(page_navigation_id.url)) url::Origin::Create(GURL(page_navigation_id.url))
.IsSameOriginWith(writer_origin_)) { .IsSameOriginWith(writer_origin_)) {
MaybeNotifyBackgroundFeatureUsage( MaybeNotifyBackgroundFeatureUsage(
&SiteCharacteristicsDataWriter::NotifyUsesNotificationsInBackground); &SiteCharacteristicsDataWriter::NotifyUsesNotificationsInBackground,
FeatureType::kNotificationUsage);
} }
} }
bool LocalSiteCharacteristicsWebContentsObserver:: bool LocalSiteCharacteristicsWebContentsObserver::ShouldIgnoreFeatureUsageEvent(
ShouldIgnoreFeatureUsageEvent() { FeatureType feature_type) {
// The feature usage should be ignored if there's no writer for this tab. // The feature usage should be ignored if there's no writer for this tab.
if (!writer_) if (!writer_)
return true; return true;
// Features happening before the site gets loaded are also ignored. // Ignore all features happening before the website gets fully loaded except
// TODO(sebmarchand): Consider recording audio/notification usage before the // for the non-persistent notifications.
// site gets fully loaded. if (feature_type != FeatureType::kNotificationUsage &&
if (TabLoadTracker::Get()->GetLoadingState(web_contents()) != TabLoadTracker::Get()->GetLoadingState(web_contents()) !=
LoadingState::LOADED) { LoadingState::LOADED) {
return true;
}
// Ignore events if the tab is not in background.
if (ContentVisibilityToRCVisibility(web_contents()->GetVisibility()) !=
TabVisibility::kBackground) {
return true; return true;
} }
if (feature_type == FeatureType::kTitleChange ||
feature_type == FeatureType::kFaviconChange) {
DCHECK(!loaded_time_.is_null());
if (NowTicks() - loaded_time_ < GetStaticSiteCharacteristicsDatabaseParams()
.title_or_favicon_change_grace_period) {
return true;
}
} else if (feature_type == FeatureType::kAudioUsage) {
DCHECK(!backgrounded_time_.is_null());
if (NowTicks() - backgrounded_time_ <
GetStaticSiteCharacteristicsDatabaseParams().audio_usage_grace_period) {
return true;
}
}
return false; return false;
} }
void LocalSiteCharacteristicsWebContentsObserver:: void LocalSiteCharacteristicsWebContentsObserver::
MaybeNotifyBackgroundFeatureUsage( MaybeNotifyBackgroundFeatureUsage(
void (SiteCharacteristicsDataWriter::*method)()) { void (SiteCharacteristicsDataWriter::*method)(),
FeatureType feature_type) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (ShouldIgnoreFeatureUsageEvent()) if (ShouldIgnoreFeatureUsageEvent(feature_type))
return; return;
if (ContentVisibilityToRCVisibility(web_contents()->GetVisibility()) ==
TabVisibility::kBackground) {
(writer_.get()->*method)(); (writer_.get()->*method)();
}
void LocalSiteCharacteristicsWebContentsObserver::OnSiteLoaded() {
DCHECK(writer_);
writer_->NotifySiteLoaded();
loaded_time_ = NowTicks();
}
void LocalSiteCharacteristicsWebContentsObserver::UpdateBackgroundedTime(
TabVisibility visibility) {
if (visibility == TabVisibility::kBackground) {
backgrounded_time_ = NowTicks();
} else {
backgrounded_time_ = base::TimeTicks();
} }
} }
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/sequence_checker.h" #include "base/sequence_checker.h"
#include "base/time/time.h"
#include "chrome/browser/resource_coordinator/local_site_characteristics_data_writer.h" #include "chrome/browser/resource_coordinator/local_site_characteristics_data_writer.h"
#include "chrome/browser/resource_coordinator/page_signal_receiver.h" #include "chrome/browser/resource_coordinator/page_signal_receiver.h"
#include "chrome/browser/resource_coordinator/tab_load_tracker.h" #include "chrome/browser/resource_coordinator/tab_load_tracker.h"
...@@ -68,15 +69,28 @@ class LocalSiteCharacteristicsWebContentsObserver ...@@ -68,15 +69,28 @@ class LocalSiteCharacteristicsWebContentsObserver
} }
private: private:
enum class FeatureType {
kTitleChange,
kFaviconChange,
kAudioUsage,
kNotificationUsage,
};
// Indicates if the feature usage event just received should be ignored. // Indicates if the feature usage event just received should be ignored.
bool ShouldIgnoreFeatureUsageEvent(); bool ShouldIgnoreFeatureUsageEvent(FeatureType feature_type);
// Helper function to maybe notify |writer_| that a feature event has been // Helper function to maybe notify |writer_| that a feature event has been
// received while in background. Doen't do anything if // received while in background. Doesn't do anything if
// ShouldIgnoreFeatureUsageEvent returns true or if the tab isn't // ShouldIgnoreFeatureUsageEvent returns true.
// backgrounded.
void MaybeNotifyBackgroundFeatureUsage( void MaybeNotifyBackgroundFeatureUsage(
void (SiteCharacteristicsDataWriter::*method)()); void (SiteCharacteristicsDataWriter::*method)(),
FeatureType feature_type);
// Function to call when the site switch to the loaded state.
void OnSiteLoaded();
// Updates |backgrounded_time_| based on |visibility|.
void UpdateBackgroundedTime(TabVisibility visibility);
// The writer that processes the event received by this class. // The writer that processes the event received by this class.
std::unique_ptr<SiteCharacteristicsDataWriter> writer_; std::unique_ptr<SiteCharacteristicsDataWriter> writer_;
...@@ -94,6 +108,14 @@ class LocalSiteCharacteristicsWebContentsObserver ...@@ -94,6 +108,14 @@ class LocalSiteCharacteristicsWebContentsObserver
// The PageSignalReceiver observed by this instance. // The PageSignalReceiver observed by this instance.
PageSignalReceiver* page_signal_receiver_ = nullptr; PageSignalReceiver* page_signal_receiver_ = nullptr;
// The time at which this tab switched to the loaded state, null if this tab
// is not currently loaded.
base::TimeTicks loaded_time_;
// The time at which this tab has been backgrounded, null if this tab is
// currently visible.
base::TimeTicks backgrounded_time_;
SEQUENCE_CHECKER(sequence_checker_); SEQUENCE_CHECKER(sequence_checker_);
DISALLOW_COPY_AND_ASSIGN(LocalSiteCharacteristicsWebContentsObserver); DISALLOW_COPY_AND_ASSIGN(LocalSiteCharacteristicsWebContentsObserver);
......
...@@ -5,11 +5,13 @@ ...@@ -5,11 +5,13 @@
#include "chrome/browser/resource_coordinator/local_site_characteristics_webcontents_observer.h" #include "chrome/browser/resource_coordinator/local_site_characteristics_webcontents_observer.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/test/simple_test_tick_clock.h"
#include "chrome/browser/resource_coordinator/local_site_characteristics_data_store_factory.h" #include "chrome/browser/resource_coordinator/local_site_characteristics_data_store_factory.h"
#include "chrome/browser/resource_coordinator/local_site_characteristics_data_unittest_utils.h" #include "chrome/browser/resource_coordinator/local_site_characteristics_data_unittest_utils.h"
#include "chrome/browser/resource_coordinator/page_signal_receiver.h" #include "chrome/browser/resource_coordinator/page_signal_receiver.h"
#include "chrome/browser/resource_coordinator/site_characteristics_data_store.h" #include "chrome/browser/resource_coordinator/site_characteristics_data_store.h"
#include "chrome/browser/resource_coordinator/tab_manager_features.h" #include "chrome/browser/resource_coordinator/tab_manager_features.h"
#include "chrome/browser/resource_coordinator/time.h"
#include "content/public/browser/navigation_handle.h" #include "content/public/browser/navigation_handle.h"
#include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents.h"
#include "content/public/common/favicon_url.h" #include "content/public/common/favicon_url.h"
...@@ -77,12 +79,14 @@ std::unique_ptr<KeyedService> BuildMockDataStoreForContext( ...@@ -77,12 +79,14 @@ std::unique_ptr<KeyedService> BuildMockDataStoreForContext(
class LocalSiteCharacteristicsWebContentsObserverTest class LocalSiteCharacteristicsWebContentsObserverTest
: public testing::ChromeTestHarnessWithLocalDB { : public testing::ChromeTestHarnessWithLocalDB {
protected: protected:
LocalSiteCharacteristicsWebContentsObserverTest() = default; LocalSiteCharacteristicsWebContentsObserverTest()
: scoped_set_tick_clock_for_testing_(&test_clock_) {}
~LocalSiteCharacteristicsWebContentsObserverTest() override = default; ~LocalSiteCharacteristicsWebContentsObserverTest() override = default;
void SetUp() override { void SetUp() override {
testing::ChromeTestHarnessWithLocalDB::SetUp(); testing::ChromeTestHarnessWithLocalDB::SetUp();
test_clock().Advance(base::TimeDelta::FromSeconds(1));
// Set the testing factory for the test browser context. // Set the testing factory for the test browser context.
LocalSiteCharacteristicsDataStoreFactory::GetInstance()->SetTestingFactory( LocalSiteCharacteristicsDataStoreFactory::GetInstance()->SetTestingFactory(
browser_context(), &BuildMockDataStoreForContext); browser_context(), &BuildMockDataStoreForContext);
...@@ -122,9 +126,13 @@ class LocalSiteCharacteristicsWebContentsObserverTest ...@@ -122,9 +126,13 @@ class LocalSiteCharacteristicsWebContentsObserverTest
receiver_.GetNavigationIDForWebContents(web_contents()), ""}; receiver_.GetNavigationIDForWebContents(web_contents()), ""};
} }
base::SimpleTestTickClock& test_clock() { return test_clock_; }
private: private:
std::unique_ptr<LocalSiteCharacteristicsWebContentsObserver> observer_; std::unique_ptr<LocalSiteCharacteristicsWebContentsObserver> observer_;
PageSignalReceiver receiver_; PageSignalReceiver receiver_;
base::SimpleTestTickClock test_clock_;
ScopedSetTickClockForTesting scoped_set_tick_clock_for_testing_;
DISALLOW_COPY_AND_ASSIGN(LocalSiteCharacteristicsWebContentsObserverTest); DISALLOW_COPY_AND_ASSIGN(LocalSiteCharacteristicsWebContentsObserverTest);
}; };
...@@ -169,6 +177,8 @@ TEST_F(LocalSiteCharacteristicsWebContentsObserverTest, ...@@ -169,6 +177,8 @@ TEST_F(LocalSiteCharacteristicsWebContentsObserverTest,
EXPECT_CALL(*mock_writer, OnDestroy()); EXPECT_CALL(*mock_writer, OnDestroy());
} }
// Test that the feature usage events get forwarded to the writer when the tab
// is in background.
TEST_F(LocalSiteCharacteristicsWebContentsObserverTest, TEST_F(LocalSiteCharacteristicsWebContentsObserverTest,
FeatureEventsGetForwardedWhenInBackground) { FeatureEventsGetForwardedWhenInBackground) {
MockDataWriter* mock_writer = NavigateAndReturnMockWriter(kTestUrl1); MockDataWriter* mock_writer = NavigateAndReturnMockWriter(kTestUrl1);
...@@ -180,14 +190,16 @@ TEST_F(LocalSiteCharacteristicsWebContentsObserverTest, ...@@ -180,14 +190,16 @@ TEST_F(LocalSiteCharacteristicsWebContentsObserverTest,
TabLoadTracker::Get()->TransitionStateForTesting(web_contents(), TabLoadTracker::Get()->TransitionStateForTesting(web_contents(),
LoadingState::LOADED); LoadingState::LOADED);
EXPECT_CALL(*mock_writer, EXPECT_CALL(*mock_writer,
NotifySiteVisibilityChanged(TabVisibility::kForeground)); NotifySiteVisibilityChanged(TabVisibility::kForeground));
EXPECT_CALL(*mock_writer, NotifySiteLoaded());
web_contents()->WasShown(); web_contents()->WasShown();
observer()->OnLoadingStateChange(web_contents(),
TabLoadTracker::LoadingState::LOADING,
TabLoadTracker::LoadingState::LOADED);
::testing::Mock::VerifyAndClear(mock_writer); ::testing::Mock::VerifyAndClear(mock_writer);
// Test that the feature usage events get forwarded to the writer when the // Ensure that no event gets forwarded if the tab is not in background.
// tab is in background.
observer()->DidUpdateFaviconURL({}); observer()->DidUpdateFaviconURL({});
::testing::Mock::VerifyAndClear(mock_writer); ::testing::Mock::VerifyAndClear(mock_writer);
observer()->TitleWasSet(nullptr); observer()->TitleWasSet(nullptr);
...@@ -203,18 +215,44 @@ TEST_F(LocalSiteCharacteristicsWebContentsObserverTest, ...@@ -203,18 +215,44 @@ TEST_F(LocalSiteCharacteristicsWebContentsObserverTest,
web_contents()->WasHidden(); web_contents()->WasHidden();
::testing::Mock::VerifyAndClear(mock_writer); ::testing::Mock::VerifyAndClear(mock_writer);
// Notification usage events always get forwarded.
EXPECT_CALL(*mock_writer, NotifyUsesNotificationsInBackground());
observer()->OnNonPersistentNotificationCreated(web_contents(),
GetNavIdForWebContents());
::testing::Mock::VerifyAndClear(mock_writer);
auto params = GetStaticSiteCharacteristicsDatabaseParams();
// Title and Favicon should be ignored during the post-loading grace period.
observer()->DidUpdateFaviconURL({});
observer()->TitleWasSet(nullptr);
::testing::Mock::VerifyAndClear(mock_writer);
test_clock().Advance(params.title_or_favicon_change_grace_period);
EXPECT_CALL(*mock_writer, NotifyUpdatesFaviconInBackground()); EXPECT_CALL(*mock_writer, NotifyUpdatesFaviconInBackground());
observer()->DidUpdateFaviconURL({}); observer()->DidUpdateFaviconURL({});
::testing::Mock::VerifyAndClear(mock_writer); ::testing::Mock::VerifyAndClear(mock_writer);
EXPECT_CALL(*mock_writer, NotifyUpdatesTitleInBackground()); EXPECT_CALL(*mock_writer, NotifyUpdatesTitleInBackground());
observer()->TitleWasSet(nullptr); observer()->TitleWasSet(nullptr);
::testing::Mock::VerifyAndClear(mock_writer); ::testing::Mock::VerifyAndClear(mock_writer);
EXPECT_CALL(*mock_writer, NotifyUsesAudioInBackground());
// Brievly switch the tab to foreground to reset the last backgrounded time.
EXPECT_CALL(*mock_writer,
NotifySiteVisibilityChanged(TabVisibility::kForeground));
EXPECT_CALL(*mock_writer,
NotifySiteVisibilityChanged(TabVisibility::kBackground));
web_contents()->WasShown();
web_contents()->WasHidden();
::testing::Mock::VerifyAndClear(mock_writer);
// Audio usage events should be ignored during the post-background grace
// period.
observer()->OnAudioStateChanged(true); observer()->OnAudioStateChanged(true);
::testing::Mock::VerifyAndClear(mock_writer); ::testing::Mock::VerifyAndClear(mock_writer);
EXPECT_CALL(*mock_writer, NotifyUsesNotificationsInBackground());
observer()->OnNonPersistentNotificationCreated(web_contents(), test_clock().Advance(params.audio_usage_grace_period);
GetNavIdForWebContents()); EXPECT_CALL(*mock_writer, NotifyUsesAudioInBackground());
observer()->OnAudioStateChanged(true);
::testing::Mock::VerifyAndClear(mock_writer); ::testing::Mock::VerifyAndClear(mock_writer);
EXPECT_CALL(*mock_writer, OnDestroy()); EXPECT_CALL(*mock_writer, OnDestroy());
...@@ -243,6 +281,23 @@ TEST_F(LocalSiteCharacteristicsWebContentsObserverTest, ...@@ -243,6 +281,23 @@ TEST_F(LocalSiteCharacteristicsWebContentsObserverTest,
::testing::Mock::VerifyAndClear(mock_writer); ::testing::Mock::VerifyAndClear(mock_writer);
observer()->OnAudioStateChanged(true); observer()->OnAudioStateChanged(true);
::testing::Mock::VerifyAndClear(mock_writer); ::testing::Mock::VerifyAndClear(mock_writer);
EXPECT_CALL(*mock_writer, OnDestroy());
}
TEST_F(LocalSiteCharacteristicsWebContentsObserverTest,
NotificationEventsWhenLoadingInBackground) {
MockDataWriter* mock_writer = NavigateAndReturnMockWriter(kTestUrl1);
TabLoadTracker::Get()->TransitionStateForTesting(web_contents(),
LoadingState::LOADING);
EXPECT_CALL(*mock_writer,
NotifySiteVisibilityChanged(TabVisibility::kBackground));
web_contents()->WasHidden();
::testing::Mock::VerifyAndClear(mock_writer);
EXPECT_CALL(*mock_writer, NotifyUsesNotificationsInBackground());
observer()->OnNonPersistentNotificationCreated(web_contents(), observer()->OnNonPersistentNotificationCreated(web_contents(),
GetNavIdForWebContents()); GetNavIdForWebContents());
::testing::Mock::VerifyAndClear(mock_writer); ::testing::Mock::VerifyAndClear(mock_writer);
......
...@@ -125,6 +125,10 @@ const char kSiteCharacteristicsDb_AudioUsageObservationWindow[] = ...@@ -125,6 +125,10 @@ const char kSiteCharacteristicsDb_AudioUsageObservationWindow[] =
"AudioUsageObservationWindow"; "AudioUsageObservationWindow";
const char kSiteCharacteristicsDb_NotificationsUsageObservationWindow[] = const char kSiteCharacteristicsDb_NotificationsUsageObservationWindow[] =
"NotificationsUsageObservationWindow"; "NotificationsUsageObservationWindow";
const char kSiteCharacteristicsDb_TitleOrFaviconChangeGracePeriod[] =
"TitleOrFaviconChangeGracePeriod";
const char kSiteCharacteristicsDb_AudioUsageGracePeriod[] =
"AudioUsageGracePeriod";
const char kInfiniteSessionRestore_MinSimultaneousTabLoads[] = const char kInfiniteSessionRestore_MinSimultaneousTabLoads[] =
"MinSimultaneousTabLoads"; "MinSimultaneousTabLoads";
...@@ -204,6 +208,14 @@ const base::TimeDelta ...@@ -204,6 +208,14 @@ const base::TimeDelta
kSiteCharacteristicsDb_NotificationsUsageObservationWindow_Default = kSiteCharacteristicsDb_NotificationsUsageObservationWindow_Default =
base::TimeDelta::FromHours(2); base::TimeDelta::FromHours(2);
// TODO(sebmarchand): Get some real-world data and choose an appropriate value
// here.
const base::TimeDelta
kSiteCharacteristicsDb_TitleOrFaviconChangeGracePeriod_Default =
base::TimeDelta::FromSeconds(20);
const base::TimeDelta kSiteCharacteristicsDb_AudioUsageGracePeriod_Default =
base::TimeDelta::FromSeconds(10);
// Default values for infinite session restore feature. Many of these are taken // Default values for infinite session restore feature. Many of these are taken
// from thin air, but others are motivated by existing metrics. // from thin air, but others are motivated by existing metrics.
const uint32_t kInfiniteSessionRestore_MinSimultaneousTabLoadsDefault = 1; const uint32_t kInfiniteSessionRestore_MinSimultaneousTabLoadsDefault = 1;
...@@ -367,6 +379,19 @@ SiteCharacteristicsDatabaseParams GetSiteCharacteristicsDatabaseParams() { ...@@ -367,6 +379,19 @@ SiteCharacteristicsDatabaseParams GetSiteCharacteristicsDatabaseParams() {
kSiteCharacteristicsDb_NotificationsUsageObservationWindow_Default kSiteCharacteristicsDb_NotificationsUsageObservationWindow_Default
.InSeconds())); .InSeconds()));
params.title_or_favicon_change_grace_period =
base::TimeDelta::FromSeconds(base::GetFieldTrialParamByFeatureAsInt(
features::kSiteCharacteristicsDatabase,
kSiteCharacteristicsDb_TitleOrFaviconChangeGracePeriod,
kSiteCharacteristicsDb_TitleOrFaviconChangeGracePeriod_Default
.InSeconds()));
params.audio_usage_grace_period =
base::TimeDelta::FromSeconds(base::GetFieldTrialParamByFeatureAsInt(
features::kSiteCharacteristicsDatabase,
kSiteCharacteristicsDb_AudioUsageGracePeriod,
kSiteCharacteristicsDb_AudioUsageGracePeriod_Default.InSeconds()));
return params; return params;
} }
......
...@@ -54,6 +54,8 @@ extern const char kSiteCharacteristicsDb_FaviconUpdateObservationWindow[]; ...@@ -54,6 +54,8 @@ extern const char kSiteCharacteristicsDb_FaviconUpdateObservationWindow[];
extern const char kSiteCharacteristicsDb_TitleUpdateObservationWindow[]; extern const char kSiteCharacteristicsDb_TitleUpdateObservationWindow[];
extern const char kSiteCharacteristicsDb_AudioUsageObservationWindow[]; extern const char kSiteCharacteristicsDb_AudioUsageObservationWindow[];
extern const char kSiteCharacteristicsDb_NotificationsUsageObservationWindow[]; extern const char kSiteCharacteristicsDb_NotificationsUsageObservationWindow[];
extern const char kSiteCharacteristicsDb_TitleOrFaviconChangeGracePeriod[];
extern const char kSiteCharacteristicsDb_AudioUsageGracePeriod[];
// Variation parameter names related to infinite session restore. // Variation parameter names related to infinite session restore.
extern const char kInfiniteSessionRestore_MinSimultaneousTabLoads[]; extern const char kInfiniteSessionRestore_MinSimultaneousTabLoads[];
...@@ -99,6 +101,10 @@ extern const base::TimeDelta ...@@ -99,6 +101,10 @@ extern const base::TimeDelta
kSiteCharacteristicsDb_AudioUsageObservationWindow_Default; kSiteCharacteristicsDb_AudioUsageObservationWindow_Default;
extern const base::TimeDelta extern const base::TimeDelta
kSiteCharacteristicsDb_NotificationsUsageObservationWindow_Default; kSiteCharacteristicsDb_NotificationsUsageObservationWindow_Default;
extern const base::TimeDelta
kSiteCharacteristicsDb_TitleOrFaviconChangeGracePeriod_Default;
extern const base::TimeDelta
kSiteCharacteristicsDb_AudioUsageGracePeriod_Default;
// Default values for infinite session restore feature. // Default values for infinite session restore feature.
extern const uint32_t kInfiniteSessionRestore_MinSimultaneousTabLoadsDefault; extern const uint32_t kInfiniteSessionRestore_MinSimultaneousTabLoadsDefault;
...@@ -220,6 +226,16 @@ struct SiteCharacteristicsDatabaseParams { ...@@ -220,6 +226,16 @@ struct SiteCharacteristicsDatabaseParams {
// Minimum observation window before considering that this website doesn't // Minimum observation window before considering that this website doesn't
// use notifications while in background. // use notifications while in background.
base::TimeDelta notifications_usage_observation_window; base::TimeDelta notifications_usage_observation_window;
// The period of time after loading during which we ignore title/favicon
// change events. It's possible for some site that are loaded in background to
// use some of these features without this being an attempt to communicate
// with the user (e.g. the tab is just really finishing to load).
base::TimeDelta title_or_favicon_change_grace_period;
// The period of time during which we ignore audio usage gets ignored after a
// tab gets backgrounded. It's necessary because there might be a delay
// between a media request gets initiated and the time the audio actually
// starts.
base::TimeDelta audio_usage_grace_period;
}; };
// Parameters used by the infinite session restore feature. // Parameters used by the infinite session restore feature.
......
...@@ -91,7 +91,9 @@ class TabManagerFeaturesTest : public testing::Test { ...@@ -91,7 +91,9 @@ class TabManagerFeaturesTest : public testing::Test {
base::TimeDelta favicon_update_observation_window, base::TimeDelta favicon_update_observation_window,
base::TimeDelta title_update_observation_window, base::TimeDelta title_update_observation_window,
base::TimeDelta audio_usage_observation_window, base::TimeDelta audio_usage_observation_window,
base::TimeDelta notifications_usage_observation_window) { base::TimeDelta notifications_usage_observation_window,
base::TimeDelta title_or_favicon_change_grace_period,
base::TimeDelta audio_usage_grace_period) {
SiteCharacteristicsDatabaseParams params = SiteCharacteristicsDatabaseParams params =
GetSiteCharacteristicsDatabaseParams(); GetSiteCharacteristicsDatabaseParams();
...@@ -103,6 +105,9 @@ class TabManagerFeaturesTest : public testing::Test { ...@@ -103,6 +105,9 @@ class TabManagerFeaturesTest : public testing::Test {
params.audio_usage_observation_window); params.audio_usage_observation_window);
EXPECT_EQ(notifications_usage_observation_window, EXPECT_EQ(notifications_usage_observation_window,
params.notifications_usage_observation_window); params.notifications_usage_observation_window);
EXPECT_EQ(title_or_favicon_change_grace_period,
params.title_or_favicon_change_grace_period);
EXPECT_EQ(audio_usage_grace_period, params.audio_usage_grace_period);
} }
void ExpectInfiniteSessionRestoreParams( void ExpectInfiniteSessionRestoreParams(
...@@ -152,7 +157,9 @@ class TabManagerFeaturesTest : public testing::Test { ...@@ -152,7 +157,9 @@ class TabManagerFeaturesTest : public testing::Test {
kSiteCharacteristicsDb_FaviconUpdateObservationWindow_Default, kSiteCharacteristicsDb_FaviconUpdateObservationWindow_Default,
kSiteCharacteristicsDb_TitleUpdateObservationWindow_Default, kSiteCharacteristicsDb_TitleUpdateObservationWindow_Default,
kSiteCharacteristicsDb_AudioUsageObservationWindow_Default, kSiteCharacteristicsDb_AudioUsageObservationWindow_Default,
kSiteCharacteristicsDb_NotificationsUsageObservationWindow_Default); kSiteCharacteristicsDb_NotificationsUsageObservationWindow_Default,
kSiteCharacteristicsDb_TitleOrFaviconChangeGracePeriod_Default,
kSiteCharacteristicsDb_AudioUsageGracePeriod_Default);
} }
void ExpectDefaultInfiniteSessionRestoreParams() { void ExpectDefaultInfiniteSessionRestoreParams() {
...@@ -274,6 +281,8 @@ TEST_F(TabManagerFeaturesTest, ...@@ -274,6 +281,8 @@ TEST_F(TabManagerFeaturesTest,
SetParam(kSiteCharacteristicsDb_TitleUpdateObservationWindow, "foo"); SetParam(kSiteCharacteristicsDb_TitleUpdateObservationWindow, "foo");
SetParam(kSiteCharacteristicsDb_AudioUsageObservationWindow, "."); SetParam(kSiteCharacteristicsDb_AudioUsageObservationWindow, ".");
SetParam(kSiteCharacteristicsDb_NotificationsUsageObservationWindow, "abc"); SetParam(kSiteCharacteristicsDb_NotificationsUsageObservationWindow, "abc");
SetParam(kSiteCharacteristicsDb_TitleOrFaviconChangeGracePeriod, "bleh");
SetParam(kSiteCharacteristicsDb_AudioUsageGracePeriod, "!!!");
EnableSiteCharacteristicsDatabase(); EnableSiteCharacteristicsDatabase();
ExpectDefaultSiteCharacteristicsDatabaseParams(); ExpectDefaultSiteCharacteristicsDatabaseParams();
} }
...@@ -284,13 +293,16 @@ TEST_F(TabManagerFeaturesTest, GetSiteCharacteristicsDatabaseParams) { ...@@ -284,13 +293,16 @@ TEST_F(TabManagerFeaturesTest, GetSiteCharacteristicsDatabaseParams) {
SetParam(kSiteCharacteristicsDb_AudioUsageObservationWindow, "360000"); SetParam(kSiteCharacteristicsDb_AudioUsageObservationWindow, "360000");
SetParam(kSiteCharacteristicsDb_NotificationsUsageObservationWindow, SetParam(kSiteCharacteristicsDb_NotificationsUsageObservationWindow,
"3600000"); "3600000");
SetParam(kSiteCharacteristicsDb_TitleOrFaviconChangeGracePeriod, "42");
SetParam(kSiteCharacteristicsDb_AudioUsageGracePeriod, "43");
EnableSiteCharacteristicsDatabase(); EnableSiteCharacteristicsDatabase();
ExpectSiteCharacteristicsDatabaseParams( ExpectSiteCharacteristicsDatabaseParams(
base::TimeDelta::FromSeconds(3600), base::TimeDelta::FromSeconds(36000), base::TimeDelta::FromSeconds(3600), base::TimeDelta::FromSeconds(36000),
base::TimeDelta::FromSeconds(360000), base::TimeDelta::FromSeconds(360000),
base::TimeDelta::FromSeconds(3600000)); base::TimeDelta::FromSeconds(3600000), base::TimeDelta::FromSeconds(42),
base::TimeDelta::FromSeconds(43));
} }
TEST_F(TabManagerFeaturesTest, TEST_F(TabManagerFeaturesTest,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment