1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
|
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/recently_audible_helper.h"
#include "base/no_destructor.h"
#include "base/time/default_tick_clock.h"
namespace {
const base::TickClock* GetDefaultTickClock() {
static base::NoDestructor<base::DefaultTickClock> default_tick_clock;
return default_tick_clock.get();
}
} // namespace
// static
constexpr base::TimeDelta RecentlyAudibleHelper::kRecentlyAudibleTimeout;
RecentlyAudibleHelper::~RecentlyAudibleHelper() = default;
bool RecentlyAudibleHelper::WasEverAudible() const {
return !last_audible_time_.is_null();
}
bool RecentlyAudibleHelper::IsCurrentlyAudible() const {
return last_audible_time_.is_max();
}
bool RecentlyAudibleHelper::WasRecentlyAudible() const {
if (last_audible_time_.is_max()) {
return true;
}
if (last_audible_time_.is_null()) {
return false;
}
base::TimeTicks recently_audible_time_limit =
last_audible_time_ + kRecentlyAudibleTimeout;
return tick_clock_->NowTicks() < recently_audible_time_limit;
}
base::CallbackListSubscription
RecentlyAudibleHelper::RegisterCallbackForTesting(const Callback& callback) {
return callback_list_.Add(callback);
}
RecentlyAudibleHelper::RecentlyAudibleHelper(content::WebContents* contents)
: content::WebContentsObserver(contents),
content::WebContentsUserData<RecentlyAudibleHelper>(*contents),
tick_clock_(GetDefaultTickClock()) {
if (contents->IsCurrentlyAudible()) {
last_audible_time_ = base::TimeTicks::Max();
}
}
void RecentlyAudibleHelper::OnAudioStateChanged(bool audible) {
// Redundant notifications should never happen.
DCHECK(audible != IsCurrentlyAudible());
// If audio is stopping remember the time at which it stopped and set a timer
// to fire the recently audible transition.
if (!audible) {
TransitionToNotCurrentlyAudible();
return;
}
// If the tab was not recently audible prior to the audio starting then notify
// that it has become recently audible again. Otherwise, swallow this
// notification.
bool was_recently_audible = WasRecentlyAudible();
last_audible_time_ = base::TimeTicks::Max();
recently_audible_timer_.Stop();
if (!was_recently_audible) {
callback_list_.Notify(true);
}
}
void RecentlyAudibleHelper::OnRecentlyAudibleTimerFired() {
DCHECK(last_audible_time_ + kRecentlyAudibleTimeout <=
tick_clock_->NowTicks());
// Notify of the transition to no longer being recently audible.
callback_list_.Notify(false);
// This notification is redundant in most cases, because WebContents is
// notified by AudioStreamMonitor of changes due to audio in its own frames
// (but not in inner contents) directly.
//
// TODO(crbug.com/41390955): Remove this once WebContents is notified
// via |callback_list_| in this class instead.
web_contents()->NotifyNavigationStateChanged(content::INVALIDATE_TYPE_AUDIO);
}
void RecentlyAudibleHelper::TransitionToNotCurrentlyAudible() {
last_audible_time_ = tick_clock_->NowTicks();
recently_audible_timer_.Start(
FROM_HERE, kRecentlyAudibleTimeout, this,
&RecentlyAudibleHelper::OnRecentlyAudibleTimerFired);
}
void RecentlyAudibleHelper::SetTickClockForTesting(
const base::TickClock* tick_clock) {
if (tick_clock) {
tick_clock_ = tick_clock;
} else {
tick_clock_ = GetDefaultTickClock();
}
}
void RecentlyAudibleHelper::SetCurrentlyAudibleForTesting() {
recently_audible_timer_.Stop();
last_audible_time_ = base::TimeTicks::Max();
}
void RecentlyAudibleHelper::SetRecentlyAudibleForTesting() {
TransitionToNotCurrentlyAudible();
}
void RecentlyAudibleHelper::SetNotRecentlyAudibleForTesting() {
last_audible_time_ = tick_clock_->NowTicks() - kRecentlyAudibleTimeout;
recently_audible_timer_.Stop();
}
WEB_CONTENTS_USER_DATA_KEY_IMPL(RecentlyAudibleHelper);
|