Skip to content

Progress bar customization - #6527

Draft
inukiwi wants to merge 11 commits into
home-assistant:mainfrom
inukiwi:progress_style_notifications
Draft

Progress bar customization#6527
inukiwi wants to merge 11 commits into
home-assistant:mainfrom
inukiwi:progress_style_notifications

Conversation

@inukiwi

@inukiwi inukiwi commented Mar 3, 2026

Copy link
Copy Markdown
Contributor

Summary

This feature adds support for progress bar customization on Android 16.0+ devices, as shown here.

Checklist

  • New or updated tests have been added to cover the changes following the testing guidelines.
  • The code follows the project's code style and best_practices.
  • The changes have been thoroughly tested, and edge cases have been considered.
  • Changes are backward compatible whenever feasible. Any breaking changes are documented in the changelog for users and/or in the code for developers depending on the relevance.

Screenshots

image

Link to pull request in documentation repositories

User Documentation: home-assistant/companion.home-assistant#1297

Any other notes

@inukiwi
inukiwi marked this pull request as ready for review March 6, 2026 11:59
Copilot AI review requested due to automatic review settings March 6, 2026 11:59

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds support for Android 16+ “progress-centric” notification customization in the Android Companion App notification pipeline, enabling richer progress rendering (segments/points and custom icons) when notifications are received from Home Assistant.

Changes:

  • Added parsing helper (parseFlattenedList) to interpret flattened list payloads (e.g., from WebSocket-flattened notification data)
  • Added Android 16+ NotificationCompat.ProgressStyle handling for segments, points, and tracker/start/end icons
  • Introduced new notification data keys for progress customization (progress_segments, progress_points, progress_*_icon, progress_*_color)

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
common/src/main/kotlin/io/homeassistant/companion/android/common/notifications/NotificationFunctions.kt Adds helper to parse flattened list strings into structured key/value maps for progress style inputs
app/src/main/kotlin/io/homeassistant/companion/android/notifications/MessagingManager.kt Applies Android 16+ progress-centric ProgressStyle based on new notification payload keys

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +1251 to +1256
sizeDp = 20
colorFilter = PorterDuffColorFilter(progressTrackerColor, PorterDuff.Mode.SRC_IN)
backgroundColorRes = accentColor
roundedCornersDp = 10
paddingDp = 4
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would like some docs about the choice of these magic numbers.

if (progressStartIcon.startsWith("mdi:") && progressStartIcon.substringAfter("mdi:").isNotBlank()) {
val iconName = progressStartIcon.split(":")[1]
val iconDrawable = IconicsDrawable(context, "cmd-$iconName").apply {
sizeDp = 20

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here or even a const

if (progressEndIcon.startsWith("mdi:") && progressEndIcon.substringAfter("mdi:").isNotBlank()) {
val iconName = progressEndIcon.split(":")[1]
val iconDrawable = IconicsDrawable(context, "cmd-$iconName").apply {
sizeDp = 20

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here or even a const

Comment on lines +1270 to +1271
if (progressStartIcon.startsWith("mdi:") && progressStartIcon.substringAfter("mdi:").isNotBlank()) {
val iconName = progressStartIcon.split(":")[1]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same and could actually be wrap into a small helper

Comment on lines +1289 to +1290
if (progressEndIcon.startsWith("mdi:") && progressEndIcon.substringAfter("mdi:").isNotBlank()) {
val iconName = progressEndIcon.split(":")[1]

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same

@github-advanced-security github-advanced-security AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ktlint found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.

@inukiwi
inukiwi marked this pull request as ready for review June 17, 2026 15:26
@inukiwi

inukiwi commented Jun 17, 2026

Copy link
Copy Markdown
Contributor Author

This also requires PR home-assistant/mobile-apps-fcm-push#317 to support objects in notification data

// Values for temporarily added keys
const val THIS_SERVER_ID = "server_id"

private val lenientJson = Json { isLenient = true }

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a one time thing, we should not make this available too broadly because whenever we want to parse a JSON we should use our existing instance kotlinJsonMapper

val segmentsData = data[PROGRESS_SEGMENTS] ?: ""
if (segmentsData.isNotBlank()) {
try {
val segments: List<Map<String, String>> = lenientJson.decodeFromString(segmentsData)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you try if it works with our current parser? I would really like to use it instead of this one. Where is the quote removed from the key that we have to do that? If it's from our code can we avoid this?

if (segments.isNotEmpty()) {
return true
}
} catch (e: kotlinx.serialization.SerializationException) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make an import and update all try/catch in the file

iconString: String,
iconColor: Int,
backgroundColor: Int? = null,
): androidx.core.graphics.drawable.IconCompat? {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same import

@TimoPtr
TimoPtr marked this pull request as draft June 29, 2026 11:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants