Skip to content

Commit cb0c0ce

Browse files
committed
android: cross-OEM Live Update support with promoted notification, icon scaling, and BLE early fire
1 parent 2706a53 commit cb0c0ce

4 files changed

Lines changed: 69 additions & 16 deletions

File tree

android/app/src/main/AndroidManifest.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE" />
1313
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
1414
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
15+
<uses-permission
16+
android:name="android.permission.POST_PROMOTED_NOTIFICATIONS"
17+
tools:ignore="ProtectedPermissions" />
1518
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
1619
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
1720
<uses-permission
@@ -55,6 +58,11 @@
5558
android:theme="@style/Theme.LibrePods"
5659
android:description="@string/app_description"
5760
tools:ignore="UnusedAttribute" >
61+
62+
<meta-data
63+
android:name="com.samsung.android.support.ongoing_activity"
64+
android:value="true" />
65+
5866
<receiver
5967
android:name=".presentation.widgets.NoiseControlWidget"
6068
android:exported="false">

android/app/src/main/java/me/kavishdevar/librepods/services/AirPodsService.kt

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,25 @@ class AirPodsService : Service(), SharedPreferences.OnSharedPreferenceChangeList
348348
caseCharging = caseCharging == true
349349
)
350350
updateBattery()
351+
352+
if (!wasConnectedForLive
353+
&& sharedPreferences.getBoolean("show_live_update_notification", true)
354+
) {
355+
val battery = batteryNotification.getBattery()
356+
val hasMeaningfulBattery = battery.any {
357+
it.status != BatteryStatus.DISCONNECTED && it.level > 0
358+
}
359+
if (hasMeaningfulBattery) {
360+
val name = sharedPreferences.getString("name", "AirPods Pro") ?: "AirPods"
361+
LiveUpdateNotification.show(
362+
this@AirPodsService.applicationContext,
363+
name,
364+
battery,
365+
headsUp = true
366+
)
367+
wasConnectedForLive = true
368+
}
369+
}
351370
Log.d(TAG, "Battery changed")
352371
}
353372

@@ -1682,13 +1701,19 @@ class AirPodsService : Service(), SharedPreferences.OnSharedPreferenceChangeList
16821701
) {
16831702
Log.d(TAG, "Showing island window")
16841703
if (sharedPreferences.getBoolean("show_live_update_notification", true)) {
1685-
val name = sharedPreferences.getString("name", "AirPods Pro") ?: "AirPods"
1686-
LiveUpdateNotification.show(
1687-
service.applicationContext,
1688-
name,
1689-
batteryNotification.getBattery(),
1690-
headsUp = true
1691-
)
1704+
val battery = batteryNotification.getBattery()
1705+
val hasMeaningfulBattery = battery.any {
1706+
it.status != BatteryStatus.DISCONNECTED && it.level > 0
1707+
}
1708+
if (hasMeaningfulBattery) {
1709+
val name = sharedPreferences.getString("name", "AirPods Pro") ?: "AirPods"
1710+
LiveUpdateNotification.show(
1711+
service.applicationContext,
1712+
name,
1713+
battery,
1714+
headsUp = true
1715+
)
1716+
}
16921717
}
16931718
if (!sharedPreferences.getBoolean("show_island_popup", true)) {
16941719
return
@@ -2064,10 +2089,13 @@ class AirPodsService : Service(), SharedPreferences.OnSharedPreferenceChangeList
20642089

20652090
if (connected && (config.bleOnlyMode || socket.isConnected)) {
20662091
if (liveEnabled && batteryList != null) {
2067-
if (!wasConnectedForLive) {
2092+
val hasMeaningfulBattery = batteryList.any {
2093+
it.status != BatteryStatus.DISCONNECTED && it.level > 0
2094+
}
2095+
if (!wasConnectedForLive && hasMeaningfulBattery) {
20682096
LiveUpdateNotification.show(this, resolvedName, batteryList, headsUp = true)
20692097
wasConnectedForLive = true
2070-
} else {
2098+
} else if (wasConnectedForLive) {
20712099
LiveUpdateNotification.update(this, resolvedName, batteryList)
20722100
}
20732101
LiveUpdateNotification.checkLowBattery(this, batteryList)

android/app/src/main/java/me/kavishdevar/librepods/services/notifications/LiveUpdateNotification.kt

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22

33
package me.kavishdevar.librepods.services.notifications
44

5+
import android.app.Notification
56
import android.app.NotificationChannel
67
import android.app.NotificationManager
78
import android.app.PendingIntent
89
import android.content.Context
910
import android.content.Intent
11+
import android.os.Bundle
1012
import androidx.core.app.NotificationCompat
11-
import androidx.core.graphics.drawable.IconCompat
1213
import me.kavishdevar.librepods.MainActivity
1314
import me.kavishdevar.librepods.R
1415
import me.kavishdevar.librepods.data.Battery
@@ -81,7 +82,7 @@ object LiveUpdateNotification {
8182
}
8283

8384
val notif = NotificationCompat.Builder(context, CHANNEL_ID)
84-
.setSmallIcon(R.drawable.airpods)
85+
.setSmallIcon(R.drawable.airpods_live_update_icon)
8586
.setContentTitle(context.getString(titleRes, battery.level))
8687
.setContentText(context.getString(R.string.live_update_low_battery_body))
8788
.setContentIntent(pi)
@@ -101,7 +102,7 @@ object LiveUpdateNotification {
101102

102103
val nm = context.getSystemService(NotificationManager::class.java)
103104
val notif = NotificationCompat.Builder(context, CHANNEL_ID)
104-
.setSmallIcon(R.drawable.airpods)
105+
.setSmallIcon(R.drawable.airpods_live_update_icon)
105106
.setContentTitle(context.getString(R.string.live_update_case_open_title))
106107
.setContentText(context.getString(R.string.live_update_case_open_body, caseBattery.level))
107108
.setContentIntent(mainActivityPendingIntent(context))
@@ -172,20 +173,24 @@ object LiveUpdateNotification {
172173

173174
val progressStyle = NotificationCompat.ProgressStyle()
174175
.setProgress(lowestEar)
175-
.setProgressTrackerIcon(
176-
IconCompat.createWithResource(context, R.drawable.airpods)
177-
)
176+
177+
val samsungLiveExtras = Bundle().apply {
178+
putInt("android.ongoingActivityNoti.style", 1)
179+
}
178180

179181
return NotificationCompat.Builder(context, CHANNEL_ID)
180-
.setSmallIcon(R.drawable.airpods)
182+
.setSmallIcon(R.drawable.airpods_live_update_icon)
181183
.setContentTitle(airpodsName)
182184
.setContentText(if (expandedBody.isNotEmpty()) expandedBody else "$lowestEar%")
185+
.setShortCriticalText("$lowestEar%")
183186
.setStyle(progressStyle)
184187
.setOngoing(true)
188+
.setCategory(Notification.CATEGORY_STATUS)
185189
.setContentIntent(mainActivityPendingIntent(context))
186190
.setPriority(if (headsUp) NotificationCompat.PRIORITY_HIGH else NotificationCompat.PRIORITY_DEFAULT)
187191
.setOnlyAlertOnce(!headsUp)
188192
.setRequestPromotedOngoing(true)
193+
.addExtras(samsungLiveExtras)
189194
}
190195

191196
private fun mainActivityPendingIntent(context: Context): PendingIntent {
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="48dp"
3+
android:height="48dp"
4+
android:viewportWidth="1061.6"
5+
android:viewportHeight="1061.6">
6+
7+
<group android:translateX="79.63" android:translateY="226.955">
8+
<path android:fillColor="#ffffff" android:pathData="M315.92,550.31C315.92,567.88 304.69,577.41 286.13,577.41L261.48,577.41C242.92,577.41 231.45,567.88 231.45,550.31L231.45,358.73C267.25,355.98 293.73,349.94 315.92,341.64ZM670.9,358.73L670.9,550.31C670.9,567.88 659.42,577.41 640.87,577.41L616.21,577.41C597.66,577.41 586.43,567.88 586.43,550.31L586.43,341.64C608.62,349.94 635.09,355.98 670.9,358.73Z"/>
9+
<path android:fillColor="#ffffff" android:pathData="M429.2,153.09C429.2,221.45 388.18,270.28 335.2,299.57C312.69,312 288.17,321.38 249.56,326.11C255.64,311.65 259.03,294.95 259.03,276.14C259.03,213.57 207.98,151 137.53,139.93C143.33,128.37 149.48,118.78 153.81,113.29C192.14,56.65 252.44,29.55 306.64,30.29C375.24,31.02 429.2,76.43 429.2,153.09ZM748.53,113.29C752.86,118.78 759.01,128.37 764.82,139.93C694.36,151 643.31,213.57 643.31,276.14C643.31,294.95 646.71,311.65 652.78,326.11C614.17,321.38 589.66,312 567.14,299.57C514.16,270.28 473.14,221.45 473.14,153.09C473.14,76.43 527.1,31.02 595.7,30.29C649.9,29.55 710.21,56.65 748.53,113.29ZM346.19,100.11L301.51,137.71C295.41,142.84 294.68,151.62 299.56,157.48C304.69,163.83 313.72,164.32 319.34,159.44L364.75,121.84C370.85,116.71 371.09,107.92 365.97,102.06C361.33,95.72 352.3,94.98 346.19,100.11ZM536.38,102.06C531.25,107.92 531.49,116.71 537.6,121.84L583.01,159.44C588.62,164.32 597.66,163.83 602.78,157.48C607.67,151.62 606.93,142.84 600.83,137.71L556.15,100.11C550.05,94.98 541.02,95.72 536.38,102.06Z"/>
10+
<path android:fillColor="#ffffff" android:pathData="M140.87,364.76C189.45,364.76 229.98,334.48 229.98,276.14C229.98,222.43 180.18,167.25 114.99,167.25C61.28,167.25 29.05,209.24 29.05,254.65C29.05,320.08 84.72,364.76 140.87,364.76ZM125.98,319.59C117.19,327.16 102.29,319.35 84.23,297.38C66.41,275.89 61.52,260.51 70.07,252.94C79.1,245.37 93.75,252.94 111.82,274.92C129.4,297.13 134.52,312.27 125.98,319.59ZM761.47,364.76C817.63,364.76 873.29,320.08 873.29,254.65C873.29,209.24 841.06,167.25 787.35,167.25C722.17,167.25 672.36,222.43 672.36,276.14C672.36,334.48 712.89,364.76 761.47,364.76ZM776.37,319.59C767.82,312.27 772.95,297.13 790.53,274.92C808.59,252.94 823.24,245.37 832.28,252.94C840.82,260.51 835.94,275.89 818.11,297.38C800.29,319.35 785.16,327.16 776.37,319.59Z"/>
11+
</group>
12+
</vector>

0 commit comments

Comments
 (0)