diff --git a/jami-android/app/src/main/java/cx/ring/client/ContactDetailsActivity.kt b/jami-android/app/src/main/java/cx/ring/client/ContactDetailsActivity.kt
index df9bb95801270d2b301fedd40f28bb7b0a822ffa..c3cbde854d6f5b39260c5ac25057d9bdb66408b4 100644
--- a/jami-android/app/src/main/java/cx/ring/client/ContactDetailsActivity.kt
+++ b/jami-android/app/src/main/java/cx/ring/client/ContactDetailsActivity.kt
@@ -52,10 +52,9 @@ import cx.ring.databinding.ItemContactHorizontalBinding
 import cx.ring.fragments.CallFragment
 import cx.ring.fragments.ContactPickerFragment
 import cx.ring.fragments.ConversationActionsFragment
-import cx.ring.fragments.ConversationFragment
 import cx.ring.fragments.ConversationGalleryFragment
 import cx.ring.fragments.ConversationMembersFragment
-import cx.ring.services.SharedPreferencesServiceImpl.Companion.getConversationPreferences
+import cx.ring.interfaces.Colorable
 import cx.ring.utils.*
 import cx.ring.views.AvatarDrawable
 import dagger.hilt.android.AndroidEntryPoint
@@ -75,10 +74,9 @@ import java.io.ByteArrayOutputStream
 import javax.inject.Inject
 import javax.inject.Singleton
 
-
 @AndroidEntryPoint
 class ContactDetailsActivity : AppCompatActivity(), TabLayout.OnTabSelectedListener,
-    ContactPickerFragment.OnContactedPicked, RenameSwarmDialog.RenameSwarmListener {
+    ContactPickerFragment.OnContactedPicked, RenameSwarmDialog.RenameSwarmListener, Colorable {
     @Inject
     @Singleton lateinit
     var mConversationFacade: ConversationFacade
@@ -165,7 +163,6 @@ class ContactDetailsActivity : AppCompatActivity(), TabLayout.OnTabSelectedListe
             setDisplayHomeAsUpEnabled(true)
             setDisplayShowHomeEnabled(true)
         }
-        val preferences = getConversationPreferences(this, conversation.accountId, conversation.uri)
 
         mDisposableBag.add(mConversationFacade.observeConversation(conversation)
             .observeOn(DeviceUtils.uiScheduler)
@@ -221,15 +218,21 @@ class ContactDetailsActivity : AppCompatActivity(), TabLayout.OnTabSelectedListe
                 finish()
             })
 
-        val color = preferences.getInt(ConversationFragment.KEY_PREFERENCE_CONVERSATION_COLOR, resources.getColor(R.color.color_primary_light))
-        updateColor(color)
         binding.tabLayout.addOnTabSelectedListener(this)
         binding.back.setOnClickListener { onBackPressedDispatcher.onBackPressed() }
         binding.addMember.setOnClickListener { ContactPickerFragment().show(supportFragmentManager, ContactPickerFragment.TAG) }
 
-
         mPagerAdapter = ScreenSlidePagerAdapter(this, conversation)
         binding.pager.adapter = mPagerAdapter
+
+        // Update color on RX color signal.
+        mDisposableBag.add(
+            conversation
+                .getColor()
+                .observeOn(DeviceUtils.uiScheduler)
+                .subscribe { setColor(it) }
+        )
+
         binding.pager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() {
             override fun onPageSelected(position: Int) {
                 super.onPageSelected(position)
@@ -238,6 +241,14 @@ class ContactDetailsActivity : AppCompatActivity(), TabLayout.OnTabSelectedListe
         })
     }
 
+    /**
+     * Set the color of the activity (appBar and addMember button).
+     */
+    override fun setColor(color: Int) {
+        binding?.appBar?.backgroundTintList = ColorStateList.valueOf(color)
+        binding?.addMember?.backgroundTintList = ColorStateList.valueOf(color)
+    }
+
     private fun profileImageClicked() {
         val inflater = LayoutInflater.from(this)
         val view = DialogProfileBinding.inflate(inflater).apply {
@@ -336,11 +347,6 @@ class ContactDetailsActivity : AppCompatActivity(), TabLayout.OnTabSelectedListe
             })
     }
 
-    public fun updateColor(color: Int) {
-        binding!!.appBar.backgroundTintList = ColorStateList.valueOf(color)
-        binding!!.addMember.backgroundTintList = ColorStateList.valueOf(color)
-    }
-
     override fun onOptionsItemSelected(item: MenuItem): Boolean {
         if (item.itemId == android.R.id.home) {
             finishAfterTransition()
@@ -388,8 +394,6 @@ class ContactDetailsActivity : AppCompatActivity(), TabLayout.OnTabSelectedListe
 
     override fun onTabReselected(tab: TabLayout.Tab?) {}
 
-
-
     override fun onContactPicked(accountId: String, contacts: Set<Contact>) {
         mAccountService.addConversationMembers(accountId, path!!.conversationUri.host, contacts.map { contact-> contact.uri.toString() })
     }
@@ -409,13 +413,15 @@ class ContactDetailsActivity : AppCompatActivity(), TabLayout.OnTabSelectedListe
         val accountId = conversation.accountId
         val conversationId = conversation.uri
 
-        val fragments: List<Fragment> = if (conversation.mode.blockingFirst() != Conversation.Mode.OneToOne) listOf(
+        val fragments = if (conversation.mode.blockingFirst() != Conversation.Mode.OneToOne) listOf(
             ConversationActionsFragment.newInstance(accountId, conversationId),
             ConversationMembersFragment.newInstance(accountId, conversationId),
-            ConversationGalleryFragment.newInstance(accountId, conversationId))
+            ConversationGalleryFragment.newInstance(accountId, conversationId)
+            )
         else listOf(
             ConversationActionsFragment.newInstance(accountId, conversationId),
-            ConversationGalleryFragment.newInstance(accountId, conversationId))
+            ConversationGalleryFragment.newInstance(accountId, conversationId)
+            )
 
         override fun getItemCount(): Int = fragments.size
 
diff --git a/jami-android/app/src/main/java/cx/ring/client/ConversationActivity.kt b/jami-android/app/src/main/java/cx/ring/client/ConversationActivity.kt
index ed5dc0ab2175844a17ca8149861148ef2452a7b2..b9f23c97cb755098bd12955448951cbef6bb9b40 100644
--- a/jami-android/app/src/main/java/cx/ring/client/ConversationActivity.kt
+++ b/jami-android/app/src/main/java/cx/ring/client/ConversationActivity.kt
@@ -22,26 +22,22 @@ package cx.ring.client
 
 import android.content.Intent
 import android.content.res.Configuration
-import android.os.Build
 import android.os.Bundle
 import android.view.KeyEvent
 import android.view.Menu
-import android.view.WindowManager
-import androidx.annotation.ColorInt
 import androidx.appcompat.app.AppCompatActivity
 import androidx.core.view.WindowCompat
 import cx.ring.R
 import cx.ring.application.JamiApplication
 import cx.ring.databinding.ActivityConversationBinding
 import cx.ring.fragments.ConversationFragment
-import cx.ring.interfaces.Colorable
 import cx.ring.services.NotificationServiceImpl
 import cx.ring.utils.ConversationPath
 import cx.ring.utils.DeviceUtils
 import dagger.hilt.android.AndroidEntryPoint
 
 @AndroidEntryPoint
-class ConversationActivity : AppCompatActivity(), Colorable {
+class ConversationActivity : AppCompatActivity() {
     private var mConversationFragment: ConversationFragment? = null
     private lateinit var conversationPath: ConversationPath
     private var mPendingIntent: Intent? = null
@@ -128,10 +124,4 @@ class ConversationActivity : AppCompatActivity(), Colorable {
         }
         return super.dispatchKeyEvent(event)
     }
-
-    override fun setColor(@ColorInt color: Int) {
-        //colouriseToolbar(binding.mainToolbar, color);
-        //mToolbar.setBackground(new ColorDrawable(color));
-        //getWindow().setStatusBarColor(color);
-    }
 }
\ No newline at end of file
diff --git a/jami-android/app/src/main/java/cx/ring/client/HomeActivity.kt b/jami-android/app/src/main/java/cx/ring/client/HomeActivity.kt
index 33801b54d169bbab7ec910fad474e8e5d16ee792..8177ca13bccba9ac8628b64ee9aa88089789b90a 100644
--- a/jami-android/app/src/main/java/cx/ring/client/HomeActivity.kt
+++ b/jami-android/app/src/main/java/cx/ring/client/HomeActivity.kt
@@ -51,7 +51,6 @@ import cx.ring.databinding.ActivityHomeBinding
 import cx.ring.fragments.ContactPickerFragment
 import cx.ring.fragments.ConversationFragment
 import cx.ring.fragments.HomeFragment
-import cx.ring.interfaces.Colorable
 import cx.ring.service.DRingService
 import cx.ring.settings.SettingsFragment
 import cx.ring.utils.BitmapUtils
@@ -78,7 +77,7 @@ import java.util.concurrent.TimeUnit
 import javax.inject.Inject
 
 @AndroidEntryPoint
-class HomeActivity : AppCompatActivity(), Colorable, ContactPickerFragment.OnContactedPicked {
+class HomeActivity : AppCompatActivity(), ContactPickerFragment.OnContactedPicked {
     private var frameContent: Fragment? = null
     private var fConversation: ConversationFragment? = null
     private var mHomeFragment: HomeFragment? = null
@@ -414,10 +413,6 @@ class HomeActivity : AppCompatActivity(), Colorable, ContactPickerFragment.OnCon
         }
     }
 
-    override fun setColor(color: Int) {
-        //mToolbar.setBackground(new ColorDrawable(color));
-    }
-
     fun setToolbarElevation(enable: Boolean) {
 //        if (mBinding != null) mBinding!!.appBar.elevation = if (enable) resources.getDimension(R.dimen.toolbar_elevation) else 0f
     }
diff --git a/jami-android/app/src/main/java/cx/ring/fragments/ConversationActionsFragment.kt b/jami-android/app/src/main/java/cx/ring/fragments/ConversationActionsFragment.kt
index 6895c97a7619ce795edc0685b31d8209c3dd571f..3fbdafc311835bb035ae4707241e2152f6cf5acb 100644
--- a/jami-android/app/src/main/java/cx/ring/fragments/ConversationActionsFragment.kt
+++ b/jami-android/app/src/main/java/cx/ring/fragments/ConversationActionsFragment.kt
@@ -42,8 +42,9 @@ import cx.ring.client.ContactDetailsActivity
 import cx.ring.client.EmojiChooserBottomSheet
 import cx.ring.databinding.FragConversationActionsBinding
 import cx.ring.databinding.ItemContactActionBinding
-import cx.ring.services.SharedPreferencesServiceImpl
+import cx.ring.interfaces.Colorable
 import cx.ring.utils.ConversationPath
+import cx.ring.utils.DeviceUtils
 import dagger.hilt.android.AndroidEntryPoint
 import io.reactivex.rxjava3.core.Single
 import io.reactivex.rxjava3.disposables.CompositeDisposable
@@ -55,7 +56,7 @@ import javax.inject.Inject
 import javax.inject.Singleton
 
 @AndroidEntryPoint
-class ConversationActionsFragment : Fragment() {
+class ConversationActionsFragment : Fragment(), Colorable {
 
     @Inject
     @Singleton
@@ -82,40 +83,61 @@ class ConversationActionsFragment : Fragment() {
                     .startConversation(path.accountId, path.conversationUri)
                     .blockingGet()
 
-            val preferences = SharedPreferencesServiceImpl.getConversationPreferences(
-                requireActivity(),
-                path.accountId,
-                path.conversationUri
-            )
-
             colorActionPosition = 0
             symbolActionPosition = 1
 
-            colorAction = ContactAction(R.drawable.item_color_background, 0, getText(R.string.conversation_preference_color)) {
-                ColorChooserBottomSheet { color ->
-                    colorAction!!.iconTint = color
-                    (activity as ContactDetailsActivity).updateColor(color)
-                    adapter.notifyItemChanged(colorActionPosition)
-                    preferences.edit()
-                        .putInt(ConversationFragment.KEY_PREFERENCE_CONVERSATION_COLOR, color)
-                        .apply()
+            // Setup an action to allow the user to select a color for the conversation.
+            colorAction = ContactAction(
+                R.drawable.item_color_background, 0,
+                getText(R.string.conversation_preference_color)
+            ) {
+                ColorChooserBottomSheet { color -> // Color chosen by the user (onclick method).
+                    setConversationPreferences(
+                        path.accountId,
+                        path.conversationUri,
+                        color = color
+                    )
+                    // Need to manually update the color of the conversation as will not get the
+                    // update signal from daemon.
+                    if (!path.conversationUri.isSwarm) conversation.setColor(color)
                 }.show(parentFragmentManager, "colorChooser")
             }
-            val color = preferences.getInt(ConversationFragment.KEY_PREFERENCE_CONVERSATION_COLOR, resources.getColor(R.color.color_primary_light))
-            colorAction!!.iconTint = color
+            // Add the action to the list of actions.
             adapter.actions.add(colorAction!!)
+
+            // Setup an action to allow the user to select an Emoji for the conversation.
             symbolAction = ContactAction(0, getText(R.string.conversation_preference_emoji)) {
-                EmojiChooserBottomSheet{ emoji ->
-                    symbolAction?.setSymbol(emoji)
-                    adapter.notifyItemChanged(symbolActionPosition)
-                    preferences.edit()
-                        .putString(ConversationFragment.KEY_PREFERENCE_CONVERSATION_SYMBOL, emoji)
-                        .apply()
+                EmojiChooserBottomSheet { emoji -> // Emoji chosen by the user (onclick method).
+                    if (emoji == null) return@EmojiChooserBottomSheet
+                    setConversationPreferences(
+                        path.accountId,
+                        path.conversationUri,
+                        emoji = emoji
+                    )
+                    // Need to manually update the symbol of the conversation as will not get the
+                    // update signal from daemon.
+                    if(!path.conversationUri.isSwarm) conversation.setSymbol(emoji.toString())
                 }.show(parentFragmentManager, "colorChooser")
-            }.apply {
-                setSymbol(preferences.getString(ConversationFragment.KEY_PREFERENCE_CONVERSATION_SYMBOL, resources.getString(R.string.conversation_default_emoji)))
-                adapter.actions.add(this)
             }
+            adapter.actions.add(symbolAction!!)
+
+            // Update color on RX color signal.
+            mDisposableBag.add(
+                conversation
+                    .getColor()
+                    .observeOn(DeviceUtils.uiScheduler)
+                    .subscribe {
+                        setColor(it) }
+            )
+
+            // Update symbol on RX color signal.
+            mDisposableBag.add(
+                conversation
+                    .getSymbol()
+                    .observeOn(DeviceUtils.uiScheduler)
+                    .subscribe {
+                        setSymbol(it.toString()) }
+            )
 
             @StringRes val infoString = if (conversation.isSwarm)
                 if (conversation.mode.blockingFirst() == Conversation.Mode.OneToOne)
@@ -196,6 +218,42 @@ class ConversationActionsFragment : Fragment() {
         binding = null
     }
 
+    /**
+     * Set the color of the color action button.
+     */
+    override fun setColor(color: Int) {
+        colorAction?.iconTint = color
+        adapter.notifyItemChanged(colorActionPosition)
+    }
+
+    /**
+     * Set the symbol of the symbol action button.
+     */
+    private fun setSymbol(symbol: String) {
+        symbolAction?.setSymbol(symbol) // Update emoji action icon
+        adapter.notifyItemChanged(symbolActionPosition)
+    }
+
+    /**
+     * Set the conversation preferences.
+     * Always resend the color and emoji, even if they are not changed (to not reset).
+     */
+    fun setConversationPreferences(
+        accountId: String,
+        conversationUri: Uri,
+        color: Int? = colorAction?.iconTint,
+        emoji: String = symbolAction?.iconSymbol.toString(),
+    ) {
+        mConversationFacade.setConversationPreferences(
+            accountId,
+            conversationUri,
+            mapOf(
+                "symbol" to emoji,
+                "color" to if (color != null) String.format("#%06X", 0xFFFFFF and color) else ""
+            )
+        )
+    }
+
     private fun copyAndShow(toCopy: String) {
         val clipboard = requireActivity().getSystemService(AppCompatActivity.CLIPBOARD_SERVICE) as ClipboardManager
         clipboard.setPrimaryClip(ClipData.newPlainText(getText(R.string.clip_contact_uri), toCopy))
diff --git a/jami-android/app/src/main/java/cx/ring/fragments/ConversationFragment.kt b/jami-android/app/src/main/java/cx/ring/fragments/ConversationFragment.kt
index 82ec33791cdfd0a84bf8bda781e19f8feb11c1d9..2873a08b5a8ebac425455a574e46fc17fc73bed7 100644
--- a/jami-android/app/src/main/java/cx/ring/fragments/ConversationFragment.kt
+++ b/jami-android/app/src/main/java/cx/ring/fragments/ConversationFragment.kt
@@ -26,7 +26,6 @@ import android.annotation.SuppressLint
 import android.app.Activity
 import android.app.ActivityOptions
 import android.content.*
-import android.content.SharedPreferences.OnSharedPreferenceChangeListener
 import android.content.pm.PackageManager
 import android.graphics.Typeface
 import android.net.Uri
@@ -62,7 +61,6 @@ import cx.ring.client.ContactDetailsActivity
 import cx.ring.client.ConversationActivity
 import cx.ring.client.HomeActivity
 import cx.ring.databinding.FragConversationBinding
-import cx.ring.interfaces.Colorable
 import cx.ring.mvp.BaseSupportFragment
 import cx.ring.service.DRingService
 import cx.ring.service.LocationSharingService
@@ -89,7 +87,7 @@ import java.util.*
 
 @AndroidEntryPoint
 class ConversationFragment : BaseSupportFragment<ConversationPresenter, ConversationView>(),
-    MediaButtonsHelperCallback, ConversationView, OnSharedPreferenceChangeListener,
+    MediaButtonsHelperCallback, ConversationView,
     SearchView.OnQueryTextListener {
     private var locationServiceConnection: ServiceConnection? = null
     private var binding: FragConversationBinding? = null
@@ -374,8 +372,6 @@ class ConversationFragment : BaseSupportFragment<ConversationPresenter, Conversa
     }
 
     override fun setConversationColor(@ColorInt color: Int) {
-        val activity = activity as Colorable?
-        activity?.setColor(color)
         mAdapter?.setPrimaryColor(color)
     }
 
@@ -384,7 +380,6 @@ class ConversationFragment : BaseSupportFragment<ConversationPresenter, Conversa
     }
 
     override fun onDestroyView() {
-        mPreferences?.unregisterOnSharedPreferenceChangeListener(this)
         animation.removeAllUpdateListeners()
         binding?.histList?.adapter = null
         mCompositeDisposable.clear()
@@ -896,16 +891,17 @@ class ConversationFragment : BaseSupportFragment<ConversationPresenter, Conversa
         val uri = path.conversationUri
         mAdapter = ConversationAdapter(this, presenter)
         presenter.init(uri, path.accountId)
+
+        // Load shared preferences. Usually useful for non-swarm conversations.
         try {
-            mPreferences = getConversationPreferences(requireContext(), path.accountId, uri).also { preferences ->
-                preferences.registerOnSharedPreferenceChangeListener(this)
-                presenter.setConversationColor(preferences.getInt(KEY_PREFERENCE_CONVERSATION_COLOR, resources.getColor(R.color.color_primary_light)))
-                presenter.setConversationSymbol(preferences.getString(KEY_PREFERENCE_CONVERSATION_SYMBOL, resources.getText(R.string.conversation_default_emoji).toString())!!)
-                preferences.edit().remove(KEY_PREFERENCE_CONVERSATION_LAST_READ).apply()
+            mPreferences = getConversationPreferences(requireContext(), path.accountId, uri)
+                .also { sharedPreferences ->
+                    sharedPreferences.edit().remove(KEY_PREFERENCE_CONVERSATION_LAST_READ).apply()
             }
         } catch (e: Exception) {
             Log.e(TAG, "Can't load conversation preferences")
         }
+
         var connection = locationServiceConnection
         if (connection == null) {
             connection = object : ServiceConnection {
@@ -935,15 +931,6 @@ class ConversationFragment : BaseSupportFragment<ConversationPresenter, Conversa
         }
     }
 
-    override fun onSharedPreferenceChanged(prefs: SharedPreferences, key: String) {
-        when (key) {
-            KEY_PREFERENCE_CONVERSATION_COLOR -> presenter.setConversationColor(
-                prefs.getInt(KEY_PREFERENCE_CONVERSATION_COLOR, resources.getColor(R.color.color_primary_light)))
-            KEY_PREFERENCE_CONVERSATION_SYMBOL -> presenter.setConversationSymbol(
-                prefs.getString(KEY_PREFERENCE_CONVERSATION_SYMBOL, resources.getText(R.string.conversation_default_emoji).toString())!!)
-        }
-    }
-
     override fun updateContact(contact: ContactViewModel) {
         val contactKey = contact.contact.primaryNumber
         val a = mSmallParticipantAvatars[contactKey]
diff --git a/jami-android/app/src/main/java/cx/ring/services/SharedPreferencesServiceImpl.kt b/jami-android/app/src/main/java/cx/ring/services/SharedPreferencesServiceImpl.kt
index 89fec228392b34da04e43a30768564c49e3e7833..30320a7053b052e7a6603da5b646e705a6476d80 100644
--- a/jami-android/app/src/main/java/cx/ring/services/SharedPreferencesServiceImpl.kt
+++ b/jami-android/app/src/main/java/cx/ring/services/SharedPreferencesServiceImpl.kt
@@ -25,6 +25,7 @@ import android.content.SharedPreferences
 import android.os.Build
 import android.text.TextUtils
 import androidx.appcompat.app.AppCompatDelegate
+import androidx.core.content.edit
 import androidx.preference.PreferenceManager
 import cx.ring.R
 import cx.ring.application.JamiApplication
@@ -36,6 +37,7 @@ import net.jami.services.AccountService
 import net.jami.services.DeviceRuntimeService
 import net.jami.services.PreferencesService
 import java.util.*
+import kotlin.collections.HashMap
 
 class SharedPreferencesServiceImpl(private val context: Context, accountService: AccountService, deviceService: DeviceRuntimeService)
     : PreferencesService(accountService, deviceService) {
@@ -103,6 +105,28 @@ class SharedPreferencesServiceImpl(private val context: Context, accountService:
         saveRequests(accountId, requests)
     }
 
+    /**
+     * Load conversation preferences from the shared preferences.
+     */
+    override fun getConversationPreferences(
+        accountId: String,
+        conversationUri: Uri,
+    ): Map<String, String> =
+        getConversationPreferences(context, accountId, conversationUri)
+            .all.mapValuesTo(HashMap()) { (_, v) -> v.toString() }
+
+    /**
+     * Save conversation preferences to the shared preferences.
+     */
+    override fun setConversationPreferences(
+        accountId: String,
+        conversationUri: Uri,
+        preferences: Map<String, String>,
+    ) =
+        getConversationPreferences(context, accountId, conversationUri)
+        .edit { preferences.forEach { (k, v) -> putString(k, v) } }
+
+
     override fun hasNetworkConnected(): Boolean = NetworkUtils.isConnectivityAllowed(context)
 
     override val isPushAllowed: Boolean
@@ -175,8 +199,7 @@ class SharedPreferencesServiceImpl(private val context: Context, accountService:
         const val PREF_PLUGINS = "plugins"
         private const val PREF_LOG_IS_ACTIVE = "log_is_active"
 
-        fun getConversationPreferences(context: Context, accountId: String, conversationUri: Uri): SharedPreferences {
-            return context.getSharedPreferences(accountId + "_" + conversationUri.uri, Context.MODE_PRIVATE)
-        }
+        fun getConversationPreferences(context: Context, accountId: String, conversationUri: Uri): SharedPreferences =
+            context.getSharedPreferences(accountId + "_" + conversationUri.uri, Context.MODE_PRIVATE)
     }
 }
\ No newline at end of file
diff --git a/jami-android/libjamiclient/src/main/kotlin/net/jami/model/Conversation.kt b/jami-android/libjamiclient/src/main/kotlin/net/jami/model/Conversation.kt
index 20a2bad01fd7bfc8743a195d29ada4c76dbba0d4..9abb80515876552b3f693b8b3860ea3c99557129 100644
--- a/jami-android/libjamiclient/src/main/kotlin/net/jami/model/Conversation.kt
+++ b/jami-android/libjamiclient/src/main/kotlin/net/jami/model/Conversation.kt
@@ -26,11 +26,8 @@ import io.reactivex.rxjava3.subjects.BehaviorSubject
 import io.reactivex.rxjava3.subjects.PublishSubject
 import io.reactivex.rxjava3.subjects.SingleSubject
 import io.reactivex.rxjava3.subjects.Subject
-import kotlin.jvm.Synchronized
 import net.jami.utils.Log
-import java.lang.IllegalStateException
 import java.util.*
-import kotlin.collections.HashMap
 
 class Conversation : ConversationHistory {
     val accountId: String
@@ -653,7 +650,12 @@ class Conversation : ConversationHistory {
     fun getSymbol(): Observable<CharSequence> = symbol
 
     fun updatePreferences(preferences: Map<String, String>) {
-        preferences["color"]?.let { color.onNext(it.substring(1).toInt(16)) }
+        preferences["color"]?.let {
+            // First, we remove the string first character (the #).
+            // The color format is RRGGBB but we want AARRGGBB.
+            // So we add FF in front of the color (full opacity).
+            color.onNext(it.substring(1).toInt(16) or 0xFF000000.toInt())
+        }
         preferences["symbol"]?.let { symbol.onNext(it) }
     }
 
diff --git a/jami-android/libjamiclient/src/main/kotlin/net/jami/services/AccountService.kt b/jami-android/libjamiclient/src/main/kotlin/net/jami/services/AccountService.kt
index ddfe30c529fad068d2a99e4e96e113dd1c23c9de..16d055e904eec213196c24edb64e61586a099007 100644
--- a/jami-android/libjamiclient/src/main/kotlin/net/jami/services/AccountService.kt
+++ b/jami-android/libjamiclient/src/main/kotlin/net/jami/services/AccountService.kt
@@ -276,6 +276,11 @@ class AccountService(
                         val mode = if ("true" == info["syncing"]) Conversation.Mode.Syncing else Conversation.Mode.values()[info["mode"]!!.toInt()]
                         val conversation = account.newSwarm(conversationId, mode)
                         conversation.setProfile(mVCardService.loadConversationProfile(info))
+
+                        val preferences = // Load conversation preferences (color, symbol, etc.)
+                            JamiService.getConversationPreferences(accountId, conversationId)
+                        conversation.updatePreferences(preferences)
+
                         conversation.setLastMessageNotified(mHistoryService.getLastMessageNotified(accountId, conversation.uri))
                         for (member in JamiService.getConversationMembers(accountId, conversationId)) {
                             /*for (Map.Entry<String, String> i : member.entrySet()) {
diff --git a/jami-android/libjamiclient/src/main/kotlin/net/jami/services/ConversationFacade.kt b/jami-android/libjamiclient/src/main/kotlin/net/jami/services/ConversationFacade.kt
index 6a19362977e8ad8bf238d4276b52abc187325329..2f96c078ddf9e445fe65a5f93c23f60be34f4c7a 100644
--- a/jami-android/libjamiclient/src/main/kotlin/net/jami/services/ConversationFacade.kt
+++ b/jami-android/libjamiclient/src/main/kotlin/net/jami/services/ConversationFacade.kt
@@ -53,6 +53,26 @@ class ConversationFacade(
         .currentAccountSubject
         .switchMapSingle { account: Account -> loadSmartlist(account) }
 
+    /**
+     * Two cases: Swarm conversation or non-swarm conversation.
+     * If swarm conversation, we need to send the preferences to daemon (in order
+     * to update preferences also on other devices).
+     * Else, we just save preferences to preferences service.
+     */
+    fun setConversationPreferences(
+        accountId: String,
+        conversationUri: Uri,
+        preferences: Map<String, String>,
+    ) {
+        if (conversationUri.isSwarm) {
+            mAccountService.setConversationPreferences(
+                accountId, conversationUri.rawRingId, preferences
+            )
+        } else {
+            mPreferencesService.setConversationPreferences(accountId, conversationUri, preferences)
+        }
+    }
+
     fun startConversation(accountId: String, contactId: Uri): Single<Conversation> = getAccountSubject(accountId)
         .map { account: Account -> account.getByUri(contactId)!! }
 
@@ -429,6 +449,13 @@ class ConversationFacade(
                         conversation.id = e.conversation!!.id
                         conversation.addElement(e)
                         conversation.setLastMessageNotified(mHistoryService.getLastMessageNotified(account.accountId, conversation.uri))
+                        // Update the conversation preferences.
+                        conversation.updatePreferences(
+                            mPreferencesService.getConversationPreferences(
+                                account.accountId,
+                                conversation.uri
+                            )
+                        )
                         conversations.add(conversation)
                     }
                     account.setHistoryLoaded(conversations)
diff --git a/jami-android/libjamiclient/src/main/kotlin/net/jami/services/PreferencesService.kt b/jami-android/libjamiclient/src/main/kotlin/net/jami/services/PreferencesService.kt
index 3a5b7ed11e102372ace15c9361645263694cc621..e1ec0002a065245372245c0eb7c1287690e3d40a 100644
--- a/jami-android/libjamiclient/src/main/kotlin/net/jami/services/PreferencesService.kt
+++ b/jami-android/libjamiclient/src/main/kotlin/net/jami/services/PreferencesService.kt
@@ -24,6 +24,7 @@ import io.reactivex.rxjava3.core.Observable
 import io.reactivex.rxjava3.subjects.BehaviorSubject
 import io.reactivex.rxjava3.subjects.Subject
 import net.jami.model.Settings
+import net.jami.model.Uri
 
 abstract class PreferencesService(
     private val mAccountService: AccountService,
@@ -53,6 +54,31 @@ abstract class PreferencesService(
     val settingsSubject: Observable<Settings>
         get() = mSettingsSubject
 
+    /**
+     * Get the preferences for a given account
+     *
+     * @param accountId the account id
+     * @param conversationUri the conversation uri
+     * @return the preferences for the given account
+     */
+    abstract fun getConversationPreferences(
+        accountId: String,
+        conversationUri: Uri,
+    ): Map<String, String>
+
+    /**
+     * Set the preferences for a given account
+     *
+     * @param accountId the account id
+     * @param conversationUri the conversation uri
+     * @param preferences the preferences to set
+     */
+    abstract fun setConversationPreferences(
+        accountId: String,
+        conversationUri: Uri,
+        preferences: Map<String, String>,
+    )
+
     abstract fun hasNetworkConnected(): Boolean
     abstract val isPushAllowed: Boolean
     abstract fun saveRequestPreferences(accountId: String, contactId: String)