Android Live Updates for an Ongoing Workout Notification
Last verified October 3, 2026 · 7 min read
The iPhone has Live Activities; the Android phone now has Live Updates, and for an ongoing workout they solve the same problem: keeping a session that is happening right now visible without the app open. Unlike ActivityKit, a Live Update is not a separate framework. It is an ordinary ongoing notification that asks the system to promote it, and the system decides whether it qualifies. On the watch, the counterpart is Wear OS ongoing activity.
What Google says a promoted notification gets#
Google's Live Updates guide describes promoted notifications as appearing more prominently on system surfaces: at the top of the notification drawer, on the lock screen, and as a chip in the status bar. Promoted cards are expanded by default and cannot be collapsed. Google also states that users can temporarily dismiss a Live Update or demote it to a standard notification, so the design has to survive being shown as a plain notification.
The eligibility checklist#
Google lists these requirements for a notification to qualify as a Live Update:
- It uses the standard style,
BigTextStyle,CallStyle,ProgressStyleorMetricStyle. - The app declares the non-runtime permission
android.permission.POST_PROMOTED_NOTIFICATIONSin its manifest. - It requests promotion with
EXTRA_REQUEST_PROMOTED_ONGOINGorsetRequestPromotedOngoing. - It is ongoing, with
FLAG_ONGOING_EVENTset. - It has a content title.
- It has no custom content view, which means no
RemoteViews. - It is not a group summary set with
setGroupSummary. - It does not set
setColorizedto true. - Its notification channel is not
IMPORTANCE_MIN.
Google adds that device manufacturers can enforce additional criteria, and points to their own documentation. Treat promotion as something you request, not something you get.
The permission line deserves a second look. Google's Manifest.permission reference says POST_PROMOTED_NOTIFICATIONS is required in addition to, not instead of, POST_NOTIFICATIONS. A user who denied the ordinary notification permission therefore gets no Live Update either; push notifications for a fitness app covers what that denial takes with it.
Is a workout an appropriate use?#
Google gives three usage criteria: the activity must be ongoing, user-initiated and time-sensitive. A workout meets all three, and Google uses it as an example: most Live Updates should represent activities the user explicitly triggered, "such as starting a workout."
The same criteria rule out the things fitness teams are tempted to promote. Google says an activity in the past should use a standard notification, which covers the post-workout summary. It lists alerts, upcoming calendar events and quick access to app features as inappropriate, which covers a reminder to train. And it says not to let activities triggered by other parties generate Live Updates, which matters if your product has coaches or training partners.
API levels, as Google's reference labels them#
| API | What Google's reference says | Added in |
|---|---|---|
Notification.FLAG_PROMOTED_ONGOING | Set by the system when the notification is promoted | API level 36 |
Notification.hasPromotableCharacteristics() | Whether the notification has every characteristic that makes it eligible, ignoring user preferences | API level 36 |
NotificationManager.canPostPromotedNotifications() | Whether the app's properly formatted notifications can appear promoted | API level 36 |
Notification.Builder.setShortCriticalText() | Very short text for the status bar chip; suggested maximum 7 characters | API level 36 |
Notification.ProgressStyle | Expanded progress bar with segments, points and a tracker icon | API level 36 |
Notification.Builder.setRequestPromotedOngoing() | Requests promoted ongoing status | version 36.1 |
POST_PROMOTED_NOTIFICATIONS | Required to post promoted notifications, in addition to POST_NOTIFICATIONS | version 36.1 |
Notification.MetricStyle | Shows up to 3 metrics when expanded | API level 37 |
NotificationCompat.Builder.setRequestPromotedOngoing() | The Jetpack equivalent | androidx.core 1.17.0 |
Google's SDK setup pages put Android 16 at compileSdk 36 and Android 17 at 37.
MetricStyle is the workout template#
ProgressStyle is built for a tracker moving toward a destination; Google's examples are a car on its way, food being delivered and a navigation journey. A run with no fixed end does not fit that shape. MetricStyle does: Google's reference describes it as a style that shows up to 3 metrics when expanded, where metrics usually represent quantities that change over time, "such as fitness information collected by a tracker, timers, weather information."
What the reference specifies:
- A
MetricStylemust contain at least oneMetric, or the style is rejected when the notification is built. - When the notification is promoted, one of its metrics might be shown in the status bar chip, and
setCriticalMetric(index)tells the system which one is most important. - The style does not display the large icon.
- A
Metricis a value plus a label. Value types includeFixedIntandFixedFloatwith an optional unit,FixedText,FixedDate,FixedTime, andTimeDifference, which represents a timer, a stopwatch or a countdown. TimeDifference.forStopwatchtakes a start time in theSystemClock.elapsedRealtime()time base, or anInstant, plus a format;forPausedStopwatchtakes the elapsedDurationfor a paused session.
One inconsistency to know about: the class-level sample on Google's MetricStyle page passes a FORMAT_CHRONOMETER_AUTOMATIC constant, but the forStopwatch reference lists only FORMAT_ADAPTIVE and FORMAT_CHRONOMETER as valid values. Use the listed constants.
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.POST_PROMOTED_NOTIFICATIONS" />
// MetricStyle and Notification.Metric are API level 37. Below that, post a
// standard-style ongoing notification instead.
fun buildWorkoutNotification(
context: Context,
startElapsedRealtime: Long,
distanceKm: Float,
heartRate: Int?,
): Notification {
val builder = Notification.Builder(context, WORKOUT_CHANNEL_ID)
.setSmallIcon(R.drawable.ic_workout)
.setContentTitle("Outdoor run")
.setOngoing(true)
if (Build.VERSION.SDK_INT >= 37) {
val heartRateValue =
if (heartRate != null) Notification.Metric.FixedInt(heartRate, "bpm")
else Notification.Metric.FixedText("--")
builder
.setStyle(
Notification.MetricStyle()
.addMetric(
Notification.Metric(
Notification.Metric.TimeDifference.forStopwatch(
startElapsedRealtime,
Notification.Metric.TimeDifference.FORMAT_CHRONOMETER,
),
"Time",
)
)
.addMetric(
Notification.Metric(Notification.Metric.FixedFloat(distanceKm, "km"), "Distance")
)
.addMetric(Notification.Metric(heartRateValue, "Heart rate"))
.setCriticalMetric(0) // elapsed time is the chip candidate
)
.setRequestPromotedOngoing(true)
}
return builder.build()
}
The stopwatch value keeps counting on its own, so you do not need to repost every second; repost when distance or heart rate changes, at a cadence a person can read. Showing a placeholder when the sensor drops follows Google's own UX advice not to show an empty state.
The status chip#
Google's guide describes the chip as always including an icon and optionally text, with a maximum width of 96dp. Text under 7 characters is shown whole; for longer text the system decides how much fits, and shows the icon alone if less than half would. setShortCriticalText takes the highest precedence for the chip, with a suggested maximum of 7 characters and no guarantee of how much is shown. Alternatively, the guide says a timer appears in the chip when the notification's when time uses a chronometer, through setUsesChronometer. For a workout, elapsed time is the natural chip content either way.
Check before you rely on it#
Google documents three checks. hasPromotableCharacteristics() tells you whether the notification itself is eligible, and its reference is explicit that it does not consider user preferences. canPostPromotedNotifications() tells you whether the app can post promoted notifications at all, for example whether the user turned the feature off. FLAG_PROMOTED_ONGOING is what the system sets on a notification it actually promoted.
To send users to the setting, the NotificationManager and Settings references name Settings.ACTION_APP_NOTIFICATION_PROMOTION_SETTINGS. The Live Updates guide, last updated on 1 October 2026, names a different constant, ACTION_MANAGE_APP_PROMOTED_NOTIFICATIONS, which we did not find in the Settings reference. Build against the reference for your compile SDK.
Dismissal and lifecycle#
Google's guidance is direct: posting unwanted Live Updates can lead users to revoke the app's posting permission, and you should not repost a Live Update the user dismissed. Use setDeleteIntent to detect the dismissal and record it against the session, so the next distance update does not bring the card back.
The rest of the lifecycle is the same as on the watch. Tie the notification to the session object rather than to a screen, end it on every terminal path including an abandoned session, and make sure an app update mid-session does not orphan it. Wear OS ongoing activity walks through those cases, and Google notes that Live Updates are bridged to some connected Wear OS devices, so the phone notification may also show up on the wrist. The notification is presentation only; the numbers in it come from whatever owns the session in your app, and on the watch that is Health Services exercise tracking.
Every requirement, method and API level above is taken from Google's Live Updates guide and the Android and Jetpack reference pages as of this page's review date. This part of the platform is new and still moving, so check each symbol against the reference for your target SDK.
Frequently asked questions
- Does an Android workout Live Update need POST_PROMOTED_NOTIFICATIONS as well as POST_NOTIFICATIONS?
- Yes. Google's Live Updates guide lists declaring the non-runtime permission android.permission.POST_PROMOTED_NOTIFICATIONS in the manifest as a requirement, and Google's Manifest.permission reference says that permission is required in addition to, not instead of, POST_NOTIFICATIONS. The reference labels it as added in version 36.1. The practical consequence is that a user who denied the ordinary notification permission cannot see your workout Live Update either, so the in-app workout screen has to stand on its own.
- How many metrics can an Android MetricStyle workout notification show?
- Up to three when expanded, according to Google's MetricStyle reference, which describes metrics as quantities that change over time such as fitness information collected by a tracker, timers or weather. The style must contain at least one metric or it is rejected when the notification is built. When the notification is promoted, one metric might be shown in the status bar chip, and setCriticalMetric tells the system which one is most important. Each metric is a value and a label, and the value can be a fixed number with a unit, text, a date, a time, or a running or paused stopwatch.
- Why is my ongoing workout notification not being promoted to a Live Update?
- Check it against Google's list: an allowed style, a promotion request through setRequestPromotedOngoing, the ongoing flag, a content title, no custom RemoteViews, not a group summary, not colorized, a channel above IMPORTANCE_MIN, and the POST_PROMOTED_NOTIFICATIONS permission. Then call hasPromotableCharacteristics, which reports eligibility but ignores user preferences, and canPostPromotedNotifications, which reflects whether the user allows promotion for the app. Google also says device manufacturers can enforce additional criteria, and users can demote a Live Update to a standard notification, so a correct notification may still appear unpromoted.
- Should a fitness app use a Live Update for a workout summary or a reminder to train?
- No. Google's usage criteria say a Live Update must represent an activity actively in progress, with a distinct start and end, and that an activity in the past should use a standard notification, which covers a post-workout summary. Google lists alerts, upcoming calendar events and quick access to app features as inappropriate uses, which covers training reminders, and says not to let activities triggered by other parties generate Live Updates. The workout itself qualifies: Google names starting a workout as an example of the user-initiated activity Live Updates are meant to represent.
Keep reading
Elsewhere on the site
Pages that share this one’s concepts and sources, from other sections.
Next steps
Was this page useful?
Independent comparison, last reviewed October 3, 2026. Pricing, rate limits, and feature availability change often — confirm current details in each provider’s official documentation before you commit. Product and company names are trademarks of their respective owners; AIFitnessAPI is not affiliated with, endorsed by, or sponsored by any product listed here.
← All engagement & retention · by AIFitnessAPI