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.
- 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
)
}
}
}
}
}
- 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()
}
}
- 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>
- 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.