File: custom-help-bubbles.md

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (208 lines) | stat: -rw-r--r-- 9,207 bytes parent folder | download | duplicates (5)
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
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
# Custom Help Bubbles

A custom help bubble is a UI used specifically for
[feature promos](./feature-promos.md) instead of a normal blue help bubble.
You can use a custom help bubble when you want all of the normal rate-limiting
and contention management of the feature promo system, but you need something
other than a blue bubble.

Note that custom help bubble UI are subject to allowlisting and UI review;
custom help bubble UI must conform to the normal requirements of help bubbles:
 - Must have an (X) button in the upper right or a prominent dismiss button
 - Must respond to ESC with the same effect as (X)
 - Must meet all other accessibility requirements

Note that custom help bubble UI will be focused when shown, so take that into
account when designing them, especially for screen reader users.

## Registering Custom Help Bubble IPH

When registering `browser_user_education_service.cc` use
`FeaturePromoSpecification::CreateForCustomUi()`. You'll note that this takes a
`CustomHelpBubbleFactoryCallback` which returns a `CustomHelpBubble`. Most of
the time you won't be directly creating your own CustomHelpBubble (though you
can!) but instead using a utility method to directly wrap your UI.

Which utility method you use to create your `CustomHelpBubbleFactoryCallback`
will depend on whether you are creating a Views BubbleDialog or a WebUI dialog.
If you are not creating one of these supported UI types, you will have to both
create your own UI and your own `CustomHelpBubble` class to wrap it.

## Custom Promo UI Using Views Bubble Dialogs

The simplest way to create a custom UI for your promo is by making your own
bubble dialog.

Here are the steps:

1. Derive your class from `BubbleDialogDelegateView` and also inherit from
   `CustomHelpBubbleUi`.
2. Ensure that any input that should close the dialog instead calls
   `CustomHelpBubbleUi::NotifyUserAction()` with one of the appropriate values
   (depending on the type of action the user took).
   - If you cannot prevent your bubble from closing (e.g. you are using default
     dismiss-on-escape behavior) make sure to call before closing the bubble.
   - If the bubble closes for any reason before `NotifyUserAction()` then an
     "aborted" result will be registered instead of the correct result.
   - Don't be afraid to call `DialogDelegate::SetCancelCallback()` and
     `DialogDelegate::SetAcceptCallback()` to set up some default behavior
     handling.

That's it! There's a ready (if very simple) example in
[TestCustomHelpBubbleView](./test/test_custom_help_bubble_view.h). For layout
examples (including how to get the close button positioned) check out
[HelpBubbleView](./views/help_bubble_view.h).

### Registering

To register a Custom UI feature promo with a Views-based custom bubble, first
follow all of the [normal steps for feature promos](./feature-promos.md), then
bind a `CustomHelpBubbleViewFactoryCallback` and pass it to
`CreateCustomHelpBubbleViewFactoryCallback()`.

Example:

```cpp
  // This could go inline in the call below, but is separated to make the
  // example clearer.
  auto my_custom_help_bubble_view_factory_callback =
      base::BindRepeating(
          [](ui::ElementContext from_context,
             HelpBubbleArrow arrow,
             FeaturePromoSpecification::BuildHelpBubbleParams build_params) {
            return std::make_unique<MyCustomUiBubbleDialogView>(
              build_params.anchor_element->AsA<views::TrackedElementViews>()->view(),
              arrow);
          });

  feature_promo_registry.Register(
      user_education::FeaturePromoSpecification::CreateForCustomUi(
          kIPHMyCustomUIPromoFeature,
          kAnchorElementId,
          CreateCustomHelpBubbleViewFactoryCallback(
              my_custom_help_bubble_view_factory_callback));
  )
```

Note: you can use the `from_context` parameter to locate the browser that the
promo is being launched from, even if `build_params.anchor_element` is in a
different window.

This example assumes that the anchor is a `View`, however you can get creative
if you want to; see
[FloatingWebUIHelpBubbleFactory](./webui/floating_webui_help_bubble_factory.h)
for one of the more sophisticated examples.

For handling of "custom action" IPH-like dialogs,
[see below](#custom-and-follow-up-actions).

## Custom Promo UI Using WebUI Bubble Dialogs

You can create dialogs without the limitations of Views by using WebUI (though
there is significantly more boilerplate involved). When you create a WebUI in
this way, it must be a "Top Chrome" WebUI, which has a few extra requirements so
it can be easily wrapped in a bubble dialog.

On the browser/C++ side:

1. Your controller class must extend `TopChromeWebUIController` and
   `CustomWebUIHelpBubbleController`.
   - You probably want `enable_chrome_send = true` as well.
   - The latter also puts this into the `UserEducation.` histogram bucket for
     Top Chrome WebUI performance metrics.
2. Call `webui::SetupWebUIDataSource()` in the constructor with the appropriate
   parameters.
3. Add `WEB_UI_CONTROLLER_TYPE_DECL()` in the header and
   `WEB_UI_CONTROLLER_TYPE_IMPL(ClassName)` in the source file.
4. Use `DECLARE_TOP_CHROME_WEBUI_CONFIG(ClassName)` to automatically create a
   config for your WebUI.
5. Call `.AddWebUIConfig(ClassNameConfig)` in
   [this file](/chrome/browser/ui/webui/chrome_web_ui_configs.cc).
6. Call or add to the appropriate `RegisterWebUIControllerInterfaceBinder()` in
   [this file](/chrome/browser/chrome_browser_interface_binders_webui.cc).
   - This should include `CustomHelpBubbleHandlerFactory` and any additional
     mojo bindings you need.

On the WebUI/Typescript side:
1. Fetch the `CustomHelpBubbleHandlerInterface` by calling
   `CustomHelpBubbleProxyImpl.getInstance().getHandler()`.
2. When the user interacts with a button or link, call
   `handler.notifyUserAction()` with the appropriate value.
   - Ensure you have a proper (X) close button as well as at least one link or
     action button the user can interact with.

Unlike Views, `CustomWebUIHelpBubbleController` is already a convenience class
that handles a lot of the boilerplate (yes, there's more than what's listed
above).

### Registering

To register a Custom UI feature promo with a WebUI-based custom bubble, first
follow all of the [normal steps for feature promos](./feature-promos.md), then
pass your WebUI's URL to `MakeCustomWebUIHelpBubbleFactoryCallback<T>()`.

Example:

```cpp
  feature_promo_registry.Register(
      user_education::FeaturePromoSpecification::CreateForCustomUi(
          kIPHMyCustomUIPromoFeature,
          kAnchorElementId,
          MakeCustomWebUIHelpBubbleFactoryCallback<
              MyCustomHelpBubbleWebUIController>(kMyWebUIUrl)));
```

For handling of "custom action" IPH-like dialogs,
[see below](#custom-and-follow-up-actions).

## Custom and Follow-Up Actions

There are three ways you can add additional behavior for after your bubble
closes:

1. Bubble triggers some additional action in the browser via a button, link,
   etc. in response to user action.
2. Bubble reports that the user selected "action" as their response, with logic
   provided when the IPH is registered, just as with "custom action"-style IPH.
3. External code decides the bubble should be closed due to user action outside
   the help bubble, and some further action should be taken.

### Option 1: Bubble Takes Action

An example of this would be the user clicking on a link in a WebUI dialog that
opens, say, a settings page.

Alternatively, a button might call some function directly (over a different mojo
interface if in a WebUI) that performs some action in the browser outside the
help bubble.

In all these cases, the bubble code should send `UserAction::kAction`, which
will cause the bubble to close and record the correct IPH result. No further
action is needed.

### Option 2: Custom Action-like Behavior

An example of this would be the bubble having a "Show Me" button that you want
to have open settings, start a tutorial, or something else.

In this case, the bubble can just send `UserAction::kAction`. There is an
optional fourth parameter to `CreateForCustomUi()` that is identical to the
callback in `CreateForCustomAction()`. If the bubble returns `kAction` then
this callback will be called as if this were a custom action IPH.

### Option 3: Close Promo and Continue

As with many other promos, sometimes the user will engage the feature being
promoted outside the promo - for example, the user presses the toolbar or menu
button the IPH is anchored to rather than interacting with the IPH.

In this case, at the very least, as with other IPH, you should call
`BrowserUserEducationInterface::NotifyFeaturePromoFeatureUsed()` (available on
`BrowserWindow`/`BrowserView` as well). However if you want to take additional
action (like highlighting menu elements in the app menu), you can instead call
`CloseFeaturePromoAndContinue()`.

Both of these can close the promo and mark it as dismissed. The latter allows
you to continue the promo indefinitely while the user is having some other
experience (which could be anything). Just remember to release the
`FeaturePromoHandle` when you're done!