|  | // Copyright 2024 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_USER_EDUCATION_BROWSER_USER_EDUCATION_INTERFACE_H_ | 
|  | #define CHROME_BROWSER_UI_USER_EDUCATION_BROWSER_USER_EDUCATION_INTERFACE_H_ | 
|  |  | 
|  | #include <concepts> | 
|  |  | 
|  | #include "base/feature_list.h" | 
|  | #include "base/memory/scoped_refptr.h" | 
|  | #include "base/types/pass_key.h" | 
|  | #include "components/user_education/common/feature_promo/feature_promo_controller.h" | 
|  | #include "components/user_education/common/feature_promo/feature_promo_handle.h" | 
|  | #include "components/user_education/common/feature_promo/feature_promo_result.h" | 
|  | #include "components/user_education/common/new_badge/new_badge_controller.h" | 
|  | #include "components/user_education/common/user_education_context.h" | 
|  | #include "ui/base/unowned_user_data/scoped_unowned_user_data.h" | 
|  |  | 
|  | class BrowserFeaturePromoControllerBase; | 
|  | class BrowserView; | 
|  | class BrowserWindowInterface; | 
|  | class NewTabPageUI; | 
|  | class NtpPromoHandler; | 
|  |  | 
|  | namespace content { | 
|  | class WebContents; | 
|  | } | 
|  |  | 
|  | // Describes what to do when the feature associated with an IPH is used. | 
|  | enum class FeaturePromoFeatureUsedAction { | 
|  | // If the promo is showing, it is dismissed. If it is queued, it will be | 
|  | // canceled. In most cases, the promo will not be shown again. | 
|  | kClosePromoIfPresent, | 
|  | // If the promo is showing or queued, it continues to be showing or queued. | 
|  | // However, marking the feature as used may prevent the promo from showing | 
|  | // in the future. If you intend to use e.g. CloseFeaturePromoAndContinue(), | 
|  | // this option will avoid terminating the promo prematurely. | 
|  | kIgnorePromoIfPresent, | 
|  | }; | 
|  |  | 
|  | // Provides the interface for common User Education actions. | 
|  | class BrowserUserEducationInterface { | 
|  | public: | 
|  | DECLARE_USER_DATA(BrowserUserEducationInterface); | 
|  |  | 
|  | explicit BrowserUserEducationInterface(BrowserWindowInterface* browser); | 
|  | BrowserUserEducationInterface(const BrowserUserEducationInterface&) = delete; | 
|  | void operator=(const BrowserUserEducationInterface&) = delete; | 
|  | virtual ~BrowserUserEducationInterface(); | 
|  |  | 
|  | virtual void Init(BrowserView*); | 
|  | virtual void TearDown(); | 
|  |  | 
|  | // Only a limited number of non-test classes are allowed direct access to the | 
|  | // `UserEducationContext`. | 
|  | template <typename T> | 
|  | requires std::same_as<T, BrowserFeaturePromoControllerBase> || | 
|  | std::same_as<T, UserEducationInternalsPageHandlerImpl> || | 
|  | std::same_as<T, NtpPromoHandler> || std::same_as<T, NewTabPageUI> | 
|  |  | 
|  | const user_education::UserEducationContextPtr& GetUserEducationContext( | 
|  | base::PassKey<T>) const { | 
|  | return GetUserEducationContextImpl(); | 
|  | } | 
|  |  | 
|  | // Test-only accessor for user education context. | 
|  | const user_education::UserEducationContextPtr& | 
|  | GetUserEducationContextForTesting() { | 
|  | return GetUserEducationContextImpl(); | 
|  | } | 
|  |  | 
|  | // Returns whether `iph_feature` is queued to be shown. Promos can be queued | 
|  | // for a period of time before they become active, if they are being held due | 
|  | // to an incompatible UI state or a blocking IPH. | 
|  | virtual bool IsFeaturePromoQueued(const base::Feature& iph_feature) const = 0; | 
|  |  | 
|  | // Returns whether the promo associated with `iph_feature` is running. | 
|  | // | 
|  | // Includes promos with visible bubbles and those which have been continued | 
|  | // with CloseFeaturePromoAndContinue() and are still running in the | 
|  | // background. | 
|  | virtual bool IsFeaturePromoActive(const base::Feature& iph_feature) const = 0; | 
|  |  | 
|  | // Returns whether `MaybeShowFeaturePromo()` would succeed if called now. | 
|  | // | 
|  | // USAGE NOTE: Only call this method if figuring out whether to try to show an | 
|  | // IPH would involve significant expense. This method may itself have | 
|  | // non-trivial cost. | 
|  | virtual user_education::FeaturePromoResult CanShowFeaturePromo( | 
|  | const base::Feature& iph_feature) const = 0; | 
|  |  | 
|  | // Maybe shows an in-product help promo. | 
|  | // | 
|  | // If this feature promo is likely to be shown at browser startup, prefer | 
|  | // calling `MaybeShowStartupFeaturePromo()` instead. | 
|  | // | 
|  | // If determining whether to call this method would involve significant | 
|  | // expense, you *may* first call `CanShowFeaturePromo()` before doing the | 
|  | // required computation; otherwise just call this method. | 
|  | virtual void MaybeShowFeaturePromo( | 
|  | user_education::FeaturePromoParams params) = 0; | 
|  |  | 
|  | // Maybe shows an in-product help promo at startup, whenever the Feature | 
|  | // Engagement system is fully initialized. If the promo cannot be queued for | 
|  | // whatever reason, `params.show_promo_result_callback` will be called with | 
|  | // the appropriate error. The promo may still not run if it is excluded for | 
|  | // other reasons (e.g. another promo starts first; its Feature Engagement | 
|  | // conditions are not satisfied). | 
|  | // | 
|  | // On success, when the FE system is initialized (which might be immediately), | 
|  | // or when the promo is determined to have failed to show for any reason, | 
|  | // `show_promo_result_callback` is called with the result of whether the promo | 
|  | // was actually shown. Since `show_promo_result_callback` could be called any | 
|  | // time, make sure that you will not experience any race conditions or UAFs if | 
|  | // the calling object goes out of scope. | 
|  | virtual void MaybeShowStartupFeaturePromo( | 
|  | user_education::FeaturePromoParams params) = 0; | 
|  |  | 
|  | // Aborts the in-product help promo for `iph_feature` if it is showing or | 
|  | // cancels a pending startup promo. Aborting a promo means it was not fully | 
|  | // shown or interacted with, and may allow the promo to show again. Returns | 
|  | // whether a showing or pending promo was canceled. | 
|  | virtual bool AbortFeaturePromo(const base::Feature& iph_feature) = 0; | 
|  |  | 
|  | // Closes the bubble for a feature promo but continues the promo; returns a | 
|  | // handle that can be used to end the promo when it is destructed. The handle | 
|  | // will be valid (i.e. have a true boolean value) if the promo was showing, | 
|  | // invalid otherwise. | 
|  | virtual user_education::FeaturePromoHandle CloseFeaturePromoAndContinue( | 
|  | const base::Feature& iph_feature) = 0; | 
|  |  | 
|  | // Records that the user has engaged the specific `feature` associated with an | 
|  | // IPH promo; this information is used to determine whether to show the promo | 
|  | // in the future. Also specifies which `action` should be taken regarding | 
|  | // existing queued or showing promos associated with `feature`. | 
|  | // | 
|  | // Returns whether a promo was closed as a result. | 
|  | virtual bool NotifyFeaturePromoFeatureUsed( | 
|  | const base::Feature& feature, | 
|  | FeaturePromoFeatureUsedAction action) = 0; | 
|  |  | 
|  | // Records that the user has performed an action that is specified in in a | 
|  | // FeaturePromoSpecification by calling the `SetAdditionalConditions()` | 
|  | // method; this information may be used to determine whether and when to show | 
|  | // the promo in the future. | 
|  | virtual void NotifyAdditionalConditionEvent(const char* event_name) = 0; | 
|  |  | 
|  | // Returns whether a "New" Badge should be shown on the entry point for | 
|  | // `feature`; the badge must be registered for the feature in | 
|  | // browser_user_education_service.cc. Call exactly once per time the surface | 
|  | // containing the badge will be shown to the user. | 
|  | virtual user_education::DisplayNewBadge MaybeShowNewBadgeFor( | 
|  | const base::Feature& feature) = 0; | 
|  |  | 
|  | // Records that the user has engaged the specific `feature` associated with a | 
|  | // "New" Badge; this information is used to determine whether to show the | 
|  | // badge in the future. | 
|  | // | 
|  | // You can also call `UserEducationService::MaybeNotifyNewBadgeFeatureUsed()` | 
|  | // if you only have access ot a `BrowserContext` or `Profile`. | 
|  | virtual void NotifyNewBadgeFeatureUsed(const base::Feature& feature) = 0; | 
|  |  | 
|  | // Returns the interface associated with the browser containing `contents` in | 
|  | // its tabstrip, or null if `contents` is not a tab in any known browser. | 
|  | // | 
|  | // For WebUI embedded in a specific browser window or secondary UI of a | 
|  | // browser window, instead just use the appropriate BrowserWindow[Interface] | 
|  | // for that window. | 
|  | static BrowserUserEducationInterface* MaybeGetForWebContentsInTab( | 
|  | content::WebContents* contents); | 
|  |  | 
|  | // Retrieves from the a browser window interface, or null if none. | 
|  | // Note: May return null in unit_tests, even for a valid `browser`. | 
|  | static BrowserUserEducationInterface* From(BrowserWindowInterface* browser); | 
|  |  | 
|  | protected: | 
|  | virtual const user_education::UserEducationContextPtr& | 
|  | GetUserEducationContextImpl() const = 0; | 
|  |  | 
|  | private: | 
|  | ui::ScopedUnownedUserData<BrowserUserEducationInterface> | 
|  | scoped_unowned_user_data_; | 
|  | }; | 
|  |  | 
|  | #endif  // CHROME_BROWSER_UI_USER_EDUCATION_BROWSER_USER_EDUCATION_INTERFACE_H_ |