tree: bd5fd5750e1da7af5a127fc9aba5081b3007abd0 [path history] [tgz]
  1. android/
  2. COMMON_METADATA
  3. DIR_METADATA
  4. OWNERS
  5. README.md
components/messages/README.md

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.

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 by adding a Message Identifier.
  2. Build a message model.
  3. 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 as an example):

  1. components/messages/android/message_enums.h [1]
  2. MessageIdentifier in tools/metrics/histograms/enums.xml [1]
  3. MessageIdentifier in tools/metrics/histograms/metadata/android/histograms.xml [1]
  4. MessageIdentifier string in components/messages/android/java/src/org/chromium/components/messages/MessagesMetrics.java [1]

Build a message model

All available model properties are defined in components/messages/android/…/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 as an example on the Java side and this CL 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 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 from https://google.com or navigating to https://google.com/about from 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, 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 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 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.