#ifndef COMPONENTS_USER_EDUCATION_WEBUI_HELP_BUBBLE_HANDLER_H_
#define COMPONENTS_USER_EDUCATION_WEBUI_HELP_BUBBLE_HANDLER_H_
#include <map>
#include <memory>
#include <string>
#include <string_view>
#include <vector>
#include "base/functional/callback.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "components/user_education/common/help_bubble/help_bubble.h"
#include "components/user_education/common/help_bubble/help_bubble_params.h"
#include "content/public/browser/web_ui_controller.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "ui/base/interaction/element_identifier.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/webui/resources/cr_components/help_bubble/help_bubble.mojom.h"
#include "ui/webui/resources/js/tracked_element/tracked_element.mojom.h"
namespace content {
class WebContents;
}
namespace user_education {
class HelpBubbleWebUI;
class HelpBubbleHandlerBase
: public help_bubble::mojom::HelpBubbleHandler,
public tracked_element::mojom::TrackedElementHandler {
public:
using GetWebContentsCallback =
base::RepeatingCallback<content::WebContents*()>;
HelpBubbleHandlerBase(const HelpBubbleHandlerBase&) = delete;
HelpBubbleHandlerBase(const std::vector<ui::ElementIdentifier>& identifiers,
ui::ElementContext context);
HelpBubbleHandlerBase& operator=(const HelpBubbleHandlerBase&) = delete;
~HelpBubbleHandlerBase() override;
ui::ElementContext context() const { return context_; }
content::WebContents* GetWebContents();
bool IsHelpBubbleShowingForTesting(ui::ElementIdentifier id) const;
protected:
class ClientProvider {
public:
ClientProvider() = default;
ClientProvider(const ClientProvider&) = delete;
ClientProvider& operator=(const ClientProvider&) = delete;
virtual ~ClientProvider() = default;
virtual help_bubble::mojom::HelpBubbleClient* GetClient() = 0;
};
class VisibilityProvider {
public:
VisibilityProvider() = default;
VisibilityProvider(const VisibilityProvider& other) = delete;
VisibilityProvider& operator=(const VisibilityProvider&) = delete;
virtual ~VisibilityProvider() = default;
void set_handler(HelpBubbleHandlerBase* handler) { handler_ = handler; }
virtual bool CheckIsVisible() = 0;
protected:
HelpBubbleHandlerBase* handler() const { return handler_; }
void SetLastKnownVisibility(std::optional<bool> visible);
private:
raw_ptr<HelpBubbleHandlerBase> handler_ = nullptr;
};
HelpBubbleHandlerBase(std::unique_ptr<ClientProvider> client_provider,
std::unique_ptr<VisibilityProvider> visibility_provider,
GetWebContentsCallback get_web_contents_callback,
const std::vector<ui::ElementIdentifier>& identifiers,
ui::ElementContext context);
help_bubble::mojom::HelpBubbleClient* GetClient();
ClientProvider* client_provider() { return client_provider_.get(); }
virtual void ReportBadMessage(std::string_view error);
private:
friend class VisibilityProvider;
friend class FloatingWebUIHelpBubbleFactory;
friend class HelpBubbleFactoryWebUI;
friend class HelpBubbleWebUI;
FRIEND_TEST_ALL_PREFIXES(HelpBubbleHandlerTest, ExternalHelpBubbleUpdated);
struct ElementData;
bool is_web_contents_visible() const {
return web_contents_visibility_.value_or(false);
}
std::unique_ptr<HelpBubbleWebUI> CreateHelpBubble(
ui::ElementIdentifier target,
HelpBubbleParams params);
void OnHelpBubbleClosing(ui::ElementIdentifier anchor_id);
bool ToggleHelpBubbleFocusForAccessibility(ui::ElementIdentifier anchor_id);
gfx::Rect GetHelpBubbleBoundsInScreen(ui::ElementIdentifier anchor_id) const;
void OnFloatingHelpBubbleCreated(ui::ElementIdentifier anchor_id,
HelpBubble* help_bubble);
void OnFloatingHelpBubbleClosed(ui::ElementIdentifier anchor_id,
HelpBubble* help_bubble,
HelpBubble::CloseReason);
void OnWebContentsVisibilityChanged(std::optional<bool> visibility);
void HelpBubbleButtonPressed(const std::string& identifier_name,
uint8_t button) final;
void HelpBubbleClosed(
const std::string& identifier_name,
help_bubble::mojom::HelpBubbleClosedReason reason) final;
void BindTrackedElementHandler(
mojo::PendingReceiver<tracked_element::mojom::TrackedElementHandler>
handler) final;
void TrackedElementVisibilityChanged(const std::string& identifier_name,
bool visible,
const gfx::RectF& rect) final;
void TrackedElementActivated(const std::string& identifier_name) final;
void TrackedElementCustomEvent(const std::string& identifier_name,
const std::string& event_name) final;
ElementData* GetDataByName(const std::string& identifier_name,
ui::ElementIdentifier* found_identifier = nullptr);
std::optional<bool> web_contents_visibility_;
const std::unique_ptr<ClientProvider> client_provider_;
const std::unique_ptr<VisibilityProvider> visibility_provider_;
const GetWebContentsCallback get_web_contents_callback_;
const ui::ElementContext context_;
std::map<ui::ElementIdentifier, ElementData> element_data_;
mojo::Receiver<tracked_element::mojom::TrackedElementHandler>
tracked_element_handler_receiver_{this};
base::WeakPtrFactory<HelpBubbleHandlerBase> weak_ptr_factory_{this};
};
class HelpBubbleHandler : public HelpBubbleHandlerBase {
public:
HelpBubbleHandler(
mojo::PendingReceiver<help_bubble::mojom::HelpBubbleHandler>
pending_handler,
mojo::PendingRemote<help_bubble::mojom::HelpBubbleClient> pending_client,
content::WebUIController* controller,
const std::vector<ui::ElementIdentifier>& identifiers);
HelpBubbleHandler(
mojo::PendingReceiver<help_bubble::mojom::HelpBubbleHandler>
pending_handler,
mojo::PendingRemote<help_bubble::mojom::HelpBubbleClient> pending_client,
GetWebContentsCallback get_web_contents_callback,
void* context,
const std::vector<ui::ElementIdentifier>& identifiers);
~HelpBubbleHandler() override;
private:
class ClientProvider;
class VisibilityProvider;
void ReportBadMessage(std::string_view error) override;
mojo::Receiver<help_bubble::mojom::HelpBubbleHandler> receiver_;
};
}
#endif