Customize Android notifications#
Android needs a persistent notification to keep the app alive during the navigation tracking.
By default a simple notification is shown, which has some basic configuration options.
Configure the basic notification#
Is possible to customize the icon, and the notification title, using the meta-data
tag in the AndroidManifest.xml
The available keys are:
com.citymapper.sdk.notification_title
for the title of the notificationcom.citymapper.sdk.notification_icon
for the icon of the notification
<meta-data
android:name="com.citymapper.sdk.notification_title"
android:value="@string/notification_title" />
<meta-data
android:name="com.citymapper.sdk.notification_icon"
android:resource="@drawable/ic_stat" />
From android oreo (API 26), notifications need a channel, you can change the channel name using the key com.citymapper.sdk.notification_channel
<meta-data
android:name="com.citymapper.sdk.notification_channel"
android:value="@string/notification_channel" />
Show a completely custom notification#
For more control over the notification, implement a custom foreground Service
which will run while navigation is active.
Specify the custom service class in the TrackingConfiguration
object when starting navigation, or retrieving a
NavigableRoute
.
val trackingConfiguration = TrackingConfiguration(
foregroundServiceClass = CustomForegroundService::class.java
)
It is strongly recommended that this service extends from BaseNavigationForegroundService
which gives a simple API
for building a notification from the latest RouteProgress
information, and automatically handles the service lifecycle.
class CustomForegroundService : BaseNavigationForegroundService<CustomForegroundService.State>() {
private val channel by lazy {
val channel = NotificationChannelCompat.Builder(
"notification-channel-custom",
NotificationManager.IMPORTANCE_DEFAULT
)
.setName("My custom navigation notification")
.setSound(null, null)
.setVibrationEnabled(false)
.setShowBadge(false)
.build()
NotificationManagerCompat.from(this).createNotificationChannel(channel)
channel
}
private val contentIntent by lazy {
PendingIntent.getActivity(
this,
0,
Intent(this, MyNavigationActivity::class.java).apply {
addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
},
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
}
override fun createNotificationModel(routeProgress: RouteProgress): State {
val secondsRemaining = routeProgress.durationSecondsRemaining
?: return State(title = "Loading...")
return State(title = "${secondsRemaining / 60} minutes left!")
}
override fun getNotification(notificationModel: State?): Notification {
return NotificationCompat.Builder(this, channel.id)
.setContentTitle(notificationModel?.title ?: "Loading...")
.setSmallIcon(R.drawable.my_notification_icon)
.setContentIntent(contentIntent)
.build()
}
// To prevent unneccesary notification updates, this must be a data class
// or correctly implement `equals`
data class State(val title: String)
}