1 // Copyright 2020 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef CHROME_BROWSER_UI_VIEWS_USER_EDUCATION_FEATURE_PROMO_CONTROLLER_VIEWS_H_ 6 #define CHROME_BROWSER_UI_VIEWS_USER_EDUCATION_FEATURE_PROMO_CONTROLLER_VIEWS_H_ 7 8 #include <memory> 9 10 #include "base/memory/weak_ptr.h" 11 #include "base/optional.h" 12 #include "base/scoped_observer.h" 13 #include "base/token.h" 14 #include "chrome/browser/ui/user_education/feature_promo_controller.h" 15 #include "ui/views/view_tracker.h" 16 #include "ui/views/widget/widget.h" 17 #include "ui/views/widget/widget_observer.h" 18 19 class BrowserView; 20 class FeaturePromoBubbleView; 21 struct FeaturePromoBubbleParams; 22 class FeaturePromoSnoozeService; 23 24 namespace base { 25 struct Feature; 26 class Token; 27 } // namespace base 28 29 namespace feature_engagement { 30 class Tracker; 31 } 32 33 // Views implementation of FeaturePromoController. There is one instance 34 // per window. 35 class FeaturePromoControllerViews : public FeaturePromoController, 36 public views::WidgetObserver { 37 public: 38 // Create the instance for the given |browser_view|. 39 explicit FeaturePromoControllerViews(BrowserView* browser_view); 40 ~FeaturePromoControllerViews() override; 41 42 // Get the appropriate instance for |view|. This finds the BrowserView 43 // that contains |view| and returns its instance. May return nullptr, 44 // but if |view| is in a BrowserView's hierarchy it shouldn't. 45 static FeaturePromoControllerViews* GetForView(views::View* view); 46 47 // Repositions the bubble (if showing) relative to the anchor view. 48 // This should be called whenever the anchor view is potentially 49 // moved. It is safe to call this if a bubble is not showing. 50 void UpdateBubbleForAnchorBoundsChange(); 51 52 // For IPH not registered with |FeaturePromoRegistry|. Only use this 53 // if it is infeasible to pre-register your IPH. 54 bool MaybeShowPromoWithParams( 55 const base::Feature& iph_feature, 56 const FeaturePromoBubbleParams& params, 57 BubbleCloseCallback close_callback = BubbleCloseCallback()); 58 59 // Only for security or privacy critical promos. Immedialy shows a 60 // promo with |params|, cancelling any normal promo and blocking any 61 // further promos until it's done. 62 // 63 // Returns an ID that can be passed to CloseBubbleForCriticalPromo() 64 // if successful. This can fail if another critical promo is showing. 65 base::Optional<base::Token> ShowCriticalPromo( 66 const FeaturePromoBubbleParams& params); 67 68 // Ends a promo started by ShowCriticalPromo() if it's still showing. 69 void CloseBubbleForCriticalPromo(const base::Token& critical_promo_id); 70 71 // FeaturePromoController: 72 bool MaybeShowPromo( 73 const base::Feature& iph_feature, 74 BubbleCloseCallback close_callback = BubbleCloseCallback()) override; 75 bool BubbleIsShowing(const base::Feature& iph_feature) const override; 76 bool CloseBubble(const base::Feature& iph_feature) override; 77 PromoHandle CloseBubbleAndContinuePromo( 78 const base::Feature& iph_feature) override; 79 80 // views::WidgetObserver: 81 void OnWidgetClosing(views::Widget* widget) override; 82 void OnWidgetDestroying(views::Widget* widget) override; 83 84 // Gets the IPH backend. Provided for convenience. feature_engagement_tracker()85 feature_engagement::Tracker* feature_engagement_tracker() { return tracker_; } 86 87 // Blocks any further promos from showing. Additionally cancels the 88 // current promo unless an outstanding PromoHandle from 89 // CloseBubbleAndContinuePromo exists. Intended for browser tests. 90 void BlockPromosForTesting(); 91 promo_bubble_for_testing()92 FeaturePromoBubbleView* promo_bubble_for_testing() { return promo_bubble_; } promo_bubble_for_testing()93 const FeaturePromoBubbleView* promo_bubble_for_testing() const { 94 return promo_bubble_; 95 } 96 snooze_service_for_testing()97 FeaturePromoSnoozeService* snooze_service_for_testing() { 98 return snooze_service_.get(); 99 } 100 101 private: 102 // Called when PromoHandle is destroyed to finish the promo. 103 void FinishContinuedPromo() override; 104 105 void ShowPromoBubbleImpl(const FeaturePromoBubbleParams& params); 106 107 void HandleBubbleClosed(); 108 109 // Call these methods when the user actively snooze or dismiss the IPH. 110 void OnUserSnooze(const base::Feature& iph_feature); 111 void OnUserDismiss(const base::Feature& iph_feature); 112 113 // The browser window this instance is responsible for. 114 BrowserView* const browser_view_; 115 116 // Snooze service that is notified when a user snoozes or dismisses the promo. 117 // Ask this service for display permission before |tracker_|. 118 std::unique_ptr<FeaturePromoSnoozeService> snooze_service_; 119 120 // IPH backend that is notified of user events and decides whether to 121 // trigger IPH. 122 feature_engagement::Tracker* const tracker_; 123 124 // Non-null as long as a promo is showing. Corresponds to an IPH 125 // feature registered with |tracker_|. 126 const base::Feature* current_iph_feature_ = nullptr; 127 128 // Has a value if a critical promo is showing. If this has a value, 129 // |current_iph_feature_| will usually be null. There is one edge case 130 // where this may not be true: when a critical promo is requested 131 // between a normal promo's CloseBubbleAndContinuePromo() call and its 132 // end. 133 base::Optional<base::Token> current_critical_promo_; 134 135 // The bubble currently showing, if any. 136 FeaturePromoBubbleView* promo_bubble_ = nullptr; 137 138 // If present, called when |current_iph_feature_|'s bubble stops 139 // showing. Only valid if |current_iph_feature_| and |promo_bubble_| 140 // are both non-null. 141 BubbleCloseCallback close_callback_; 142 143 // Stores the bubble anchor view so we can set/unset a highlight on 144 // it. 145 views::ViewTracker anchor_view_tracker_; 146 147 bool promos_blocked_for_testing_ = false; 148 149 ScopedObserver<views::Widget, views::WidgetObserver> widget_observer_{this}; 150 151 base::WeakPtrFactory<FeaturePromoController> weak_ptr_factory_{this}; 152 }; 153 154 #endif // CHROME_BROWSER_UI_VIEWS_USER_EDUCATION_FEATURE_PROMO_CONTROLLER_VIEWS_H_ 155