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 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
|
// Copyright 2021 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_VIEWS_TABS_TAB_HOVER_CARD_CONTROLLER_H_
#define CHROME_BROWSER_UI_VIEWS_TABS_TAB_HOVER_CARD_CONTROLLER_H_
#include <memory>
#include "base/callback_list.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_observation.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "chrome/browser/ui/performance_controls/tab_resource_usage_collector.h"
#include "chrome/browser/ui/views/tabs/tab_slot_controller.h"
#include "components/prefs/pref_change_registrar.h"
#include "ui/events/event.h"
#include "ui/views/animation/bubble_slide_animator.h"
#include "ui/views/animation/widget_fade_animator.h"
#include "ui/views/view.h"
#include "ui/views/view_observer.h"
namespace gfx {
class ImageSkia;
}
class TabHoverCardBubbleView;
class TabHoverCardThumbnailObserver;
class Tab;
class TabStrip;
// Controls how hover cards are shown and hidden for tabs.
class TabHoverCardController : public views::ViewObserver,
public TabResourceUsageCollector::Observer {
public:
explicit TabHoverCardController(TabStrip* tab_strip);
~TabHoverCardController() override;
bool IsHoverCardVisible() const;
bool IsHoverCardShowingForTab(Tab* tab) const;
void UpdateHoverCard(Tab* tab,
TabSlotController::HoverCardUpdateType update_type);
void PreventImmediateReshow();
TabHoverCardBubbleView* hover_card_for_testing() { return hover_card_.get(); }
size_t hover_cards_seen_count_for_testing() const {
return hover_cards_seen_count_;
}
static void set_disable_animations_for_testing(
bool disable_animations_for_testing) {
disable_animations_for_testing_ = disable_animations_for_testing;
}
private:
FRIEND_TEST_ALL_PREFIXES(TabHoverCardControllerTest, ShowWrongTabDoesntCrash);
FRIEND_TEST_ALL_PREFIXES(TabHoverCardControllerTest,
SetPreviewWithNoHoverCardDoesntCrash);
FRIEND_TEST_ALL_PREFIXES(TabHoverCardControllerTest, ShowPreviewsForTab);
FRIEND_TEST_ALL_PREFIXES(TabHoverCardControllerTest, DisablePreviewsForTab);
FRIEND_TEST_ALL_PREFIXES(TabHoverCardFadeFooterInteractiveUiTest,
HoverCardFooterMemoryUsagePrefEnabled);
FRIEND_TEST_ALL_PREFIXES(TabHoverCardFadeFooterInteractiveUiTest,
HoverCardFooterMemoryUsagePrefDisabled);
FRIEND_TEST_ALL_PREFIXES(TabHoverCardControllerTest,
HidePreviewsForDiscardedTab);
FRIEND_TEST_ALL_PREFIXES(TabHoverCardControllerTest,
DisableMemoryUsageForTab);
FRIEND_TEST_ALL_PREFIXES(TabHoverCardControllerTest,
ShowPreviewsForDiscardedTabWithThumbnail);
FRIEND_TEST_ALL_PREFIXES(TabHoverCardControllerTest,
DontCaptureUnderCriticalMemoryPressure);
FRIEND_TEST_ALL_PREFIXES(TabHoverCardPreviewsEnabledPrefTest, DefaultState);
class EventSniffer;
enum ThumbnailWaitState {
kNotWaiting,
kWaitingWithPlaceholder,
kWaitingWithoutPlaceholder
};
// Returns whether the hover card preview images feature is enabled.
static bool AreHoverCardImagesEnabled();
// Returns whether hover card animations should be shown on the current
// device.
static bool UseAnimations();
// views::ViewObserver:
void OnViewIsDeleting(views::View* observed_view) override;
void OnViewVisibilityChanged(views::View* observed_view,
views::View* starting_view) override;
// TabResourceUsageCollector::Observer:
void OnTabResourceMetricsRefreshed() override;
bool ArePreviewsEnabled() const;
void CreateHoverCard(Tab* tab);
void UpdateCardContent(Tab* tab);
void MaybeStartThumbnailObservation(Tab* tab, bool is_initial_show);
void StartThumbnailObservation(Tab* tab);
void UpdateOrShowCard(Tab* tab,
TabSlotController::HoverCardUpdateType update_type);
void ShowHoverCard(bool is_initial, const Tab* intended_tab);
void HideHoverCard();
bool ShouldShowImmediately(const Tab* tab) const;
const views::View* GetTargetAnchorView() const;
// Determines if `target_tab_` is still valid. Call this when entering
// TabHoverCardController from an asynchronous callback.
bool TargetTabIsValid() const;
// Helper for recording when a card becomes fully visible to the user.
void OnCardFullyVisible();
// Helper for resetting the cards seen count for testing.
void ResetCardsSeenCount();
// Animator events:
void OnFadeAnimationEnded(views::WidgetFadeAnimator* animator,
views::WidgetFadeAnimator::FadeType fade_type);
void OnSlideAnimationProgressed(views::BubbleSlideAnimator* animator,
double value);
void OnSlideAnimationComplete(views::BubbleSlideAnimator* animator);
void OnPreviewImageAvailable(TabHoverCardThumbnailObserver* observer,
gfx::ImageSkia thumbnail_image);
void OnHovercardImagesEnabledChanged();
void OnHovercardMemoryUsageEnabledChanged();
bool waiting_for_preview() const {
return thumbnail_wait_state_ != ThumbnailWaitState::kNotWaiting;
}
// Timestamp of the last time the hover card is hidden by the mouse leaving
// the tab strip. This is used for reshowing the hover card without delay if
// the mouse reenters within a given amount of time.
base::TimeTicks last_mouse_exit_timestamp_;
raw_ptr<Tab> target_tab_ = nullptr;
const raw_ptr<TabStrip> tab_strip_;
raw_ptr<TabHoverCardBubbleView> hover_card_ = nullptr;
base::ScopedObservation<views::View, views::ViewObserver>
hover_card_observation_{this};
base::ScopedObservation<views::View, views::ViewObserver>
target_tab_observation_{this};
std::unique_ptr<EventSniffer> event_sniffer_;
// These are used to track when a hover card is shown on a new tab for
// testing purposes. Counts cards seen from the time the first card is shown
// to a tab is selected, or the hover card is shown from scratch again.
raw_ptr<const void> hover_card_last_seen_on_tab_ = nullptr;
size_t hover_cards_seen_count_ = 0;
// Fade animations interfere with browser tests so we disable them in tests.
static bool disable_animations_for_testing_;
std::unique_ptr<views::WidgetFadeAnimator> fade_animator_;
// Used to animate the tab hover card's movement between tabs.
std::unique_ptr<views::BubbleSlideAnimator> slide_animator_;
std::unique_ptr<TabHoverCardThumbnailObserver> thumbnail_observer_;
base::CallbackListSubscription thumbnail_subscription_;
ThumbnailWaitState thumbnail_wait_state_ = ThumbnailWaitState::kNotWaiting;
base::CallbackListSubscription fade_complete_subscription_;
base::CallbackListSubscription slide_progressed_subscription_;
base::CallbackListSubscription slide_complete_subscription_;
// Ensure that an instance of the TabResourceUsageCollector exists so
// resources are up to date when we eventually show the hover card.
raw_ptr<TabResourceUsageCollector> tab_resource_usage_collector_;
// Tracks changes to the hover card preferences
PrefChangeRegistrar pref_change_registrar_;
bool hover_card_image_previews_enabled_ = false;
bool hover_card_memory_usage_enabled_ = false;
// Ensure that this timer is destroyed before anything else is cleaned up.
base::OneShotTimer delayed_show_timer_;
base::WeakPtrFactory<TabHoverCardController> weak_ptr_factory_{this};
};
#endif // CHROME_BROWSER_UI_VIEWS_TABS_TAB_HOVER_CARD_CONTROLLER_H_
|