- Overview
- Prerequisites
- Project Setup
- Manifest Configuration
- Notification Service Implementation
- Samsung-Specific Extras
- UI Integration
- Testing & Debugging
- Best Practices
- Troubleshooting
- API Reference
Samsung Live Notifications and Now Bar are enhanced notification features available in Samsung One UI 7+ that provide:
- Live Notifications: Enhanced notifications displayed in a separate section of the notification drawer
- Now Bar: Interactive notifications shown on the lock screen
- Custom Styling: Chips, progress indicators, and custom colors
- Rich Content: Primary/secondary text, icons, and progress tracking
- Real-time progress updates
- Custom chip styling with colors and icons
- Notification actions (pause, stop, etc.)
- Lock screen integration (Now Bar)
- Segmented progress indicators
- Custom notification layouts
- Android Studio: Arctic Fox or later
- Android SDK: API 26+ (minimum), API 34+ (recommended)
- Java/Kotlin: Java 8+ or Kotlin 1.8+
- Samsung Device: One UI 7+ for testing (optional but recommended)
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" /># Using Android Studio or command line
android create project \
--target android-34 \
--name SamsungLiveNotifications \
--path ./samsung-live-notifications \
--activity MainActivity \
--package com.example.samsunglivenotificationsandroid {
compileSdk 34
defaultConfig {
applicationId "com.example.samsunglivenotifications"
minSdk 26
targetSdk 34
versionCode 1
versionName "1.0"
}
buildFeatures {
viewBinding true
}
}
dependencies {
implementation 'androidx.core:core-ktx:1.10.1'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.9.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.lifecycle:lifecycle-service:2.7.0'
}<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<!-- Required Permissions -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.SamsungLiveNotifications"
tools:targetApi="31">
<!-- CRITICAL: Samsung Live Notifications Metadata -->
<meta-data
android:name="com.samsung.android.support.ongoing_activity"
android:value="true" />
<!-- Main Activity -->
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- Foreground Service for Live Notifications -->
<service
android:name=".LiveNotificationService"
android:enabled="true"
android:exported="false"
android:foregroundServiceType="specialUse">
<property
android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
android:value="Samsung Live Notifications Demo" />
</service>
</application>
</manifest><meta-data
android:name="com.samsung.android.support.ongoing_activity"
android:value="true" />This metadata tells Samsung's system that your app supports ongoing activities and Live Notifications.
<service
android:name=".LiveNotificationService"
android:foregroundServiceType="specialUse">
<property
android:name="android.app.PROPERTY_SPECIAL_USE_FGS_SUBTYPE"
android:value="Samsung Live Notifications Demo" />
</service>package com.example.samsunglivenotifications
import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.Service
import android.content.Context
import android.content.Intent
import android.graphics.drawable.Icon
import android.os.Build
import android.os.Bundle
import android.os.IBinder
import androidx.core.app.NotificationCompat
import androidx.core.os.bundleOf
import java.util.Timer
import java.util.TimerTask
class LiveNotificationService : Service() {
companion object {
const val ACTION_START = "ACTION_START"
const val ACTION_STOP = "ACTION_STOP"
const val ACTION_PAUSE = "ACTION_PAUSE"
private const val NOTIFICATION_ID = 1001
private const val CHANNEL_ID = "live_notifications_channel"
private const val REQUEST_CODE_PAUSE = 100
private const val REQUEST_CODE_STOP = 101
private const val REQUEST_CODE_MAIN = 102
}
private var notificationManager: NotificationManager? = null
private var timer: Timer? = null
private var progress = 0
private var isPaused = false
override fun onCreate() {
super.onCreate()
notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
createNotificationChannel()
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
when (intent?.action) {
ACTION_START -> startLiveNotification()
ACTION_PAUSE -> togglePause()
ACTION_STOP -> stopLiveNotification()
}
return START_STICKY
}
override fun onBind(intent: Intent?): IBinder? = null
private fun createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
CHANNEL_ID,
"Live Notifications Channel",
NotificationManager.IMPORTANCE_LOW
).apply {
description = "Channel for Samsung Live Notifications demo"
setShowBadge(false)
}
notificationManager?.createNotificationChannel(channel)
}
}
private fun startLiveNotification() {
startForeground(NOTIFICATION_ID, createLiveNotification())
startProgressTimer()
}
private fun stopLiveNotification() {
timer?.cancel()
timer = null
stopForeground(STOP_FOREGROUND_REMOVE)
stopSelf()
}
private fun togglePause() {
isPaused = !isPaused
updateNotification()
}
private fun startProgressTimer() {
timer?.cancel()
timer = Timer()
timer?.scheduleAtFixedRate(object : TimerTask() {
override fun run() {
if (!isPaused) {
progress = (progress + 1) % 101
updateNotification()
}
}
}, 0, 1000) // Update every second
}
private fun updateNotification() {
notificationManager?.notify(NOTIFICATION_ID, createLiveNotification())
}
private fun createLiveNotification(): Notification {
// Create pending intents for actions
val pauseIntent = Intent(this, LiveNotificationService::class.java).apply {
action = ACTION_PAUSE
}
val pausePendingIntent = PendingIntent.getService(
this, REQUEST_CODE_PAUSE, pauseIntent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
val stopIntent = Intent(this, LiveNotificationService::class.java).apply {
action = ACTION_STOP
}
val stopPendingIntent = PendingIntent.getService(
this, REQUEST_CODE_STOP, stopIntent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
val mainIntent = Intent(this, MainActivity::class.java)
val mainPendingIntent = PendingIntent.getActivity(
this, REQUEST_CODE_MAIN, mainIntent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
// Create Samsung Live Notifications extras bundle
val extras = createSamsungLiveNotificationExtras()
return NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Live Notification Demo")
.setContentText("Samsung Live Notifications Active")
.setSmallIcon(R.drawable.ic_notification)
.setContentIntent(mainPendingIntent)
.setOngoing(true)
.setAutoCancel(false)
.addAction(
R.drawable.ic_pause,
if (isPaused) "Resume" else "Pause",
pausePendingIntent
)
.addAction(
R.drawable.ic_stop,
"Stop",
stopPendingIntent
)
.setExtras(extras)
.build()
}
private fun createSamsungLiveNotificationExtras(): Bundle {
return bundleOf(
// REQUIRED: Enable Samsung Live Notifications
"android.ongoingActivityNoti.style" to 1,
// Standard Style Configuration
"android.ongoingActivityNoti.primaryInfo" to "Demo App",
"android.ongoingActivityNoti.secondaryInfo" to if (isPaused) "Paused" else "Running",
"android.ongoingActivityNoti.secondaryInfoIcon" to Icon.createWithResource(this, R.drawable.ic_celebration),
// Chip Configuration
"android.ongoingActivityNoti.chipBgColor" to getColor(R.color.chip_background),
"android.ongoingActivityNoti.chipIcon" to Icon.createWithResource(this, R.drawable.ic_chip_location),
"android.ongoingActivityNoti.chipExpandedText" to "Live Demo",
// Progress Configuration
"android.ongoingActivityNoti.progress" to progress,
"android.ongoingActivityNoti.progressMax" to 100,
"android.ongoingActivityNoti.progressSegments.icon" to Icon.createWithResource(this, R.drawable.ic_notification),
"android.ongoingActivityNoti.progressSegments.progressColor" to getColor(R.color.progress_current),
"android.ongoingActivityNoti.progressSegments" to arrayOf(
bundleOf(
"android.ongoingActivityNoti.progressSegments.segmentStart" to 0.0f,
"android.ongoingActivityNoti.progressSegments.segmentColor" to getColor(R.color.progress_segment_1)
),
bundleOf(
"android.ongoingActivityNoti.progressSegments.segmentStart" to 50.0f,
"android.ongoingActivityNoti.progressSegments.segmentColor" to getColor(R.color.progress_segment_2)
)
),
// Action Configuration for Live Notifications
"android.ongoingActivityNoti.actionType" to 1,
"android.ongoingActivityNoti.actionPrimarySet" to 0,
// Now Bar Configuration (Lock Screen)
"android.ongoingActivityNoti.nowbarPrimaryInfo" to "Demo",
"android.ongoingActivityNoti.nowbarSecondaryInfo" to if (isPaused) "Paused" else "Active"
)
}
}"android.ongoingActivityNoti.style" to 1This is the most important extra - it enables Samsung Live Notifications.
// Primary text displayed prominently
"android.ongoingActivityNoti.primaryInfo" to "Your App Name"
// Secondary text with optional icon
"android.ongoingActivityNoti.secondaryInfo" to "Status Text"
"android.ongoingActivityNoti.secondaryInfoIcon" to Icon.createWithResource(context, R.drawable.icon)// Chip background color
"android.ongoingActivityNoti.chipBgColor" to Color.parseColor("#FF6B35")
// Chip icon
"android.ongoingActivityNoti.chipIcon" to Icon.createWithResource(context, R.drawable.chip_icon)
// Text shown when chip is expanded
"android.ongoingActivityNoti.chipExpandedText" to "Expanded Text"// Current progress value
"android.ongoingActivityNoti.progress" to currentProgress
// Maximum progress value
"android.ongoingActivityNoti.progressMax" to 100
// Progress bar icon
"android.ongoingActivityNoti.progressSegments.icon" to Icon.createWithResource(context, R.drawable.progress_icon)
// Current progress color
"android.ongoingActivityNoti.progressSegments.progressColor" to Color.parseColor("#4CAF50")
// Progress segments with different colors
"android.ongoingActivityNoti.progressSegments" to arrayOf(
bundleOf(
"android.ongoingActivityNoti.progressSegments.segmentStart" to 0.0f,
"android.ongoingActivityNoti.progressSegments.segmentColor" to Color.parseColor("#FF9800")
),
bundleOf(
"android.ongoingActivityNoti.progressSegments.segmentStart" to 50.0f,
"android.ongoingActivityNoti.progressSegments.segmentColor" to Color.parseColor("#4CAF50")
)
)// Action type for Live Notifications
"android.ongoingActivityNoti.actionType" to 1
// Primary action set
"android.ongoingActivityNoti.actionPrimarySet" to 0// Primary text for Now Bar (shorter than main notification)
"android.ongoingActivityNoti.nowbarPrimaryInfo" to "App"
// Secondary text for Now Bar
"android.ongoingActivityNoti.nowbarSecondaryInfo" to "Status"private fun createCompleteSamsungExtras(): Bundle {
return bundleOf(
// === CORE CONFIGURATION ===
"android.ongoingActivityNoti.style" to 1, // REQUIRED: Enable Live Notifications
// === STANDARD STYLE ===
"android.ongoingActivityNoti.primaryInfo" to "Primary Text",
"android.ongoingActivityNoti.secondaryInfo" to "Secondary Text",
"android.ongoingActivityNoti.secondaryInfoIcon" to Icon.createWithResource(this, R.drawable.secondary_icon),
// === CHIP STYLING ===
"android.ongoingActivityNoti.chipBgColor" to Color.parseColor("#FF6B35"),
"android.ongoingActivityNoti.chipIcon" to Icon.createWithResource(this, R.drawable.chip_icon),
"android.ongoingActivityNoti.chipExpandedText" to "Expanded Chip Text",
// === PROGRESS INDICATORS ===
"android.ongoingActivityNoti.progress" to progress,
"android.ongoingActivityNoti.progressMax" to 100,
"android.ongoingActivityNoti.progressSegments.icon" to Icon.createWithResource(this, R.drawable.progress_icon),
"android.ongoingActivityNoti.progressSegments.progressColor" to Color.parseColor("#4CAF50"),
"android.ongoingActivityNoti.progressSegments" to arrayOf(
bundleOf(
"android.ongoingActivityNoti.progressSegments.segmentStart" to 0.0f,
"android.ongoingActivityNoti.progressSegments.segmentColor" to Color.parseColor("#FF9800")
),
bundleOf(
"android.ongoingActivityNoti.progressSegments.segmentStart" to 33.0f,
"android.ongoingActivityNoti.progressSegments.segmentColor" to Color.parseColor("#FFC107")
),
bundleOf(
"android.ongoingActivityNoti.progressSegments.segmentStart" to 66.0f,
"android.ongoingActivityNoti.progressSegments.segmentColor" to Color.parseColor("#4CAF50")
)
),
// === ACTION CONFIGURATION ===
"android.ongoingActivityNoti.actionType" to 1,
"android.ongoingActivityNoti.actionPrimarySet" to 0,
// === NOW BAR (LOCK SCREEN) ===
"android.ongoingActivityNoti.nowbarPrimaryInfo" to "Lock Screen Primary",
"android.ongoingActivityNoti.nowbarSecondaryInfo" to "Lock Screen Secondary"
)
}package com.example.samsunglivenotifications
import android.Manifest
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import com.example.samsunglivenotifications.databinding.ActivityMainBinding
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private var isServiceRunning = false
private val requestPermissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestPermission()
) { isGranted: Boolean ->
if (isGranted) {
startLiveNotificationService()
} else {
Toast.makeText(this, "Notification permission is required", Toast.LENGTH_SHORT).show()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
setupClickListeners()
updateUI()
}
private fun setupClickListeners() {
binding.startButton.setOnClickListener {
if (checkNotificationPermission()) {
startLiveNotificationService()
} else {
requestNotificationPermission()
}
}
binding.stopButton.setOnClickListener {
stopLiveNotificationService()
}
}
private fun checkNotificationPermission(): Boolean {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
ContextCompat.checkSelfPermission(
this,
Manifest.permission.POST_NOTIFICATIONS
) == PackageManager.PERMISSION_GRANTED
} else {
true
}
}
private fun requestNotificationPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
}
}
private fun startLiveNotificationService() {
val serviceIntent = Intent(this, LiveNotificationService::class.java)
serviceIntent.action = LiveNotificationService.ACTION_START
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(serviceIntent)
} else {
startService(serviceIntent)
}
isServiceRunning = true
updateUI()
Toast.makeText(this, "Live Notification started", Toast.LENGTH_SHORT).show()
}
private fun stopLiveNotificationService() {
val serviceIntent = Intent(this, LiveNotificationService::class.java)
serviceIntent.action = LiveNotificationService.ACTION_STOP
startService(serviceIntent)
isServiceRunning = false
updateUI()
Toast.makeText(this, "Live Notification stopped", Toast.LENGTH_SHORT).show()
}
private fun updateUI() {
binding.startButton.isEnabled = !isServiceRunning
binding.stopButton.isEnabled = isServiceRunning
binding.statusText.text = if (isServiceRunning) {
"Status: Running - Check notification drawer and lock screen"
} else {
"Status: Stopped"
}
}
}<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp"
tools:context=".MainActivity">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Samsung Live Notifications Demo"
android:textSize="24sp"
android:textStyle="bold"
android:gravity="center"
android:layout_marginBottom="32dp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="This app demonstrates Samsung's Live Notifications and Now Bar features available in One UI 7."
android:textSize="16sp"
android:gravity="center"
android:layout_marginBottom="32dp" />
<Button
android:id="@+id/startButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Start Live Notification"
android:textSize="18sp"
android:layout_marginBottom="16dp" />
<Button
android:id="@+id/stopButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Stop Live Notification"
android:textSize="18sp"
android:enabled="false" />
<TextView
android:id="@+id/statusText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Status: Stopped"
android:textSize="16sp"
android:gravity="center"
android:layout_marginTop="32dp" />
</LinearLayout>- ✅ Live Notifications appear in separate section
- ✅ Now Bar shows on lock screen
- ✅ Custom chip styling visible
- ✅ Progress indicators work
- ✅ Enhanced notification layout
- ❌ Live Notifications fallback to standard notifications
- ❌ Now Bar not available
- ❌ Custom styling not applied
- ✅ Basic notification functionality works
- ❌ Samsung-specific features not available
- ✅ Standard Android notifications work
- ✅ Foreground service functions normally
private fun logSamsungExtras(extras: Bundle) {
Log.d("SamsungLiveNotif", "=== Samsung Live Notification Extras ===")
for (key in extras.keySet()) {
val value = extras.get(key)
Log.d("SamsungLiveNotif", "$key: $value")
}
Log.d("SamsungLiveNotif", "==========================================")
}private fun debugNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = notificationManager?.getNotificationChannel(CHANNEL_ID)
Log.d("SamsungLiveNotif", "Channel importance: ${channel?.importance}")
Log.d("SamsungLiveNotif", "Channel can show badge: ${channel?.canShowBadge()}")
}
}private fun checkSamsungMetadata() {
try {
val appInfo = packageManager.getApplicationInfo(packageName, PackageManager.GET_META_DATA)
val metaData = appInfo.metaData
val samsungSupport = metaData?.getBoolean("com.samsung.android.support.ongoing_activity", false)
Log.d("SamsungLiveNotif", "Samsung ongoing activity support: $samsungSupport")
} catch (e: Exception) {
Log.e("SamsungLiveNotif", "Error checking metadata", e)
}
}Solution:
- Verify Samsung metadata in manifest
- Check if app is whitelisted by Samsung
- Ensure
android.ongoingActivityNoti.styleis set to 1
Solution:
- Call
notificationManager.notify()with same ID - Ensure progress values are within valid range
- Check timer/update mechanism
Solution:
- Verify PendingIntent flags (use FLAG_IMMUTABLE)
- Check service action handling
- Ensure unique request codes
// Update only when necessary
private var lastProgress = -1
private fun updateNotificationIfNeeded(newProgress: Int) {
if (newProgress != lastProgress) {
lastProgress = newProgress
updateNotification()
}
}// Avoid too frequent updates
private val updateHandler = Handler(Looper.getMainLooper())
private var pendingUpdate = false
private fun scheduleUpdate() {
if (!pendingUpdate) {
pendingUpdate = true
updateHandler.postDelayed({
updateNotification()
pendingUpdate = false
}, 500) // Update at most every 500ms
}
}override fun onDestroy() {
timer?.cancel()
timer = null
super.onDestroy()
}// Use vector drawables when possible
"android.ongoingActivityNoti.chipIcon" to Icon.createWithResource(this, R.drawable.ic_vector_icon)
// For bitmap icons, ensure proper sizing
private fun createOptimizedIcon(resourceId: Int): Icon {
val bitmap = BitmapFactory.decodeResource(resources, resourceId)
val scaledBitmap = Bitmap.createScaledBitmap(bitmap, 64, 64, true)
return Icon.createWithBitmap(scaledBitmap)
}// Show meaningful progress information
"android.ongoingActivityNoti.secondaryInfo" to when {
progress < 25 -> "Starting..."
progress < 50 -> "In Progress..."
progress < 75 -> "Almost Done..."
progress < 100 -> "Finishing..."
else -> "Complete!"
}// Use colors that match your app theme
private fun getProgressColor(progress: Int): Int {
return when {
progress < 30 -> Color.parseColor("#FF5722") // Red for low progress
progress < 70 -> Color.parseColor("#FF9800") // Orange for medium
else -> Color.parseColor("#4CAF50") // Green for high progress
}
}Symptoms: Notifications show as regular Android notifications Causes:
- Missing Samsung metadata in manifest
- App not whitelisted by Samsung
- Incorrect extras bundle configuration
- Not running on Samsung One UI 7+ device
Solutions:
// Verify metadata exists
private fun verifySamsungSupport(): Boolean {
try {
val appInfo = packageManager.getApplicationInfo(packageName, PackageManager.GET_META_DATA)
return appInfo.metaData?.getBoolean("com.samsung.android.support.ongoing_activity", false) == true
} catch (e: Exception) {
return false
}
}
// Check if running on Samsung device
private fun isSamsungDevice(): Boolean {
return Build.MANUFACTURER.equals("samsung", ignoreCase = true)
}
// Verify One UI version (if possible)
private fun checkOneUIVersion(): String? {
return try {
val version = Build.VERSION.RELEASE
// Additional Samsung-specific version checking if needed
version
} catch (e: Exception) {
null
}
}Symptoms: Progress bar stuck or not visible Solutions:
// Ensure proper progress range
private fun updateProgress(newProgress: Int) {
val clampedProgress = newProgress.coerceIn(0, 100)
val extras = bundleOf(
"android.ongoingActivityNoti.style" to 1,
"android.ongoingActivityNoti.progress" to clampedProgress,
"android.ongoingActivityNoti.progressMax" to 100,
// ... other extras
)
// Update notification
val notification = NotificationCompat.Builder(this, CHANNEL_ID)
.setExtras(extras)
.build()
notificationManager?.notify(NOTIFICATION_ID, notification)
}Symptoms: Notification buttons don't work Solutions:
// Use proper PendingIntent flags
private fun createActionPendingIntent(action: String): PendingIntent {
val intent = Intent(this, LiveNotificationService::class.java).apply {
this.action = action
}
return PendingIntent.getService(
this,
action.hashCode(), // Unique request code
intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
}Symptoms: Notification disappears, service killed Solutions:
// Use START_STICKY for service restart
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
// Handle intent
return START_STICKY // Service will be restarted if killed
}
// Handle low memory situations
override fun onLowMemory() {
super.onLowMemory()
// Reduce memory usage, pause non-essential updates
}
// Proper foreground service handling
private fun ensureForegroundService() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForeground(NOTIFICATION_ID, createLiveNotification())
}
}- Samsung metadata present in AndroidManifest.xml
- Required permissions declared and granted
- Foreground service properly configured
- Samsung-specific extras bundle correctly formatted
- Notification channel created with appropriate importance
- PendingIntents use FLAG_IMMUTABLE
- Progress values within valid range (0-100)
- Icons exist and are accessible
- Service handles all required actions
- Testing on Samsung One UI 7+ device
| Extra Key | Type | Required | Description |
|---|---|---|---|
android.ongoingActivityNoti.style |
int | ✅ | Must be 1 to enable Live Notifications |
android.ongoingActivityNoti.primaryInfo |
String | ❌ | Primary text displayed prominently |
android.ongoingActivityNoti.secondaryInfo |
String | ❌ | Secondary text with optional icon |
android.ongoingActivityNoti.secondaryInfoIcon |
Icon | ❌ | Icon for secondary information |
android.ongoingActivityNoti.chipBgColor |
int | ❌ | Background color for chip |
android.ongoingActivityNoti.chipIcon |
Icon | ❌ | Icon displayed in chip |
android.ongoingActivityNoti.chipExpandedText |
String | ❌ | Text shown when chip is expanded |
android.ongoingActivityNoti.progress |
int | ❌ | Current progress value |
android.ongoingActivityNoti.progressMax |
int | ❌ | Maximum progress value |
android.ongoingActivityNoti.progressSegments.icon |
Icon | ❌ | Icon for progress bar |
android.ongoingActivityNoti.progressSegments.progressColor |
int | ❌ | Color of current progress |
android.ongoingActivityNoti.progressSegments |
Array | ❌ | Progress segments with colors |
android.ongoingActivityNoti.actionType |
int | ❌ | Action type for Live Notifications |
android.ongoingActivityNoti.actionPrimarySet |
int | ❌ | Primary action set identifier |
android.ongoingActivityNoti.nowbarPrimaryInfo |
String | ❌ | Primary text for Now Bar (lock screen) |
android.ongoingActivityNoti.nowbarSecondaryInfo |
String | ❌ | Secondary text for Now Bar |
bundleOf(
"android.ongoingActivityNoti.progressSegments.segmentStart" to 0.0f, // Start percentage (0.0-100.0)
"android.ongoingActivityNoti.progressSegments.segmentColor" to Color.parseColor("#FF9800") // Segment color
)| Action | Description |
|---|---|
ACTION_START |
Start the Live Notification service |
ACTION_STOP |
Stop the Live Notification service |
ACTION_PAUSE |
Pause/Resume the notification |
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" /><meta-data
android:name="com.samsung.android.support.ongoing_activity"
android:value="true" />Samsung Live Notifications provide a powerful way to create enhanced notification experiences on Samsung devices. While currently requiring Samsung's whitelist approval, these features will become available to all developers with Android 16.
Key takeaways:
- Always include the required Samsung metadata
- Use
android.ongoingActivityNoti.style = 1to enable Live Notifications - Test on Samsung One UI 7+ devices for full functionality
- Implement proper fallbacks for non-Samsung devices
- Follow Android foreground service best practices
For the most up-to-date information, refer to Samsung's official developer documentation and the Android 16 Live Updates API when it becomes available.