diff --git a/jami-android/app/src/main/java/cx/ring/client/LogsActivity.kt b/jami-android/app/src/main/java/cx/ring/client/LogsActivity.kt
index 6b2a650e61e2a71e63f16ed119dcd0baa2c2d188..1c9cbf4717d793367954bbf263b0dd3ce32a5273 100644
--- a/jami-android/app/src/main/java/cx/ring/client/LogsActivity.kt
+++ b/jami-android/app/src/main/java/cx/ring/client/LogsActivity.kt
@@ -16,9 +16,11 @@
  */
 package cx.ring.client
 
+import android.animation.ValueAnimator
 import android.app.ActivityManager
 import android.app.ApplicationExitInfo
 import android.content.Intent
+import android.graphics.Color
 import android.net.Uri
 import android.os.Build
 import android.os.Bundle
@@ -31,11 +33,12 @@ import android.view.ViewGroup
 import android.widget.TextView
 import androidx.activity.result.ActivityResultLauncher
 import androidx.activity.result.contract.ActivityResultContracts
+import androidx.annotation.ColorInt
 import androidx.appcompat.app.AppCompatActivity
 import androidx.core.content.ContextCompat
 import androidx.core.content.getSystemService
-import androidx.recyclerview.widget.LinearLayoutManager
 import androidx.recyclerview.widget.RecyclerView
+import androidx.recyclerview.widget.SimpleItemAnimator
 import com.google.android.material.bottomsheet.BottomSheetDialogFragment
 import com.google.android.material.snackbar.Snackbar
 import cx.ring.R
@@ -91,8 +94,16 @@ class LogsActivity : AppCompatActivity() {
         }
         binding.fab.setOnClickListener { if (disposable == null) startLogging() else stopLogging() }
 
-        binding.logRecyclerView.adapter = LogAdapter()
-        binding.logRecyclerView.layoutManager = LinearLayoutManager(this)
+        val highlightColor = getColor(R.color.colorSecondaryTranslucent)
+        val bgColor = getColor(R.color.transparent)
+
+        binding.logRecyclerView.apply {
+            setHasFixedSize(true)
+            itemAnimator = FadeInItemAnimator(highlightColor, bgColor)
+            adapter = LogAdapter(highlightColor, bgColor).apply {
+                stateRestorationPolicy = RecyclerView.Adapter.StateRestorationPolicy.PREVENT_WHEN_EMPTY
+            }
+        }
 
         // Check for previous crash reasons, if any.
         if (savedInstanceState == null)
@@ -260,7 +271,7 @@ class LogsActivity : AppCompatActivity() {
             .subscribe({ messages: List<String> ->
                 val adapter = binding.logRecyclerView.adapter as LogAdapter
                 adapter.addLogs(messages.map { LogMessage(it) })
-                binding.logRecyclerView.smoothScrollToPosition(adapter.itemCount - 1)
+                binding.logRecyclerView.scrollToPosition(adapter.itemCount - 1)
             }) { e -> Log.w(TAG, "Error in logger", e) }
             .apply { disposable = this })
         setButtonState(true)
@@ -291,42 +302,102 @@ class LogsActivity : AppCompatActivity() {
         super.onDestroy()
     }
 
-    companion object {
-        private val TAG = LogsActivity::class.simpleName!!
-    }
-}
+    data class LogMessage(val message: String)
 
-data class LogMessage(val message: String)
+    class FadeInItemAnimator(@ColorInt val highlightColor: Int, @ColorInt val bgColor: Int): SimpleItemAnimator() {
+        init {
+            supportsChangeAnimations = false
+            addDuration = 1000
+        }
 
-class LogAdapter :
-    RecyclerView.Adapter<LogAdapter.LogViewHolder>() {
+        override fun animateAdd(holder: RecyclerView.ViewHolder): Boolean {
+            val logHolder = holder as LogAdapter.LogViewHolder
+            val pos = holder.adapterPosition
+            Log.w(TAG, "animateAdd ${pos}")
+            val view = holder.itemView
+            view.setBackgroundColor(highlightColor)
+            logHolder.animation.setDuration(addDuration)
+            logHolder.animation.addUpdateListener { animation ->
+                view.setBackgroundColor(animation.getAnimatedValue() as Int)
+            }
+            logHolder.animation.start()
+            return false
+        }
 
-    private val logList = mutableListOf<LogMessage>()
+        override fun animateRemove(holder: RecyclerView.ViewHolder): Boolean {
+            //dispatchRemoveFinished(holder)
+            return false;
+        }
 
-    fun getLogs(): String = logList.joinToString(separator = "\n") { it.message }
+        override fun animateMove(holder: RecyclerView.ViewHolder, fromX: Int, fromY: Int, toX: Int, toY: Int): Boolean {
+            // Implement if you need move animations
+            //dispatchMoveFinished(holder)
+            return false;
+        }
 
-    class LogViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
-        val messageTextView: TextView = itemView.findViewById(R.id.log_item_text)
-    }
+        override fun animateChange(oldHolder: RecyclerView.ViewHolder, newHolder: RecyclerView.ViewHolder,
+                                   fromLeft: Int, fromTop: Int, toLeft: Int, toTop: Int): Boolean {
+            // Implement if you need change animations
+            return false;
+        }
 
-    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LogViewHolder =
-        LogViewHolder(
-            LayoutInflater.from(parent.context).inflate(R.layout.item_log, parent, false)
-        )
+        override fun runPendingAnimations() {
+            // No-op for this example
+        }
 
-    override fun onBindViewHolder(holder: LogViewHolder, position: Int) {
-        holder.messageTextView.text = logList[position].message
-    }
+        override fun endAnimation(item: RecyclerView.ViewHolder) {
+            Log.w(TAG, "endAnimation ${item.adapterPosition}")
+            val logHolder = item as LogAdapter.LogViewHolder
+            logHolder.animation.cancel()
+            item.itemView.setBackgroundColor(bgColor)
+            dispatchAnimationFinished(item)
+        }
 
-    override fun getItemCount(): Int = logList.size
+        override fun endAnimations() {
+            // No-op for this example
+        }
 
-    fun addLogs(logs: List<LogMessage>) {
-        logList.addAll(logs)
-        notifyItemRangeInserted(logList.size - logs.size, logs.size)
+        override fun isRunning(): Boolean {
+            return false; // Return true if animations are running
+        }
     }
 
-    fun clearLogs() {
-        logList.clear()
-        notifyDataSetChanged()
+    class LogAdapter(@ColorInt val highlightColor: Int, @ColorInt val bgColor: Int) :
+        RecyclerView.Adapter<LogAdapter.LogViewHolder>() {
+
+        private val logList = mutableListOf<LogMessage>()
+
+        fun getLogs(): String = logList.joinToString(separator = "\n") { it.message }
+
+        class LogViewHolder(itemView: View, @ColorInt highlightColor: Int, @ColorInt bgColor: Int) : RecyclerView.ViewHolder(itemView) {
+            val messageTextView: TextView = itemView.findViewById(R.id.log_item_text)
+            val animation: ValueAnimator = ValueAnimator.ofArgb(highlightColor, bgColor)
+        }
+
+        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LogViewHolder =
+            LogViewHolder(
+                LayoutInflater.from(parent.context).inflate(R.layout.item_log, parent, false),
+                highlightColor,
+                bgColor
+            )
+
+        override fun onBindViewHolder(holder: LogViewHolder, position: Int) {
+            holder.messageTextView.text = logList[position].message
+        }
+
+        override fun getItemCount(): Int = logList.size
+
+        fun addLogs(logs: List<LogMessage>) {
+            logList.addAll(logs)
+            notifyItemRangeInserted(logList.size - logs.size, logs.size)
+        }
+
+        fun clearLogs() {
+            logList.clear()
+            notifyDataSetChanged()
+        }
     }
-}
\ No newline at end of file
+    companion object {
+        private val TAG = LogsActivity::class.simpleName!!
+    }
+}
diff --git a/jami-android/app/src/main/java/cx/ring/client/PushNotificationLogsActivity.kt b/jami-android/app/src/main/java/cx/ring/client/PushNotificationLogsActivity.kt
index acbfe5077e36a9c4755ce5d596c59609a280cabe..2be4d0ed1a87d8a73a2f792ea619ee5fa164b768 100644
--- a/jami-android/app/src/main/java/cx/ring/client/PushNotificationLogsActivity.kt
+++ b/jami-android/app/src/main/java/cx/ring/client/PushNotificationLogsActivity.kt
@@ -30,6 +30,9 @@ import androidx.core.content.ContextCompat
 import androidx.recyclerview.widget.LinearLayoutManager
 import com.google.android.material.snackbar.Snackbar
 import cx.ring.R
+import cx.ring.client.LogsActivity.FadeInItemAnimator
+import cx.ring.client.LogsActivity.LogAdapter
+import cx.ring.client.LogsActivity.LogMessage
 import cx.ring.databinding.ActivityPushNotificationLogsBinding
 import cx.ring.utils.AndroidFileUtils
 import cx.ring.utils.ContentUri
@@ -52,8 +55,13 @@ class PushNotificationLogsActivity : AppCompatActivity() {
     private val compositeDisposable = CompositeDisposable()
     private var disposable: Disposable? = null
     private lateinit var logAdapter: LogAdapter
-    private lateinit var fileSaver: ActivityResultLauncher<String>
     private lateinit var logFile: File
+    private var fileSaver: ActivityResultLauncher<String> = registerForActivityResult(ActivityResultContracts
+        .CreateDocument("text/plain")) { result: Uri? ->
+        if (result != null) {
+            copyFileToUri(logFile, result)
+        }
+    }
 
     @Inject
     @Singleton
@@ -65,7 +73,10 @@ class PushNotificationLogsActivity : AppCompatActivity() {
         setContentView(binding.root)
         setSupportActionBar(binding.toolbar)
         supportActionBar?.setDisplayHomeAsUpEnabled(true)
-        logAdapter = LogAdapter()
+        val highlightColor = getColor(R.color.colorSecondaryTranslucent)
+        val bgColor = getColor(R.color.transparent)
+        logAdapter = LogAdapter(highlightColor, bgColor)
+        binding.logRecyclerView.itemAnimator = FadeInItemAnimator(highlightColor, bgColor)
         binding.logRecyclerView.adapter = logAdapter
         binding.logRecyclerView.layoutManager = LinearLayoutManager(this)
         val pushSummaryTextView = findViewById<TextView>(R.id.pushSummaryTextView)
@@ -81,15 +92,7 @@ class PushNotificationLogsActivity : AppCompatActivity() {
             if (disposable == null) startLogging() else stopLogging()
         }
 
-        fileSaver = registerForActivityResult(ActivityResultContracts
-            .CreateDocument("text/plain")) { result: Uri? ->
-            if (result != null) {
-                copyFileToUri(logFile, result)
-            }
-        }
-
         if (mHardwareService.loggingStatus) startLogging()
-
     }
 
     override fun onCreateOptionsMenu(menu: Menu): Boolean {
diff --git a/jami-android/app/src/main/res/layout/activity_logs.xml b/jami-android/app/src/main/res/layout/activity_logs.xml
index 319325a31571cc12a62d797b7edbd19a41cce84e..ec45f74f7b5d704d6a019068a8318a3d21dc619e 100644
--- a/jami-android/app/src/main/res/layout/activity_logs.xml
+++ b/jami-android/app/src/main/res/layout/activity_logs.xml
@@ -15,10 +15,8 @@
 
         <com.google.android.material.appbar.MaterialToolbar
             android:id="@+id/toolbar"
-            style="@style/Widget.Material3.Toolbar.Surface"
             android:layout_width="match_parent"
             android:layout_height="?attr/actionBarSize"
-            android:background="@color/background"
             tools:menu="@menu/logs_menu"
             tools:title="Logs" />
 
@@ -34,14 +32,19 @@
             android:id="@+id/log_recycler_view"
             android:layout_width="match_parent"
             android:layout_height="0dp"
-            android:layout_weight="1" />
+            android:layout_weight="1"
+            android:orientation="vertical"
+            app:stackFromEnd="true"
+            app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
+            tools:listitem="@layout/item_log"/>
 
         <com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
             android:id="@+id/fab"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_gravity="bottom|center_horizontal"
-            android:layout_margin="@dimen/fab_margin"
+            android:layout_marginTop="8dp"
+            android:layout_marginBottom="@dimen/fab_margin"
             android:gravity="center"
             android:text="@string/pref_logs_start"
             app:icon="@drawable/baseline_article_24" />
diff --git a/jami-android/app/src/main/res/layout/item_log.xml b/jami-android/app/src/main/res/layout/item_log.xml
index c08ce604ec318d4512fad26d4bb045df74804c53..7156c1b0c212218704886152a3165d69eae8572b 100644
--- a/jami-android/app/src/main/res/layout/item_log.xml
+++ b/jami-android/app/src/main/res/layout/item_log.xml
@@ -13,7 +13,6 @@ GNU General Public License for more details.
 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
 -->
-
 <TextView xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools"
     android:id="@+id/log_item_text"
@@ -22,6 +21,6 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
     android:breakStrategy="simple"
     android:hyphenationFrequency="none"
     android:paddingHorizontal="@dimen/padding_medium"
-    android:paddingTop="@dimen/padding_small"
+    android:paddingVertical="@dimen/padding_xsmall"
     android:textIsSelectable="true"
-    tools:text="@tools:sample/lorem/random" />
\ No newline at end of file
+    tools:text="@tools:sample/first_names"/>
\ No newline at end of file
diff --git a/jami-android/app/src/main/res/values-night/colors.xml b/jami-android/app/src/main/res/values-night/colors.xml
index 3a7545996c6f422289edfc3b46319047e1befb95..1a8ecd4784de9825fd798edcca990274b6c0044f 100644
--- a/jami-android/app/src/main/res/values-night/colors.xml
+++ b/jami-android/app/src/main/res/values-night/colors.xml
@@ -9,6 +9,9 @@
     <color name="colorPrimary">@color/white</color>
     <color name="colorPrimaryTranslucent">#C0FFFFFF</color>
     <color name="colorOnPrimary">@color/color_primary_dark</color>
+    <color name="colorSecondaryTranslucent">@color/color_primary_dark_translucent</color>
+
+    <color name="transparent">#00000000</color>
 
     <!--  Text color  -->
     <color name="colorOnSurface">@color/abc_primary_text_material_dark</color>
diff --git a/jami-android/app/src/main/res/values/colors.xml b/jami-android/app/src/main/res/values/colors.xml
index 0347945b57ce68d41c6ac630c49084a7501cc3c7..8ee0f2918c7e385fbbb46e1635bd3b3e8b065107 100644
--- a/jami-android/app/src/main/res/values/colors.xml
+++ b/jami-android/app/src/main/res/values/colors.xml
@@ -9,6 +9,7 @@
     <color name="colorPrimary">@color/color_primary_dark</color>
     <color name="colorPrimaryTranslucent">@color/color_primary_dark_translucent</color>
     <color name="colorOnPrimary">@color/white</color>
+    <color name="colorSecondaryTranslucent">@color/color_primary_light_translucent</color>
 
     <color name="colorSecondary">@color/color_primary_light</color>
     <color name="colorSecondaryContainer">@color/color_primary_light_container</color>
@@ -32,7 +33,7 @@
     <color name="darker_gray">#c4c4c4</color>
     <color name="lighter_gray">#d3d3d3</color>
     <color name="light">#eee</color>
-    <color name="transparent">#00000000</color>
+    <color name="transparent">#00FFFFFF</color>
 
     <color name="white">#FFF</color>
     <color name="black">#000000</color>
diff --git a/jami-android/libjamiclient/src/main/kotlin/net/jami/services/HardwareService.kt b/jami-android/libjamiclient/src/main/kotlin/net/jami/services/HardwareService.kt
index ba58ccaf084f28eb3ce82e09b32f5bc7717bd6d7..0c328be0ade7745c82c77fca86e2936b10ba422f 100644
--- a/jami-android/libjamiclient/src/main/kotlin/net/jami/services/HardwareService.kt
+++ b/jami-android/libjamiclient/src/main/kotlin/net/jami/services/HardwareService.kt
@@ -166,7 +166,6 @@ abstract class HardwareService(
     var unknownPriorityPushCount = 0
     var startTime: String? = null
 
-
     @get:Synchronized
     val isLogging: Boolean
         get() = logs != null
@@ -186,6 +185,7 @@ abstract class HardwareService(
             }
         }
             .buffer(500, TimeUnit.MILLISECONDS)
+            .filter { it.isNotEmpty() }
             .replay()
             .autoConnect()
             .apply { logs = this }