Android Message Center

The default Message Center is available for iOS and Android. Minimal integration is required, and basic theming options are supported.

Installation

Message Center requires adding the urbanairship-message-center module:


dependencies {
    val airshipVersion = "18.6.0"
    
    implementation("com.urbanairship.android:urbanairship-message-center:$airshipVersion")
}

dependencies {
  def airshipVersion = "18.6.0"

  implementation "com.urbanairship.android:urbanairship-message-center:$airshipVersion"
}

Listening for Inbox Updates

To listen for inbox changes, add a InboxListener the inbox to be notified whenever the message listing changes:

// Option 1: Messages Flow
scope.launch {
    MessagesCenter.shared().inbox.getMessagesFlow().collect { messages ->
        // ...
    }
}

// Option 2: InboxListener
MessageCenter.shared().inbox.addListener(object: InboxListener {
    override fun onInboxUpdated() {
        // ...
    }
})
MessageCenter.shared().getInbox().addListener(() -> {
    // ...         
});

Styling the Message Center

The Message Center can be styled via a combination of theme attributes and xml resource merging to override the default styles. The Message Center can be customized with the following theme attributes:

messageCenterToolbarTitle
String to use for the Message Center toolbar title
messageCenterIconsEnabled
Flag to enable message thumbnails in the message list
messageCenterPlaceholderIcon
The default placeholder image for message thumbnails
messageCenterItemDividersEnabled
Flag to enable dividers between messages in the list
messageCenterItemDividerInsetStart
The start inset for message list dividers
messageCenterItemDividerInsetEnd
The end inset for message list dividers
dividerColor (set via Material Theme)
The message list divider color, if dividers are enabled

Android resource merging can be used to further customize the default styles that the SDK provides. Copy portions or all of the style sheet into the application’s styles.xml or a new style resource, then change any of the styles.

Example
<style name="AppTheme" parent="Theme.Material3.DayNight.NoActionBar">
    <!-- ... -->
</style>

<!-- Custom Message Center style (using AppTheme colors as a base) -->
<style name="UrbanAirship.MessageCenter" parent="AppTheme">
    <!-- Set custom toolbar title -->
    <item name="messageCenterToolbarTitle">@string/inbox</item>

    <!-- Show message thumbnails in the message list -->
    <item name="messageCenterIconsEnabled">true</item>

    <!-- MessageCenter specific colors can be set here (overriding any defaults from AppTheme) -->
</style>

<!-- Custom message title text appearance -->
<style name="UrbanAirship.MessageCenter.TextAppearance.MessageTitle" parent="TextAppearance.Material3.TitleMedium">
    <item name="android:textStyle">italic</item>
</style>

<!-- Custom message date text appearance -->
<style name="UrbanAirship.MessageCenter.TextAppearance.MessageSentDate" parent="TextAppearance.Material3.BodySmall">
    <item name="android:textStyle">italic</item>
    <item name="android:textColor">?android:textColorSecondary</item>
</style>

Layout Support

The Message Center provides automatic support for both single-pane and two-pane layouts, when on large display sizes or foldable devices. In two-pane mode, the selected message is highlighted in the list and displayed in the detail pane. Right-to-left (RTL) layout is also supported when android:supportsRtl="true" is set in your application manifest.

Message Center Filtering

Sometimes it can be useful to filter the contents of the Message Center according to some predetermined pattern. To facilitate this, use the shared MessageCenter instance to set a predicate. Once set, only messages that match the predicate will be displayed.

Filtering messages

MessageCenter.shared().predicate = Predicate { message ->
    message.title.contains("Cool")
}
MessageCenter.shared().setPredicate(message -> 
    message.getTitle().contains("Cool")
);

Embedding the Message Center

Embedding MessageCenterFragment in an xml layout

The Message Center UI can be embedded in any FragmentActivity or Fragment using MessageCenterFragment . When embedding the MessageCenterFragment, either use a FragmentContainerView or create the fragment directly.

Example layout xml
<androidx.fragment.app.FragmentContainerView
    android:id="@+id/fragment_container_view"
    android:name="com.urbanairship.messagecenter.ui.MessageCenterFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

Instantiating a MessageCenterFragment

val fragment = MessageCenterFragment.newInstance()
MessageCenterFragment fragment = MessageCenterFragment.newInstance();

You will need to override the show behavior to navigate to your embedded fragment instead of letting Airship launch the MessageCenterActivity.

Advanced embedding

For more control over the UI, MessageCenterListFragment and MessageCenterMessageFragment can be used to embed the list and message views separately, each maintaining its own Toolbar.

This example assumes that Jetpack Navigation is being used to navigate between the list and message views, but any navigation method can be used.

class CustomMessageListFragment() : MessageCenterListFragment() {

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        val toolbar = view.findViewById<Toolbar>(R.id.toolbar)
        toolbar.inflateMenu(messageCenterR.menu.ua_message_center_list_pane_menu)

        // Set up the toolbar, if desired.
        setupWithNavController(toolbar, findNavController())

        onMessageClickListener = OnMessageClickListener {
            // Handle message clicks by navigating to the message fragment 
            // (or replace with custom navigation logic).
            findNavController().navigate(
                R.id.action_messageCenterFragment_to_messageFragment, bundleOf(
                    MessageCenterMessageFragment.ARG_MESSAGE_ID to it.id,
                    MessageCenterMessageFragment.ARG_MESSAGE_TITLE to it.title
                )
            )
        }
    }
}
class CustomMessageFragment : MessageCenterMessageFragment(R.layout.fragment_inbox_message) {

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        toolbar?.run {
            // Inflate the default menu
            inflateMenu(messageCenterR.menu.ua_message_center_message_pane_menu)

            // Set up the toolbar, if desired.
            setupWithNavController(toolbar, findNavController(view))
        }

        // Handle message deletion from the message view
        onMessageDeletedListener = OnMessageDeletedListener {
            // Handle message deletion by navigating back to the message list fragment 
            // (or replace with custom navigation logic).
            findNavController().popBackStack()

            // Optionally show a toast confirmation message
            context?.run {
                val msg = getQuantityString(messageCenterR.plurals.ua_mc_description_deleted, 1, 1)
                Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
            }
        }
    }
}

These custom fragments can then be embedded into your app UI using FragmentContainerView or by using FragmentManager programmatically. You will need to override the show behavior to navigate to your custom message list fragment instead of letting Airship launch the MessageCenterActivity.