# 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](#Declare-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.