Changes for friends list storage

This commit is contained in:
Sylvain Berfini 2023-09-01 11:22:55 +02:00
parent b93f75aade
commit 89c7e734d4
8 changed files with 79 additions and 33 deletions

View file

@ -38,6 +38,7 @@ enable_basic_to_client_group_chat_room_migration=0
enable_simple_group_chat_message_state=0
aggregate_imdn=1
notify_each_friend_individually_when_presence_received=0
store_friends=0
[app]
activation_code_length=4

View file

@ -49,6 +49,11 @@ class ContactLoader : LoaderManager.LoaderCallbacks<Cursor> {
ContactsContract.CommonDataKinds.Phone.LABEL,
ContactsContract.CommonDataKinds.Phone.NORMALIZED_NUMBER
)
private const val TAG = "[Contacts Loader]"
private const val NATIVE_ADDRESS_BOOK_FRIEND_LIST = "Native address-book"
const val LINPHONE_ADDRESS_BOOK_FRIEND_LIST = "Linphone address-book"
}
@MainThread
@ -77,15 +82,15 @@ class ContactLoader : LoaderManager.LoaderCallbacks<Cursor> {
@MainThread
override fun onLoadFinished(loader: Loader<Cursor>, cursor: Cursor?) {
if (cursor == null) {
Log.e("[Contacts Loader] Cursor is null!")
Log.e("$TAG Cursor is null!")
return
}
Log.i("[Contacts Loader] Load finished, found ${cursor.count} entries in cursor")
Log.i("$TAG Load finished, found ${cursor.count} entries in cursor")
coreContext.postOnCoreThread { core ->
val state = coreContext.core.globalState
if (state == GlobalState.Shutdown || state == GlobalState.Off) {
Log.w("[Contacts Loader] Core is being stopped or already destroyed, abort")
Log.w("$TAG Core is being stopped or already destroyed, abort")
return@postOnCoreThread
}
@ -278,47 +283,57 @@ class ContactLoader : LoaderManager.LoaderCallbacks<Cursor> {
friends[id] = friend
} catch (e: Exception) {
Log.e("[Contacts Loader] Exception: $e")
Log.e("$TAG Exception: $e")
}
}
if (core.globalState == GlobalState.Shutdown || core.globalState == GlobalState.Off) {
Log.w("[Contacts Loader] Core is being stopped or already destroyed, abort")
Log.w("$TAG Core is being stopped or already destroyed, abort")
} else if (friends.isEmpty()) {
Log.w("[Contacts Loader] No friend created!")
Log.w("$TAG No friend created!")
} else {
Log.i("[Contacts Loader] ${friends.size} friends created")
Log.i("$TAG ${friends.size} friends created")
val fl = core.defaultFriendList ?: core.createFriendList()
for (friend in fl.friends) {
fl.removeFriend(friend)
val fl = core.getFriendListByName(NATIVE_ADDRESS_BOOK_FRIEND_LIST) ?: core.createFriendList()
if (fl.displayName.isNullOrEmpty()) {
Log.i(
"$TAG Friend list [$NATIVE_ADDRESS_BOOK_FRIEND_LIST] didn't exist yet, let's create it"
)
fl.isDatabaseStorageEnabled = false // We don't want to store local address-book in DB
fl.displayName = NATIVE_ADDRESS_BOOK_FRIEND_LIST
core.addFriendList(fl)
} else {
Log.i(
"$TAG Friend list [$LINPHONE_ADDRESS_BOOK_FRIEND_LIST] found, removing existing friends if any"
)
for (friend in fl.friends) {
fl.removeFriend(friend)
}
}
if (fl != core.defaultFriendList) core.addFriendList(fl)
val friendsList = friends.values
for (friend in friendsList) {
fl.addLocalFriend(friend)
}
friends.clear()
Log.i("[Contacts Loader] Friends added")
Log.i("$TAG Friends added")
fl.updateSubscriptions()
Log.i("[Contacts Loader] Subscription(s) updated")
Log.i("$TAG Subscription(s) updated")
coreContext.contactsManager.onContactsLoaded()
}
} catch (sde: StaleDataException) {
Log.e("[Contacts Loader] State Data Exception: $sde")
Log.e("$TAG State Data Exception: $sde")
} catch (ise: IllegalStateException) {
Log.e("[Contacts Loader] Illegal State Exception: $ise")
Log.e("$TAG Illegal State Exception: $ise")
} catch (e: Exception) {
Log.e("[Contacts Loader] Exception: $e")
Log.e("$TAG Exception: $e")
}
}
}
@MainThread
override fun onLoaderReset(loader: Loader<Cursor>) {
Log.i("[Contacts Loader] Loader reset")
Log.i("$TAG Loader reset")
}
}

View file

@ -117,7 +117,11 @@ class ContactsManager @UiThread constructor(context: Context) {
@WorkerThread
fun findContactById(id: String): Friend? {
return coreContext.core.defaultFriendList?.findFriendByRefKey(id)
for (friendList in coreContext.core.friendsLists) {
val found = friendList.findFriendByRefKey(id)
if (found != null) return found
}
return null
}
@WorkerThread

View file

@ -104,10 +104,11 @@ class CoreContext @UiThread constructor(val context: Context) : HandlerThread("C
coreThread = Handler(looper)
core = Factory.instance().createCoreWithConfig(corePreferences.config, context)
core.isAutoIterateEnabled = false
core.addListener(coreListener)
core.friendsDatabasePath = corePreferences.friendsDatabasePath
val timer = Timer("Linphone core.iterate() scheduler")
timer.schedule(
object : TimerTask() {

View file

@ -29,6 +29,10 @@ import java.io.FileOutputStream
import org.linphone.LinphoneApplication.Companion.coreContext
class CorePreferences @UiThread constructor(private val context: Context) {
companion object {
private const val TAG = "[Preferences]"
}
private var _config: Config? = null
@get:WorkerThread @set:WorkerThread
@ -82,6 +86,10 @@ class CorePreferences @UiThread constructor(private val context: Context) {
val factoryConfigPath: String
get() = context.filesDir.absolutePath + "/linphonerc"
@get:AnyThread
val friendsDatabasePath: String
get() = context.filesDir.absolutePath + "/friends.db"
@get:AnyThread
val linphoneDefaultValuesPath: String
get() = context.filesDir.absolutePath + "/assistant_linphone_default_values"
@ -100,14 +108,14 @@ class CorePreferences @UiThread constructor(private val context: Context) {
if (!overrideIfExists) {
android.util.Log.i(
context.getString(org.linphone.R.string.app_name),
"[Preferences] File $to already exists"
"$TAG File $to already exists"
)
return
}
}
android.util.Log.i(
context.getString(org.linphone.R.string.app_name),
"[Preferences] Overriding $to by $from asset"
"$TAG Overriding $to by $from asset"
)
val outStream = FileOutputStream(outFile)

View file

@ -106,12 +106,15 @@ class ContactsListFragment : GenericFragment() {
listViewModel.contactsList.observe(
viewLifecycleOwner
) {
val emptyAdapter = adapter.itemCount == 0
adapter.submitList(it)
Log.i("$TAG Contacts list is ready with [${it.size}] items")
Log.i("$TAG Contacts list updated with [${it.size}] items")
(view.parent as? ViewGroup)?.doOnPreDraw {
startPostponedEnterTransition()
sharedViewModel.contactsListReadyToBeDisplayedEvent.value = Event(true)
if (emptyAdapter) {
(view.parent as? ViewGroup)?.doOnPreDraw {
startPostponedEnterTransition()
sharedViewModel.contactsListReadyToBeDisplayedEvent.value = Event(true)
}
}
}
@ -119,7 +122,7 @@ class ContactsListFragment : GenericFragment() {
viewLifecycleOwner
) {
favouritesAdapter.submitList(it)
Log.i("$TAG Favourites contacts list is ready with [${it.size}] items")
Log.i("$TAG Favourites contacts list updated with [${it.size}] items")
}
listViewModel.vCardTerminatedEvent.observe(viewLifecycleOwner) {

View file

@ -25,6 +25,7 @@ import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import org.linphone.LinphoneApplication.Companion.coreContext
import org.linphone.contacts.ContactLoader.Companion.LINPHONE_ADDRESS_BOOK_FRIEND_LIST
import org.linphone.core.Friend
import org.linphone.core.FriendList.Status
import org.linphone.core.tools.Log
@ -179,10 +180,23 @@ class ContactNewOrEditViewModel @UiThread constructor() : ViewModel() {
Log.e("$TAG Failed to generate a ref key using vCard's generateUniqueId()")
// TODO : generate unique ref key
}
status = core.defaultFriendList?.addFriend(friend) ?: Status.InvalidFriend
friend.done()
val fl = core.getFriendListByName(LINPHONE_ADDRESS_BOOK_FRIEND_LIST) ?: core.createFriendList()
if (fl.displayName.isNullOrEmpty()) {
Log.i(
"$TAG Locally saved friend list [$LINPHONE_ADDRESS_BOOK_FRIEND_LIST] didn't exist yet, let's create it"
)
fl.isDatabaseStorageEnabled = true // We do want to store friends created in app in DB
fl.displayName = LINPHONE_ADDRESS_BOOK_FRIEND_LIST
core.addFriendList(fl)
}
status = fl.addFriend(friend)
fl.updateSubscriptions()
} else {
friend.done()
}
friend.done()
coreContext.contactsManager.notifyContactsListChanged()
saveChangesEvent.postValue(

View file

@ -142,7 +142,7 @@
android:textColor="@color/gray_9"
android:maxLines="1"
android:background="@drawable/edit_text_background"
android:inputType="text|textPersonName"
android:inputType="text|textPersonName|textCapWords"
app:layout_constraintTop_toBottomOf="@id/first_name_label"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
@ -176,7 +176,7 @@
android:textColor="@color/gray_9"
android:maxLines="1"
android:background="@drawable/edit_text_background"
android:inputType="text|textPersonName"
android:inputType="text|textPersonName|textCapWords"
app:layout_constraintTop_toBottomOf="@id/last_name_label"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
@ -230,7 +230,7 @@
android:textColor="@color/gray_9"
android:maxLines="1"
android:background="@drawable/edit_text_background"
android:inputType="text"
android:inputType="text|textCapWords"
app:layout_constraintTop_toBottomOf="@id/company_label"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
@ -265,7 +265,7 @@
android:textColor="@color/gray_9"
android:maxLines="1"
android:background="@drawable/edit_text_background"
android:inputType="text"
android:inputType="text|textCapWords"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/job_title_label"
app:layout_constraintStart_toStartOf="parent"