Android Setup

Inbox

Requires SDK 4.11.0 or later

The Rover Inbox (sometimes known as the Communication Hub) is an embeddable app area that includes an inbox of posts and other features. It is intended to be embedded within a tab bar item in the app, and includes support for badging the tab bar item when new content is available.

Communication Hub

This feature is identified as "CommunicationHub" in the API to distinguish it from the legacy "Inbox" feature. The legacy Inbox (InboxActivity et al) is deprecated and will be removed in a future release.


Jetpack Compose

To embed the CommunicationHub composable as a new tab in a typical Jetpack Compose Navigation Bar, use a NavigationBarItem:

import io.rover.sdk.notifications.communicationhub.ui.CommunicationHub

enum class SelectedTab {
    /* ... other tab definitions ... */
    RoverInbox,
}

@Composable
fun MyApp() {
    var selectedTab: SelectedTab by remember { mutableStateOf(SelectedTab.RoverInbox) }

    MaterialTheme(
        // ... ensure a Material 3 theme is configured in your app ...
    ) {
        Scaffold(
            modifier = Modifier.fillMaxSize(),
            bottomBar = {
                NavigationBar() {
                    /* ... other tab button items ... */
                    NavigationBarItem(
                        selected = selectedTab == SelectedTab.RoverInbox,
                        icon = {
                            // observe the Rover badge count
                            val badgeText by Rover.shared.roverBadge.newBadge.collectAsState()

                            // use a BadgedBox to display the badge if it is non-null
                            BadgedBox(
                                badge = {
                                    badgeText?.let { text ->
                                        Badge { Text(text) }
                                    }
                                }
                            ) {
                                // Use an "Inbox" filled icon from Google's Material Icons. You will need to do the standard Google procedure for adding the Material icon to your app. https://fonts.google.com/
                                Icon(painter = painterResource(id = R.drawable.inboxfilled48), contentDescription = "Inbox", modifier = Modifier.size(24.dp))
                            }
                        },
                        label = {
                            Text("Inbox", maxLines = 1)
                        },
                        onClick = {
                            selectedTab = SelectedTab.RoverInbox
                        }
                    )
                }
            }
        ) {
            when (selectedTab) {
                /* ... other tab content ... */
                SelectedTab.RoverInbox -> {
                    CommunicationHub(
                        /// Optionally specify the Communication Hub's title bar text, if needed. It defaults to "Inbox".
                        title = "Inbox",
                        // any custom jetpack compose modifiers:
                        modifier = Modifier
                    )
                }
        }
    }
}

Theme configuration for WebView in Dark Mode

Even though the Rover Inbox (Communication Hub) uses Jetpack Compose, Android WebView will only honour dark mode if you have a values-night theme (as used by classic Android views) configured with the isLight property set to false. If you don't do this, posts in the Inbox will not be displayed in dark mode.

Ensure you have a values-night/themes.xml file in your app with the following content:

<item name="android:isLightTheme">false</item>

Compose Theme & Accent Color Configuration

When embedded in a tab, the CommunicationHub composable will adopt whatever Material 3 theme it is wrapped in (particularly for tinting controls like hyperlinks with the primary/accent color), just as other composables do. By wrapping a Material 3 Jetpack Compose theme around your Compose UI content, this will happen automatically for an embedded Communication Hub.

However, when the Communication Hub is launched from a deep link, this theme provided by UI context is not available. Therefore, in order for the Communication Hub UI to be properly styled, Material 3 color schemes need to be supplied globally to Rover for it to use when it launches a standalone activity with the Communication Hub composable.

Typically, as part of your Material 3 Theme, you will have defined a lightScheme and darkScheme in your app.

You can set these to Rover's global lightColorScheme and darkColorScheme properties to ensure that the Communication Hub is presented in the correct theme when launched from a deep link:

Rover.shared.lightColorScheme = lightScheme
Rover.shared.darkColorScheme = darkScheme

Classic Android Views

To use the CommunicationHub in a classic Android Views app with an MDC BottomNavigationView, and display a badge count on the Inbox tab, perform the following steps.

  1. Create a Fragment to host the CommunicationHub composable:
import io.rover.sdk.notifications.communicationhub.ui.CommunicationHub

class CommunicationHubFragment : Fragment() {
    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        // Use ComposeView to host the CommunicationHub composable
        return ComposeView(requireContext()).apply {
            setContent {
                // configure a Material 3 theme as you would normally do here. Rover's Communication Hub will adopt it, paricularly for the primary (or accent) color.
                MaterialTheme {
                    CommunicationHub(
                        /// Optionally specify the Communication Hub's title bar text, if needed. It defaults to "Inbox".
                        title = "Inbox",
                        // any custom jetpack compose modifiers:
                        modifier = Modifier
                    )
                }
            }
        }
    }
}
  1. In your Activity, set up the BottomNavigationView and observe the badge count:
class MainActivity : AppCompatActivity() {

    private var badgeJob: Job? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main) // Your layout with a FrameLayout and BottomNavigationView

        // Set initial fragment
        if (savedInstanceState == null) {
            supportFragmentManager.beginTransaction()
            // where "HomeFragment" is the view for your default tab
                .replace(R.id.fragment_container, HomeFragment())
                .commit()
        }

        val bottomNav = findViewById<BottomNavigationView>(R.id.bottom_navigation)

        // Set up badge for Inbox tab
        val inboxMenuItemId = R.id.tab_inbox

        // Observe badge count using a coroutine
        badgeJob = lifecycleScope.launch {
            // Import kotlinx.coroutines.flow.collectLatest
            io.rover.sdk.core.Rover.shared.roverBadge.newBadge.collect { badgeText ->
                val badge = bottomNav.getOrCreateBadge(inboxMenuItemId)
                if (badgeText.isNullOrEmpty() || badgeText == "0") {
                    // Remove badge if no unread
                    bottomNav.removeBadge(inboxMenuItemId)
                } else {
                    badge.isVisible = true
                    badge.number = badgeText.toIntOrNull() ?: 0
                }
            }
        }

        bottomNav.setOnItemSelectedListener { item ->
            when (item.itemId) {
                /* ... other tab views ... */
                R.id.tab_inbox -> {
                    supportFragmentManager.beginTransaction()
                        .replace(R.id.fragment_container, CommunicationHubFragment())
                        .commit()
                    true
                }
                // ... handle other tabs ...
                else -> false
            }
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        badgeJob?.cancel()
    }
}
  1. In your res/layout/activity_main.xml, you should have something like:
<LinearLayout ... >
    <FrameLayout
        android:id="@+id/fragment_container"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"/>
    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/bottom_navigation"
        ... />
</LinearLayout>
  1. In your res/menu/bottom_nav_menu.xml, define the menu items:
<menu>
    <item
        android:id="@+id/tab_home"
        android:icon="@drawable/ic_home"
        android:title="Home"/>
    <item
        android:id="@+id/tab_inbox"
        android:icon="@drawable/ic_inbox"
        android:title="Inbox"/>
    <!-- ... other tabs ... -->
</menu>

This approach allows you to use the CommunicationHub composable in a classic Android Views app with a BottomNavigationView, and display a badge count on the Inbox tab that updates automatically.

Previous
Push Notifications