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
|
// 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.
#ifndef CHROME_BROWSER_UI_RECENTLY_AUDIBLE_HELPER_H_
#define CHROME_BROWSER_UI_RECENTLY_AUDIBLE_HELPER_H_
#include "base/callback_list.h"
#include "base/memory/raw_ptr.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
namespace base {
class TickClock;
}
// A helper that observers tab audibility and calculates whether or not a tab
// is recently audible. This is used to make the "audio playing" icon persist
// for a short period after audio stops. This class is only safe to use from the
// UI thread.
class RecentlyAudibleHelper
: public content::WebContentsObserver,
public content::WebContentsUserData<RecentlyAudibleHelper> {
public:
// This corresponds to the amount of time that the "audio playing" icon will
// persist in the tab strip after audio has stopped playing.
static constexpr base::TimeDelta kRecentlyAudibleTimeout = base::Seconds(2);
using CallbackList =
base::RepeatingCallbackList<void(bool was_recently_audible)>;
using Callback = CallbackList::CallbackType;
RecentlyAudibleHelper(const RecentlyAudibleHelper&) = delete;
RecentlyAudibleHelper& operator=(const RecentlyAudibleHelper&) = delete;
~RecentlyAudibleHelper() override;
// Returns true if the WebContents was ever audible over its lifetime.
bool WasEverAudible() const;
// Returns true if the WebContents is currently audible.
bool IsCurrentlyAudible() const;
// Returns true if the WebContents is currently audible, or was audible
// recently.
bool WasRecentlyAudible() const;
// Registers the provided repeating callback for notifications. Destroying
// the returned subscription will unregister the callback. This is safe to do
// while in the context of the callback itself.
base::CallbackListSubscription RegisterCallbackForTesting(
const Callback& callback);
// Allows replacing the tick clock that is used by this class. Setting it back
// to nullptr will restore the default tick clock.
void SetTickClockForTesting(const base::TickClock* tick_clock);
// State transition functions for testing. These do not invoke callbacks but
// modify state such that WasEverAudible/IsCurrentlyAudible/WasRecentlyAudible
// will return as expected. They also ensure the internal state of the timer
// is as expected.
void SetCurrentlyAudibleForTesting();
void SetRecentlyAudibleForTesting();
void SetNotRecentlyAudibleForTesting();
private:
friend class RecentlyAudibleHelperTest;
friend class content::WebContentsUserData<RecentlyAudibleHelper>;
explicit RecentlyAudibleHelper(content::WebContents* contents);
// contents::WebContentsObserver implementation:
void OnAudioStateChanged(bool audible) override;
// The callback that is invoked by the |recently_audible_timer_|.
void OnRecentlyAudibleTimerFired();
// Transitions to not being audible and starts the timer.
void TransitionToNotCurrentlyAudible();
// is_null() if the tab has never been audible, and is_max() if audio is
// currently playing. Otherwise, corresponds to the last time the tab was
// audible.
base::TimeTicks last_audible_time_;
// Timer for determining when "recently audible" transitions to false. This
// starts running when a tab stops being audible, and is canceled if it starts
// being audible again before it fires.
base::OneShotTimer recently_audible_timer_;
// List of callbacks observing this helper.
CallbackList callback_list_;
// The tick clock this object is using.
raw_ptr<const base::TickClock> tick_clock_;
WEB_CONTENTS_USER_DATA_KEY_DECL();
};
#endif // CHROME_BROWSER_UI_RECENTLY_AUDIBLE_HELPER_H_
|