summaryrefslogtreecommitdiff
path: root/chromium/components/messages/README.md
blob: 560d317b6a86e1a3704076066a87697d414e8461 (plain)
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
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
# Messages UI

Message UI is an alternative to InfoBar UI on Android. It provides a set of APIs
and a consistent, ephemeral and trustworthy UI with various lifecycles and
priorities.

[TOC]

## Overview

Each message should include at least 3 properties: title, primary icon and
primary button text.

Each message will automatically be displayed, hidden and dismissed according to
given scope (see details below) and can be dismissed automatically or manually.
By default, each message will be automatically dismissed after around 10s after
it is displayed. The timer will be reset if the text or icon on the UI is
changed or if the Message is re-shown. Also, users can dismiss the message by
swiping the UI upwards, leftwards and rightwards. The feature clients can also
manually dismiss the message through provided APIs if necessary.


## Developing a new Message UI Feature

You need to do the following things to enable your message UI, all described in
detail below.

1. [Declare your message UI](#Declaring-your-message-ui) by adding a Message Identifier.
2. [Build a message model](#Build-a-message-model).
3. [Enqueue your message model](#Enqueue-your-message-model).


## Declare your message UI

You need to create a `MessageIdentifier` that represents your Message UI, which
distinguishes it from other message UIs and enables some feature-specific metrics
to be recorded.

The MessageIdentifier is defined as an `enum` and a string, which should be
appended in following files (you can refer to
[this CL](https://chromium-review.googlesource.com/c/chromium/src/+/3139695) as an example):

1. `components/messages/android/message_enums.h` [[1](https://chromium-review.googlesource.com/c/chromium/src/+/3139695/4/components/messages/android/message_enums.h#90)]
2. MessageIdentifier in `tools/metrics/histograms/enums.xml` [[1](https://chromium-review.googlesource.com/c/chromium/src/+/3139695/4/tools/metrics/histograms/enums.xml#55511)]
3. MessageIdentifier in `tools/metrics/histograms/metadata/android/histograms.xml` [[1](https://chromium-review.googlesource.com/c/chromium/src/+/3139695/4/tools/metrics/histograms/metadata/android/histograms.xml#97)]
4. MessageIdentifier string in `components/messages/android/java/src/org/chromium/components/messages/MessagesMetrics.java` [[1](https://chromium-review.googlesource.com/c/chromium/src/+/3139695/4/components/messages/android/internal/java/src/org/chromium/components/messages/MessagesMetrics.java#102)]


## Build a message model

All available model properties are defined in [components/messages/android/…/MessageBannerProperties.java](https://source.chromium.org/chromium/chromium/src/+/main:components/messages/android/java/src/org/chromium/components/messages/MessageBannerProperties.java)

Only some of them are required:

1. TITLE: the main text of the message UI
2. ICON / ICON_RESOURCE_ID: the primary icon of the message UI, located at the
   start side of the UI.
3. PRIMARY_BUTTON_TEXT: the label of the primary button, located at the end of
   the message UI.

The rest are optional, but some of those are very commonly used:

1. DESCRIPTION: the description / subtitle of the message UI, usually used to
   help explain the purpose of the message UI.
2. ON_PRIMARY_ACTION: the callback function triggered when the user clicks on
   the primary button. Only called once. After this function is triggered, the
   message itself will be dismissed.
3. ON_SECONDARY_ACTION / SECONDARY_BUTTON_MENU_TEXT / SECONDARY_ICON_CONTENT_DESCRIPTION
   / SECONDARY_ICON / SECONDARY_ICON_RESOURCE_ID: these are used to set a
   secondary action / menu. If SECONDARY_BUTTON_MENU_TEXT is configured, clicking
   on the secondary button will trigger a single-menu-item popup menu.
   Clicking on the secondary icon does not guarantee that the message will be
   automatically dismissed. We recommend the feature code to manually dismiss
   the message when secondary action callback is triggered.
    1. Note: there are changes in-flight to allow multiple menu items.
       Documentation will be updated once that lands.
4. ON_DISMISSED: the callback function triggered when the message UI is dismissed.
   Dismiss means the message has been removed from the queue and will not be displayed again.

You can refer to
[this CL](https://chromium-review.googlesource.com/c/chromium/src/+/3039479/17/chrome/android/java/src/org/chromium/chrome/browser/survey/ChromeSurveyController.java#239)
as an example on the Java side and
[this CL](https://chromium-review.googlesource.com/c/chromium/src/+/3161257/5/chrome/browser/android/oom_intervention/near_oom_reduction_message_delegate.cc#35)
as an example on the Native side.

Some other, less commonly used properties are:

* ICON_TINT_COLOR: the default icon color is blue. Use this to update the icon
  color and set TINT_NONE to disable the icon tint color.
* DESCRIPTION_MAX_LINES: set max lines of the description. The default when this
  property isn't set is to show all the description texts, which may occupy too much screen space.


## Enqueue your message model

After the model is defined and ready to be displayed, it should be enqueued by
calling MessageDispatcher#enqueueMessage and providing the model, scope,
and priority.


### MessageDispatcher

MessageDispatcher is per-window object. In Java, use
[MessageDispatcherProvider#from](https://source.chromium.org/chromium/chromium/src/+/main:components/messages/android/java/src/org/chromium/components/messages/MessageDispatcherProvider.java;l=35)
to get a dispatcher available in the current window, which can be null if native
initialization is not finished yet. In C++, use
messages::MessageDispatcherBridge::Get() instead.


### Scope

Message scope can also be seen as the life cycle of a message UI. It pre-defines
when and where messages should be displayed and dismissed. There are 3 scopes in
total (components/messages/android/message_enums.h):

1. **Navigation**: messages of navigation will be displayed only on the web page
   for which they are enqueued. It will be hidden (not dismissed) when the user
   switches to another tab and displayed again when the user returns to the
   target tab. It will be dismissed when user navigates to another page, such as
   navigating to [https://chromium.org](https://chromium.org) from
   [https://google.com](https://google.com) or navigating to
   [https://google.com/about](https://google.com/about) from
   [https://google.com/settings](https://google.com/settings), and also
   dismissed when the tab where the page lives is closed. This should be used
   when the content and purpose of the Message is tightly related to a certain
   page. For example, password messages should be only displayed on the page
   where the user submits the password and dismissed if the user navigates to
   another page.
2. **Window**: messages of window scope will be displayed as long as the current
   window is alive (current window is dead usually when app is closed or user
   merges windows). It can be displayed on any tab and web page. So this scope
   should be used only when the content and purpose of the message is unrelated
   to the web page. For example, Sync Error message is related to the app rather
   than the page and works as an app-level notification. Use
   #EnqueueWindowScopedMessage to enqueue a window-scoped message.
3. **Web_Contents**: this one is rarely used and usually not recommended unless
   really necessary. The only difference between web_contents scope and navigation
   scope is that messages of web_contents scope do not dismiss when the user
   navigates to another page; i.e. it is only dismissed when its associated
   tab is closed.


### Priority

There are two types of priority: urgent (a.k.a high) and normal (a.k.a low).

Urgent messages will be displayed ASAP,  in spite of enqueued messages of normal
properties. Urgent should only be used when the message is so important that you
want users to take an action ASAP, such as a serious security risk found on the
page the user is visiting. Otherwise, use normal in most cases.


## Dismiss your message

As explained in [Overview](#Overview), by default, the message will be dismissed
in the following cases:

* Timeout
* Swiping gesture
* Primary action button is clicked
* The given scope is destroyed

In addition, messages can be dismissed by feature client code so that the
message won’t be displayed any more. Use MessageDispatcher#dismissMessage to
dismiss the message. The dismiss callback will still be triggered.


## Ownership in native

In native, MessageDispatcherBridge#EnqueueMessage will return a MessageWrapper
object. The feature client is responsible for managing it. We recommend
dismissing the message manually if the MessageWrapper object is still alive when
the owner of the MessageWrapper object is destroyed.


## Test

On the Java side,
[components/messages/android/test/…/messages/MessagesTestHelper.java](https://source.chromium.org/chromium/chromium/src/+/main:components/messages/android/test/java/src/org/chromium/components/messages/MessagesTestHelper.java)
is available to get all current enqueued messages and get the property model of a certain message.

In native, components/messages/android/mock_message_dispatcher_bridge.h is
available to test whether a message is enqueued and trigger some callbacks
manually. You can refer to
[this CL](https://chromium-review.googlesource.com/c/chromium/src/+/3161257/5/chrome/browser/android/oom_intervention/near_oom_reduction_message_delegate_unittest.cc)
as an example.


## Built-in Metrics

Some metrics have been pre-defined to help evaluate the effectiveness of a message.

**Android.Messages.Enqueued**

Records the message identifier each time a message is enqueued through
MessageDispatcher. This histogram can be used for getting a count of messages
broken down by message identifier.

**Android.Messages.Dismissed.{MessageIdentifier}**

Records the reason why this message is dismissed, such as primary action, timer,
gesture and so on.

**Android.Messages.TimeToAction.Dismiss.{MessageIdentifier}**

Records the time interval the message was displayed on the screen before the
user dismissed it with a gesture. The metric is NOT recorded when the user
presses primary or secondary button or when the message is auto-dismissed based
on timer.

**Android.Messages.TimeToAction.{MessageIdentifier}**

Records the time interval the message was displayed on the screen before the
user explicitly dismissed it. The metric is recorded when the user presses the
primary or secondary button, or dismisses the message with a gesture.


## Built-in Finch Parameter to control the duration

Using `autodismiss_duration_ms_{MessageIdentifier}` inside the feature
`MessagesForAndroidInfrastructure` to configure the duration through finch.
This method does not require any code changes in clients. E.g.:


```
// update the default timer duration of Sync Error Message to 30000 ms
Feature MessagesForAndroidInfrastructure {
    params = {
        autodismiss_duration_ms_SyncError = 30000
    }
}
```

> **Warning**: MessagesForAndroidInfrastructure is enabled by default.
> **DO NOT** disable it in any group. Disabling MessagesForAndroidInfrastructure
> will break other experiments depending on that flag.