diff --git a/ring-android/app/src/main/java/cx/ring/account/AccountEditionFragment.kt b/ring-android/app/src/main/java/cx/ring/account/AccountEditionFragment.kt index 77722ecea9c00507fb11510d9d995d15c45841e9..f94d6565a61e8f058ca9c762a53ce88cd6bf73c3 100644 --- a/ring-android/app/src/main/java/cx/ring/account/AccountEditionFragment.kt +++ b/ring-android/app/src/main/java/cx/ring/account/AccountEditionFragment.kt @@ -148,31 +148,26 @@ class AccountEditionFragment : BaseSupportFragment<AccountEditionPresenter, Acco ) : FragmentStatePagerAdapter(fm) { override fun getCount(): Int = if (isJamiAccount) 3 else 4 - override fun getItem(position: Int): Fragment { - return if (isJamiAccount) getJamiPanel(position) else getSIPPanel(position) - } + override fun getItem(position: Int): Fragment = + if (isJamiAccount) getJamiPanel(position) else getSIPPanel(position) override fun getPageTitle(position: Int): CharSequence = mContext.getString(if (isJamiAccount) getRingPanelTitle(position) else getSIPPanelTitle(position)) - private fun getJamiPanel(position: Int): Fragment { - return when (position) { - 0 -> fragmentWithBundle(GeneralAccountFragment()) - 1 -> fragmentWithBundle(MediaPreferenceFragment()) - 2 -> fragmentWithBundle(AdvancedAccountFragment()) - 3 -> fragmentWithBundle(PluginsListSettingsFragment()) - else -> throw IllegalArgumentException() - } + private fun getJamiPanel(position: Int): Fragment = when (position) { + 0 -> fragmentWithBundle(GeneralAccountFragment()) + 1 -> fragmentWithBundle(MediaPreferenceFragment()) + 2 -> fragmentWithBundle(AdvancedAccountFragment()) + 3 -> fragmentWithBundle(PluginsListSettingsFragment()) + else -> throw IllegalArgumentException() } - private fun getSIPPanel(position: Int): Fragment { - return when (position) { - 0 -> GeneralAccountFragment.newInstance(accountId) - 1 -> MediaPreferenceFragment.newInstance(accountId) - 2 -> fragmentWithBundle(AdvancedAccountFragment()) - 3 -> fragmentWithBundle(SecurityAccountFragment()) - 4 -> fragmentWithBundle(PluginsListSettingsFragment()) - else -> throw IllegalArgumentException() - } + private fun getSIPPanel(position: Int): Fragment = when (position) { + 0 -> GeneralAccountFragment.newInstance(accountId) + 1 -> MediaPreferenceFragment.newInstance(accountId) + 2 -> fragmentWithBundle(AdvancedAccountFragment()) + 3 -> fragmentWithBundle(SecurityAccountFragment()) + 4 -> fragmentWithBundle(PluginsListSettingsFragment()) + else -> throw IllegalArgumentException() } private fun fragmentWithBundle(result: Fragment): Fragment = result.apply { @@ -181,26 +176,22 @@ class AccountEditionFragment : BaseSupportFragment<AccountEditionPresenter, Acco companion object { @StringRes - private fun getRingPanelTitle(position: Int): Int { - return when (position) { - 0 -> R.string.account_preferences_basic_tab - 1 -> R.string.account_preferences_media_tab - 2 -> R.string.account_preferences_advanced_tab - 3 -> R.string.account_preference_plugin_tab - else -> -1 - } + private fun getRingPanelTitle(position: Int): Int = when (position) { + 0 -> R.string.account_preferences_basic_tab + 1 -> R.string.account_preferences_media_tab + 2 -> R.string.account_preferences_advanced_tab + 3 -> R.string.account_preference_plugin_tab + else -> -1 } @StringRes - private fun getSIPPanelTitle(position: Int): Int { - return when (position) { - 0 -> R.string.account_preferences_basic_tab - 1 -> R.string.account_preferences_media_tab - 2 -> R.string.account_preferences_advanced_tab - 3 -> R.string.account_preferences_security_tab - 4 -> R.string.account_preference_plugin_tab - else -> -1 - } + private fun getSIPPanelTitle(position: Int): Int = when (position) { + 0 -> R.string.account_preferences_basic_tab + 1 -> R.string.account_preferences_media_tab + 2 -> R.string.account_preferences_advanced_tab + 3 -> R.string.account_preferences_security_tab + 4 -> R.string.account_preference_plugin_tab + else -> -1 } } } diff --git a/ring-android/app/src/main/java/cx/ring/account/JamiAccountSummaryFragment.kt b/ring-android/app/src/main/java/cx/ring/account/JamiAccountSummaryFragment.kt index e8fe3c329c3fef9571ac547ad1a909d5bfd2d5db..626a76a6f63e185bbdb812b6f8e6732f3bb1141c 100644 --- a/ring-android/app/src/main/java/cx/ring/account/JamiAccountSummaryFragment.kt +++ b/ring-android/app/src/main/java/cx/ring/account/JamiAccountSummaryFragment.kt @@ -65,9 +65,9 @@ import cx.ring.settings.pluginssettings.PluginsListSettingsFragment import cx.ring.utils.AndroidFileUtils import cx.ring.utils.BitmapUtils import cx.ring.utils.ContentUriHandler +import cx.ring.utils.DeviceUtils import cx.ring.views.AvatarDrawable import dagger.hilt.android.AndroidEntryPoint -import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.core.Single import io.reactivex.rxjava3.disposables.CompositeDisposable import io.reactivex.rxjava3.schedulers.Schedulers @@ -195,7 +195,7 @@ class JamiAccountSummaryFragment : resultData?.data?.let { uri -> mCacheArchive?.let { cacheArchive -> AndroidFileUtils.moveToUri(requireContext().contentResolver, cacheArchive, uri) - .observeOn(AndroidSchedulers.mainThread()) + .observeOn(DeviceUtils.uiScheduler) .subscribe({}) { e: Throwable -> val v = view if (v != null) @@ -297,7 +297,7 @@ class JamiAccountSummaryFragment : } mProfilePhoto = view.profilePhoto mDisposableBag.add(AvatarDrawable.load(inflater.context, account) - .observeOn(AndroidSchedulers.mainThread()) + .observeOn(DeviceUtils.uiScheduler) .subscribe { a -> view.profilePhoto.setImageDrawable(a) }) MaterialAlertDialogBuilder(requireContext()) .setTitle(R.string.profile) @@ -468,7 +468,7 @@ class JamiAccountSummaryFragment : .withCircleCrop(true) .build(requireContext()) } - .observeOn(AndroidSchedulers.mainThread()) + .observeOn(DeviceUtils.uiScheduler) .subscribe({ avatar: AvatarDrawable -> mProfilePhoto?.setImageDrawable(avatar) }) { e: Throwable -> Log.e(TAG, "Error loading image", e) }) diff --git a/ring-android/app/src/main/java/cx/ring/adapters/ConversationAdapter.kt b/ring-android/app/src/main/java/cx/ring/adapters/ConversationAdapter.kt index 18eacc642a445ecf35260c6074892e8d89be278b..f8ae317ec69e751463a38a02f031948128e634f9 100644 --- a/ring-android/app/src/main/java/cx/ring/adapters/ConversationAdapter.kt +++ b/ring-android/app/src/main/java/cx/ring/adapters/ConversationAdapter.kt @@ -33,6 +33,8 @@ import android.graphics.SurfaceTexture import android.graphics.drawable.Drawable import android.media.MediaPlayer import android.net.Uri +import android.os.Handler +import android.os.Looper import android.text.SpannableStringBuilder import android.text.format.DateUtils import android.text.format.Formatter @@ -76,9 +78,10 @@ import cx.ring.viewholders.ConversationViewHolder import cx.ring.views.AvatarDrawable import io.noties.markwon.Markwon import io.noties.markwon.linkify.LinkifyPlugin -import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.core.Maybe import io.reactivex.rxjava3.core.Observable +import io.reactivex.rxjava3.core.Scheduler +import io.reactivex.rxjava3.schedulers.Schedulers import net.jami.conversation.ConversationPresenter import net.jami.model.* import net.jami.model.Account.ComposingStatus @@ -107,7 +110,7 @@ class ConversationAdapter( @ColorInt private var convColor = 0 private var expandedItemPosition = -1 private var lastDeliveredPosition = -1 - private val timestampUpdateTimer: Observable<Long> = Observable.interval(10, TimeUnit.SECONDS, AndroidSchedulers.mainThread()) + private val timestampUpdateTimer: Observable<Long> = Observable.interval(10, TimeUnit.SECONDS, DeviceUtils.uiScheduler) .startWithItem(0L) private var lastMsgPos = -1 private var isComposing = false @@ -287,7 +290,7 @@ class ConversationAdapter( } conversationViewHolder.compositeDisposable.add(presenter.conversationFacade .getLoadedContact(interaction.account!!, conversation, interaction.displayedContacts) - .observeOn(AndroidSchedulers.mainThread()) + .observeOn(DeviceUtils.uiScheduler) .subscribe { contacts -> conversationViewHolder.mStatusIcon?.isVisible = contacts.isNotEmpty() conversationViewHolder.mStatusIcon?.update(contacts, interaction.status, conversationViewHolder.mMsgTxt?.id ?: View.NO_ID) @@ -302,7 +305,7 @@ class ConversationAdapter( presenter.removeReaction(interaction) } conversationViewHolder.compositeDisposable.add(interaction.reactionObservable - .observeOn(AndroidSchedulers.mainThread()) + .observeOn(DeviceUtils.uiScheduler) .subscribe { reactions -> Log.w(TAG, "reaction $reactions") val chip = conversationViewHolder.reactionChip ?: return@subscribe @@ -335,7 +338,7 @@ class ConversationAdapter( .flatMapObservable { reply -> presenter.contactService .observeContact(interaction.account!!, reply.contact!!, false) .map { contact -> Pair(reply, contact) }} - .observeOn(AndroidSchedulers.mainThread()) + .observeOn(DeviceUtils.uiScheduler) .subscribe({ i -> replyView.text = SpannableStringBuilder() .bold { @@ -518,7 +521,7 @@ class ConversationAdapter( acceptBtn.setImageResource(R.drawable.baseline_play_arrow_24) } viewHolder.compositeDisposable.add( - Observable.interval(1L, TimeUnit.SECONDS, AndroidSchedulers.mainThread()) + Observable.interval(1L, TimeUnit.SECONDS, DeviceUtils.uiScheduler) .startWithItem(0L) .subscribe { val pS = player.currentPosition / 1000 @@ -797,7 +800,7 @@ class ConversationAdapter( private fun configureForTextMessage(convViewHolder: ConversationViewHolder, interaction: Interaction, position: Int) { val context = convViewHolder.itemView.context convViewHolder.compositeDisposable.add(interaction.lastElement - .observeOn(AndroidSchedulers.mainThread()) + .observeOn(DeviceUtils.uiScheduler) .subscribe { lastElement -> val textMessage = lastElement as TextMessage val contact = textMessage.contact ?: return@subscribe @@ -849,7 +852,7 @@ class ConversationAdapter( .apply { interaction.preview = this } convViewHolder.compositeDisposable.add(cachedPreview - .observeOn(AndroidSchedulers.mainThread()) + .observeOn(DeviceUtils.uiScheduler) .subscribe({ data -> Log.w(TAG, "got preview $data") val image = convViewHolder.mImage ?: return@subscribe @@ -941,6 +944,7 @@ class ConversationAdapter( }) } + private fun configureForContactEvent(viewHolder: ConversationViewHolder, interaction: Interaction) { val event = interaction as ContactEvent Log.w(TAG, "configureForContactEvent ${event.account} ${event.event} ${event.contact} ${event.author} ") @@ -949,7 +953,7 @@ class ConversationAdapter( if (interaction.isSwarm) { viewHolder.compositeDisposable.add( presenter.contactService.observeContact(event.account!!, event.contact!!, false) - .observeOn(AndroidSchedulers.mainThread()) + .observeOn(DeviceUtils.uiScheduler) .subscribe { vm -> viewHolder.mImage?.setImageDrawable(AvatarDrawable.Builder() .withContact(vm) diff --git a/ring-android/app/src/main/java/cx/ring/client/AccountSpinnerAdapter.kt b/ring-android/app/src/main/java/cx/ring/client/AccountSpinnerAdapter.kt index 4d67597caca5a68bc96b9026b3c28591a1f6f7f5..b71dec30f4bf898e86cb9615b6baca3ca076211c 100644 --- a/ring-android/app/src/main/java/cx/ring/client/AccountSpinnerAdapter.kt +++ b/ring-android/app/src/main/java/cx/ring/client/AccountSpinnerAdapter.kt @@ -31,8 +31,8 @@ import com.google.android.material.badge.BadgeUtils import cx.ring.R import cx.ring.databinding.ItemToolbarSelectedBinding import cx.ring.databinding.ItemToolbarSpinnerBinding +import cx.ring.utils.DeviceUtils import cx.ring.views.AvatarDrawable -import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.disposables.CompositeDisposable import net.jami.model.Account import net.jami.model.Profile @@ -70,7 +70,7 @@ class AccountSpinnerAdapter(context: Context, accounts: List<Account>, val dispo if (type == TYPE_ACCOUNT) { val account = getItem(position)!! holder.loader.add(mAccountService.getObservableAccountProfile(account.accountId) - .observeOn(AndroidSchedulers.mainThread()) + .observeOn(DeviceUtils.uiScheduler) .subscribe({ profile -> holder.binding.logo.setImageDrawable(AvatarDrawable.build(holder.binding.root.context, profile.first, profile.second, true, profile.first.isRegistered)) holder.binding.title.text = getTitle(profile.first, profile.second) @@ -107,7 +107,7 @@ class AccountSpinnerAdapter(context: Context, accounts: List<Account>, val dispo logoParam.height = logoSize holder.binding.logo.layoutParams = logoParam holder.loader.add(mAccountService.getObservableAccountProfile(account.accountId) - .observeOn(AndroidSchedulers.mainThread()) + .observeOn(DeviceUtils.uiScheduler) .subscribe({ profile -> val subtitle = getUri(account, ip2ipString) holder.binding.logo.setImageDrawable(AvatarDrawable.build(holder.binding.root.context, profile.first, profile.second, true, profile.first.isRegistered)) @@ -121,7 +121,7 @@ class AccountSpinnerAdapter(context: Context, accounts: List<Account>, val dispo }){ e: Throwable -> Log.e(TAG, "Error loading avatar", e) }) holder.loader.add(mConversationFacade.getAccountSubject(account.accountId) .flatMapObservable { acc -> acc.unreadConversations } - .observeOn(AndroidSchedulers.mainThread()) + .observeOn(DeviceUtils.uiScheduler) .subscribe { count -> if (count == 0) { BadgeUtils.detachBadgeDrawable(badgeDrawable, holder.binding.badgeAnchor) diff --git a/ring-android/app/src/main/java/cx/ring/client/ContactDetailsActivity.kt b/ring-android/app/src/main/java/cx/ring/client/ContactDetailsActivity.kt index 4cf68ed089c885d6256e51fc0ccdcc5d4d3b386f..6d17f9417dc163008a4d64ce0eb7ede8d7fe0416 100644 --- a/ring-android/app/src/main/java/cx/ring/client/ContactDetailsActivity.kt +++ b/ring-android/app/src/main/java/cx/ring/client/ContactDetailsActivity.kt @@ -56,13 +56,9 @@ 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.utils.AndroidFileUtils -import cx.ring.utils.BitmapUtils -import cx.ring.utils.ContentUriHandler -import cx.ring.utils.ConversationPath +import cx.ring.utils.* import cx.ring.views.AvatarDrawable import dagger.hilt.android.AndroidEntryPoint -import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.core.Single import io.reactivex.rxjava3.disposables.CompositeDisposable import io.reactivex.rxjava3.schedulers.Schedulers @@ -172,7 +168,7 @@ class ContactDetailsActivity : AppCompatActivity(), TabLayout.OnTabSelectedListe val preferences = getConversationPreferences(this, conversation.accountId, conversation.uri) mDisposableBag.add(mConversationFacade.observeConversation(conversation) - .observeOn(AndroidSchedulers.mainThread()) + .observeOn(DeviceUtils.uiScheduler) .doOnComplete { finish() } .subscribe({ vm -> binding.contactImage.setImageDrawable(AvatarDrawable.Builder() @@ -332,7 +328,7 @@ class ContactDetailsActivity : AppCompatActivity(), TabLayout.OnTabSelectedListe .withCircleCrop(true) .build(this) } - .observeOn(AndroidSchedulers.mainThread()) + .observeOn(DeviceUtils.uiScheduler) .subscribe({ avatar: AvatarDrawable -> mProfilePhoto?.setImageDrawable(avatar) }) { e: Throwable -> diff --git a/ring-android/app/src/main/java/cx/ring/client/HomeActivity.kt b/ring-android/app/src/main/java/cx/ring/client/HomeActivity.kt index 210a72e891ec96f0f5de1c3fd18554b38b054ef0..79488ee5860c3179d691dab44c8814562c7d392d 100644 --- a/ring-android/app/src/main/java/cx/ring/client/HomeActivity.kt +++ b/ring-android/app/src/main/java/cx/ring/client/HomeActivity.kt @@ -61,7 +61,6 @@ import cx.ring.utils.DeviceUtils import cx.ring.views.AvatarDrawable import cx.ring.views.AvatarFactory import dagger.hilt.android.AndroidEntryPoint -import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.core.Single import io.reactivex.rxjava3.disposables.CompositeDisposable import io.reactivex.rxjava3.schedulers.Schedulers @@ -265,7 +264,7 @@ class HomeActivity : AppCompatActivity(), Colorable, ContactPickerFragment.OnCon super.onStart() mDisposable.add( mAccountService.observableAccountList - .observeOn(AndroidSchedulers.mainThread()) + .observeOn(DeviceUtils.uiScheduler) .subscribe { accounts: List<Account> -> if (accounts.isEmpty()) { startActivity(Intent(this, AccountWizardActivity::class.java)) @@ -336,7 +335,7 @@ class HomeActivity : AppCompatActivity(), Colorable, ContactPickerFragment.OnCon fun startConversation(conversationId: String) { mDisposable.add(mAccountService.currentAccountSubject .firstElement() - .observeOn(AndroidSchedulers.mainThread()) + .observeOn(DeviceUtils.uiScheduler) .subscribe { account -> startConversation(account.accountId, Uri.fromString(conversationId)) }) @@ -486,7 +485,7 @@ class HomeActivity : AppCompatActivity(), Colorable, ContactPickerFragment.OnCon override fun onContactPicked(accountId: String, contacts: Set<Contact>) { mDisposable.add(mConversationFacade.createConversation(accountId, contacts) - .observeOn(AndroidSchedulers.mainThread()) + .observeOn(DeviceUtils.uiScheduler) .subscribe { conversation: Conversation -> startConversation(conversation.accountId, conversation.uri) }) diff --git a/ring-android/app/src/main/java/cx/ring/client/MediaViewerFragment.kt b/ring-android/app/src/main/java/cx/ring/client/MediaViewerFragment.kt index 73a478b05ffa5e34ce0e2760f3a6561fd99bdcb9..9be696aa78989d94926637d6a2b14078283edc8a 100644 --- a/ring-android/app/src/main/java/cx/ring/client/MediaViewerFragment.kt +++ b/ring-android/app/src/main/java/cx/ring/client/MediaViewerFragment.kt @@ -32,11 +32,8 @@ import com.bumptech.glide.Glide import com.google.android.material.bottomappbar.BottomAppBar import cx.ring.R import cx.ring.utils.AndroidFileUtils -import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers +import cx.ring.utils.DeviceUtils -/** - * A placeholder fragment containing a simple view. - */ class MediaViewerFragment : Fragment() { private var mUri: Uri? = null @@ -69,7 +66,7 @@ class MediaViewerFragment : Fragment() { if (requestCode == REQUEST_CODE_SAVE_FILE) { data?.data?.let { uri -> AndroidFileUtils.copyUri(requireContext().contentResolver, mUri!!, uri) - .observeOn(AndroidSchedulers.mainThread()) + .observeOn(DeviceUtils.uiScheduler) .subscribe({ Toast.makeText(context, R.string.file_saved_successfully, Toast.LENGTH_SHORT).show() }) { Toast.makeText(context, R.string.generic_error, Toast.LENGTH_SHORT).show() } } diff --git a/ring-android/app/src/main/java/cx/ring/client/RingtoneActivity.kt b/ring-android/app/src/main/java/cx/ring/client/RingtoneActivity.kt index 99d3582096759253c04eae10fcbc497422bea2fd..424e72ee6e2b6b5fadd01028e3bc61a5b1d8f766 100644 --- a/ring-android/app/src/main/java/cx/ring/client/RingtoneActivity.kt +++ b/ring-android/app/src/main/java/cx/ring/client/RingtoneActivity.kt @@ -42,8 +42,8 @@ import cx.ring.R import cx.ring.account.AccountEditionFragment import cx.ring.adapters.RingtoneAdapter import cx.ring.utils.AndroidFileUtils +import cx.ring.utils.DeviceUtils import dagger.hilt.android.AndroidEntryPoint -import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.disposables.Disposable import net.jami.model.Account import net.jami.model.ConfigKey @@ -314,7 +314,7 @@ class RingtoneActivity : AppCompatActivity() { or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)) cr.takePersistableUriPermission(uri, takeFlags) AndroidFileUtils.getCacheFile(this, uri) - .observeOn(AndroidSchedulers.mainThread()) + .observeOn(DeviceUtils.uiScheduler) .subscribe({ ringtone: File -> onFileFound(ringtone) }) { Toast.makeText(this, "Can't load ringtone !", Toast.LENGTH_SHORT).show() } diff --git a/ring-android/app/src/main/java/cx/ring/dependencyinjection/ServiceInjectionModule.kt b/ring-android/app/src/main/java/cx/ring/dependencyinjection/ServiceInjectionModule.kt index 2600fea9fa50b2f81805c085dbf77f185ed5a540..71326125cbad46e54c6f147746ff21578fab1a6b 100755 --- a/ring-android/app/src/main/java/cx/ring/dependencyinjection/ServiceInjectionModule.kt +++ b/ring-android/app/src/main/java/cx/ring/dependencyinjection/ServiceInjectionModule.kt @@ -21,12 +21,12 @@ package cx.ring.dependencyinjection import android.content.Context import cx.ring.services.* +import cx.ring.utils.DeviceUtils import dagger.Module import dagger.Provides import dagger.hilt.InstallIn import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.components.SingletonComponent -import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.core.Scheduler import net.jami.services.ConversationFacade import net.jami.services.* @@ -164,6 +164,6 @@ object ServiceInjectionModule { @Named("UiScheduler") @Singleton fun provideUiScheduler(): Scheduler { - return AndroidSchedulers.mainThread() + return DeviceUtils.uiScheduler } } \ No newline at end of file diff --git a/ring-android/app/src/main/java/cx/ring/fragments/CodecPreference.kt b/ring-android/app/src/main/java/cx/ring/fragments/CodecPreference.kt index c135d4665541104cd636195e92f560d07ab99b23..2b39e4a63f99f54b8d9665eefef2fe7d633ec703 100644 --- a/ring-android/app/src/main/java/cx/ring/fragments/CodecPreference.kt +++ b/ring-android/app/src/main/java/cx/ring/fragments/CodecPreference.kt @@ -89,17 +89,11 @@ internal class CodecPreference @JvmOverloads constructor(context: Context, attrs private class CodecAdapter constructor(private val mContext: Context) : BaseAdapter() { private val items = ArrayList<Codec>() - override fun getCount(): Int { - return items.size - } + override fun getCount(): Int = items.size - override fun getItem(position: Int): Codec { - return items[position] - } + override fun getItem(position: Int): Codec = items[position] - override fun getItemId(position: Int): Long { - return 0 - } + override fun getItemId(position: Int): Long = getItem(position).payload override fun getView(pos: Int, convertView: View?, parent: ViewGroup): View { val entryView: CodecView diff --git a/ring-android/app/src/main/java/cx/ring/fragments/ConversationFragment.kt b/ring-android/app/src/main/java/cx/ring/fragments/ConversationFragment.kt index 0140ee67b20f16d308ebcb77244f8e9877a97f87..0c06901a88806b220ef45c57fbe1d136a8d2f5d3 100644 --- a/ring-android/app/src/main/java/cx/ring/fragments/ConversationFragment.kt +++ b/ring-android/app/src/main/java/cx/ring/fragments/ConversationFragment.kt @@ -73,7 +73,6 @@ import cx.ring.utils.MediaButtonsHelper.MediaButtonsHelperCallback import cx.ring.views.AvatarDrawable import cx.ring.views.AvatarFactory import dagger.hilt.android.AndroidEntryPoint -import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.core.Completable import io.reactivex.rxjava3.core.Single import io.reactivex.rxjava3.disposables.CompositeDisposable @@ -121,7 +120,7 @@ class ConversationFragment : BaseSupportFragment<ConversationPresenter, Conversa registerForActivityResult(ActivityResultContracts.PickMultipleVisualMedia(8)) { uris -> for (uri in uris) { startFileSend(AndroidFileUtils.getCacheFile(requireContext(), uri) - .observeOn(AndroidSchedulers.mainThread()) + .observeOn(DeviceUtils.uiScheduler) .flatMapCompletable { file: File -> sendFile(file) }) } } @@ -590,7 +589,7 @@ class ConversationFragment : BaseSupportFragment<ConversationPresenter, Conversa private fun startFileSend(op: Completable): Disposable { setLoading(true) - return op.observeOn(AndroidSchedulers.mainThread()) + return op.observeOn(DeviceUtils.uiScheduler) .doFinally { setLoading(false) } .subscribe({}) { e -> Log.e(TAG, "startFileSend: not able to create cache file", e) @@ -607,13 +606,13 @@ class ConversationFragment : BaseSupportFragment<ConversationPresenter, Conversa for (i in 0 until clipData.itemCount) { val uri = clipData.getItemAt(i).uri startFileSend(AndroidFileUtils.getCacheFile(requireContext(), uri) - .observeOn(AndroidSchedulers.mainThread()) + .observeOn(DeviceUtils.uiScheduler) .flatMapCompletable { file: File -> sendFile(file) }) } } else { resultData.data?.let { uri -> startFileSend(AndroidFileUtils.getCacheFile(requireContext(), uri) - .observeOn(AndroidSchedulers.mainThread()) + .observeOn(DeviceUtils.uiScheduler) .flatMapCompletable { file: File -> sendFile(file) }) } } @@ -657,7 +656,7 @@ class ConversationFragment : BaseSupportFragment<ConversationPresenter, Conversa val path = mCurrentFileAbsolutePath ?: return val cr = context?.contentResolver ?: return mCompositeDisposable.add(AndroidFileUtils.copyFileToUri(cr, File(path), data) - .observeOn(AndroidSchedulers.mainThread()) + .observeOn(DeviceUtils.uiScheduler) .subscribe({ Toast.makeText(context, R.string.file_saved_successfully, Toast.LENGTH_SHORT).show() }) { Toast.makeText(context, R.string.generic_error, Toast.LENGTH_SHORT).show() }) } diff --git a/ring-android/app/src/main/java/cx/ring/fragments/ConversationGalleryFragment.kt b/ring-android/app/src/main/java/cx/ring/fragments/ConversationGalleryFragment.kt index 9b2b735358d38f859837aee7934d56d59c87c5d2..01d99f3886d4e0246a509e50d1c477c48e8a4a76 100644 --- a/ring-android/app/src/main/java/cx/ring/fragments/ConversationGalleryFragment.kt +++ b/ring-android/app/src/main/java/cx/ring/fragments/ConversationGalleryFragment.kt @@ -9,8 +9,8 @@ import androidx.fragment.app.Fragment import cx.ring.adapters.ConversationMediaGalleryAdapter import cx.ring.databinding.FragConversationGalleryBinding import cx.ring.utils.ConversationPath +import cx.ring.utils.DeviceUtils import dagger.hilt.android.AndroidEntryPoint -import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.disposables.CompositeDisposable import net.jami.model.DataTransfer import net.jami.model.Uri @@ -44,7 +44,7 @@ class ConversationGalleryFragment : Fragment() { type = "application/data-transfer+json" ) .map { results -> results.results.mapNotNull { i -> if (i is DataTransfer /*&& i.isComplete*/) i else null } } - .observeOn(AndroidSchedulers.mainThread()) + .observeOn(DeviceUtils.uiScheduler) .subscribe { adapter?.addSearchResults(it) binding!!.placeholder.isVisible = false diff --git a/ring-android/app/src/main/java/cx/ring/fragments/ConversationMembersFragment.kt b/ring-android/app/src/main/java/cx/ring/fragments/ConversationMembersFragment.kt index 88c22d8a9551dbbe99dd077894a6d8e045bc611a..1912a9fec3767e6e5d695eed02777ef6daa38aa3 100644 --- a/ring-android/app/src/main/java/cx/ring/fragments/ConversationMembersFragment.kt +++ b/ring-android/app/src/main/java/cx/ring/fragments/ConversationMembersFragment.kt @@ -28,9 +28,9 @@ import cx.ring.client.ContactDetailsActivity import cx.ring.databinding.FragConversationMembersBinding import cx.ring.databinding.ItemContactHorizontalBinding import cx.ring.utils.ConversationPath +import cx.ring.utils.DeviceUtils import cx.ring.views.AvatarFactory import dagger.hilt.android.AndroidEntryPoint -import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.disposables.CompositeDisposable import net.jami.model.Contact import net.jami.model.ContactViewModel @@ -66,7 +66,7 @@ class ConversationMembersFragment : Fragment() { .startConversation(path.accountId, path.conversationUri) .flatMapObservable { conversation -> conversation.contactUpdates } .flatMap { contacts -> contactService.observeContact(path.accountId, contacts, false) } - .observeOn(AndroidSchedulers.mainThread()) + .observeOn(DeviceUtils.uiScheduler) .subscribe { val adapter = binding!!.contactList.adapter if (adapter == null) { diff --git a/ring-android/app/src/main/java/cx/ring/fragments/HomeFragment.kt b/ring-android/app/src/main/java/cx/ring/fragments/HomeFragment.kt index af07e9a558242b0830f5600fe97dde0b03f6a5e9..46b7d0d12beb5113cea7f0c26283125801711151 100644 --- a/ring-android/app/src/main/java/cx/ring/fragments/HomeFragment.kt +++ b/ring-android/app/src/main/java/cx/ring/fragments/HomeFragment.kt @@ -46,8 +46,8 @@ import cx.ring.client.HomeActivity import cx.ring.contactrequests.ContactRequestsFragment import cx.ring.databinding.FragHomeBinding import cx.ring.mvp.BaseSupportFragment +import cx.ring.utils.DeviceUtils import dagger.hilt.android.AndroidEntryPoint -import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.disposables.CompositeDisposable import net.jami.home.HomePresenter import net.jami.home.HomeView @@ -229,16 +229,16 @@ class HomeFragment : BaseSupportFragment<HomePresenter, HomeView>(), mDisposable.add(mAccountService .currentAccountSubject .switchMap { obj -> obj.unreadPending } - .observeOn(AndroidSchedulers.mainThread()) + .observeOn(DeviceUtils.uiScheduler) .subscribe { count -> setBadge(TAB_INVITATIONS, count) }) mDisposable.add(mAccountService .currentAccountSubject .switchMap { obj -> obj.unreadConversations } - .observeOn(AndroidSchedulers.mainThread()) + .observeOn(DeviceUtils.uiScheduler) .subscribe { count -> setBadge(TAB_CONVERSATIONS, count) }) mDisposable.add( mAccountService.observableAccountList - .observeOn(AndroidSchedulers.mainThread()) + .observeOn(DeviceUtils.uiScheduler) .subscribe({ accounts -> mAccountAdapter?.apply { clear() diff --git a/ring-android/app/src/main/java/cx/ring/fragments/MediaPreferenceFragment.kt b/ring-android/app/src/main/java/cx/ring/fragments/MediaPreferenceFragment.kt index 50ff53bbf0d4ab7da89ffb28e6d06dbe03b93bdc..e8245192f006efb2dff2fe6cc7922d617fa52ccd 100644 --- a/ring-android/app/src/main/java/cx/ring/fragments/MediaPreferenceFragment.kt +++ b/ring-android/app/src/main/java/cx/ring/fragments/MediaPreferenceFragment.kt @@ -24,6 +24,8 @@ package cx.ring.fragments import android.content.DialogInterface import android.content.Intent import android.os.Bundle +import android.util.Log +import android.view.ViewGroup import androidx.preference.Preference import androidx.preference.TwoStatePreference import com.google.android.material.dialog.MaterialAlertDialogBuilder @@ -50,6 +52,7 @@ class MediaPreferenceFragment : BasePreferenceFragment<MediaPreferencePresenter> private var videoCodecsPref: CodecPreference? = null private val changeCodecListener = Preference.OnPreferenceChangeListener { _, _ -> + Log.w(TAG, "changeCodecListener") val audio = audioCodecsPref!!.activeCodecList val video = videoCodecsPref!!.activeCodecList val newOrder = ArrayList<Long>(audio.size + video.size) @@ -60,11 +63,16 @@ class MediaPreferenceFragment : BasePreferenceFragment<MediaPreferencePresenter> } override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { + Log.w(TAG, "onCreatePreferences") super.onCreatePreferences(savedInstanceState, rootKey) val accountId = requireArguments().getString(AccountEditionFragment.ACCOUNT_ID_KEY)!! addPreferencesFromResource(R.xml.account_media_prefs) + Log.w(TAG, "onCreatePreferences2") + // (view as ViewGroup).layoutTransition = null; audioCodecsPref = findPreference("Account.audioCodecs") videoCodecsPref = findPreference("Account.videoCodecs") + audioCodecsPref!!.onPreferenceChangeListener = changeCodecListener + videoCodecsPref!!.onPreferenceChangeListener = changeCodecListener findPreference<Preference>("ringtone")?.apply { onPreferenceClickListener = Preference.OnPreferenceClickListener { val i = Intent(requireActivity(), RingtoneActivity::class.java) @@ -73,16 +81,15 @@ class MediaPreferenceFragment : BasePreferenceFragment<MediaPreferencePresenter> true } } + findPreference<Preference>(ConfigKey.VIDEO_ENABLED.key)?.onPreferenceChangeListener = changeVideoPreferenceListener presenter.init(accountId) } override fun accountChanged(account: Account, audioCodec: ArrayList<Codec>, videoCodec: ArrayList<Codec>) { + Log.w(TAG, "accountChanged ${audioCodec.size} ${videoCodec.size}") setPreferenceDetails(account.config) audioCodecsPref!!.setCodecs(audioCodec) videoCodecsPref!!.setCodecs(videoCodec) - addPreferenceListener(ConfigKey.VIDEO_ENABLED, changeVideoPreferenceListener) - audioCodecsPref!!.onPreferenceChangeListener = changeCodecListener - videoCodecsPref!!.onPreferenceChangeListener = changeCodecListener } override fun displayWrongFileFormatDialog() { @@ -110,6 +117,7 @@ class MediaPreferenceFragment : BasePreferenceFragment<MediaPreferencePresenter> } override fun refresh(account: Account) { + Log.w(TAG, "refresh") setPreferenceDetails(account.config) if (null != listView && null != listView.adapter) { listView.adapter!!.notifyDataSetChanged() @@ -123,6 +131,7 @@ class MediaPreferenceFragment : BasePreferenceFragment<MediaPreferencePresenter> } private fun setPreferenceDetails(details: AccountConfig) { + Log.w(TAG, "setPreferenceDetails") for (confKey in details.keys) { val pref = findPreference<Preference>(confKey.key) if (pref != null) { @@ -138,14 +147,6 @@ class MediaPreferenceFragment : BasePreferenceFragment<MediaPreferencePresenter> } } - private fun addPreferenceListener(details: AccountConfig, listener: Preference.OnPreferenceChangeListener) { - for (confKey in details.keys) addPreferenceListener(confKey, listener) - } - - private fun addPreferenceListener(key: ConfigKey, listener: Preference.OnPreferenceChangeListener) { - findPreference<Preference>(key.key)?.onPreferenceChangeListener = listener - } - companion object { val TAG = MediaPreferenceFragment::class.simpleName!! private const val SELECT_RINGTONE_PATH = 40 diff --git a/ring-android/app/src/main/java/cx/ring/settings/AccountFragment.kt b/ring-android/app/src/main/java/cx/ring/settings/AccountFragment.kt index 5a2a1b88f721872052d6d1d11fd6501068f830e3..8e23387358798788d711e3d7b643fedc5d3fd43f 100644 --- a/ring-android/app/src/main/java/cx/ring/settings/AccountFragment.kt +++ b/ring-android/app/src/main/java/cx/ring/settings/AccountFragment.kt @@ -33,8 +33,8 @@ import cx.ring.account.AccountEditionFragment import cx.ring.account.JamiAccountSummaryFragment import cx.ring.client.HomeActivity import cx.ring.databinding.FragAccountBinding +import cx.ring.utils.DeviceUtils import dagger.hilt.android.AndroidEntryPoint -import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.disposables.CompositeDisposable import net.jami.model.Account import net.jami.services.AccountService @@ -66,7 +66,7 @@ class AccountFragment : Fragment(), OnScrollChangedListener { setHasOptionsMenu(true) val accountId = requireArguments().getString(AccountEditionFragment.ACCOUNT_ID_KEY)!! mDisposable.add(mAccountService.getAccountSingle(accountId) - .observeOn(AndroidSchedulers.mainThread()) + .observeOn(DeviceUtils.uiScheduler) .subscribe({ account: Account -> mBinding?.let { binding -> binding.settingsChangePassword.visibility = if (account.hasManager()) View.GONE else View.VISIBLE diff --git a/ring-android/app/src/main/java/cx/ring/utils/DeviceUtils.kt b/ring-android/app/src/main/java/cx/ring/utils/DeviceUtils.kt index f969355a78c4a7dab593e66b458648119245c086..3f1b491cea5f0cae0748dbbc24a2377cb1a4cd11 100644 --- a/ring-android/app/src/main/java/cx/ring/utils/DeviceUtils.kt +++ b/ring-android/app/src/main/java/cx/ring/utils/DeviceUtils.kt @@ -22,7 +22,11 @@ package cx.ring.utils import android.app.UiModeManager import android.content.Context import android.content.res.Configuration +import android.os.Handler +import android.os.Looper import cx.ring.R +import io.reactivex.rxjava3.core.Scheduler +import io.reactivex.rxjava3.schedulers.Schedulers object DeviceUtils { fun isTv(context: Context): Boolean { @@ -33,4 +37,16 @@ object DeviceUtils { fun isTablet(context: Context): Boolean { return context.resources.getBoolean(R.bool.isTablet) } + + private val uiThread = Looper.getMainLooper().thread + private val uiHandler = Handler(Looper.getMainLooper()) + + val uiScheduler: Scheduler = Schedulers.from { + if (Thread.currentThread() == uiThread) { + it.run() + } else { + uiHandler.post(it) + } + } + } \ No newline at end of file diff --git a/ring-android/app/src/main/java/cx/ring/viewholders/SmartListViewHolder.kt b/ring-android/app/src/main/java/cx/ring/viewholders/SmartListViewHolder.kt index 2e10d8b1eddc9daedf31ba0c5305624b82b1cb8b..5d55ed94271cbb30e11aa3b91fe198d93069a051 100644 --- a/ring-android/app/src/main/java/cx/ring/viewholders/SmartListViewHolder.kt +++ b/ring-android/app/src/main/java/cx/ring/viewholders/SmartListViewHolder.kt @@ -30,9 +30,9 @@ import androidx.recyclerview.widget.RecyclerView import cx.ring.R import cx.ring.databinding.ItemSmartlistBinding import cx.ring.databinding.ItemSmartlistHeaderBinding +import cx.ring.utils.DeviceUtils import cx.ring.utils.TextUtils import cx.ring.views.AvatarDrawable -import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.disposables.CompositeDisposable import net.jami.model.* import net.jami.services.ConversationFacade @@ -87,7 +87,7 @@ class SmartListViewHolder : RecyclerView.ViewHolder { } compositeDisposable.add(conversation.currentStateSubject - .observeOn(AndroidSchedulers.mainThread()) + .observeOn(DeviceUtils.uiScheduler) .subscribe { state -> val fade = !binding.convLastItem.isVisible || binding.convLastItem.text.isBlank() val lastEvent = state.first @@ -119,7 +119,7 @@ class SmartListViewHolder : RecyclerView.ViewHolder { compositeDisposable.add(conversationFacade.observeConversation(conversation, true) .onErrorComplete() - .observeOn(AndroidSchedulers.mainThread()) + .observeOn(DeviceUtils.uiScheduler) .subscribe { conversationItemViewModel -> binding.convParticipant.text = conversationItemViewModel.title val fade = binding.photo.drawable !is AvatarDrawable @@ -132,7 +132,7 @@ class SmartListViewHolder : RecyclerView.ViewHolder { }) compositeDisposable.add(conversation.getVisible() - .observeOn(AndroidSchedulers.mainThread()) + .observeOn(DeviceUtils.uiScheduler) .subscribe { activated -> binding.itemLayout.isActivated = activated }) } } diff --git a/ring-android/app/src/main/java/cx/ring/views/VideoSinkView.kt b/ring-android/app/src/main/java/cx/ring/views/VideoSinkView.kt index 56531172b31b800c0e1c51e47e3d495c94852098..b9d90a1b034f6abfedb7febc8e35ce258bc6454e 100644 --- a/ring-android/app/src/main/java/cx/ring/views/VideoSinkView.kt +++ b/ring-android/app/src/main/java/cx/ring/views/VideoSinkView.kt @@ -12,9 +12,9 @@ import android.view.TextureView import androidx.core.view.isVisible import cx.ring.R import cx.ring.application.JamiApplication +import cx.ring.utils.DeviceUtils import cx.ring.utils.ScalableType import cx.ring.utils.ScaleManager -import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers import io.reactivex.rxjava3.disposables.CompositeDisposable import net.jami.daemon.JamiServiceJNI import net.jami.services.HardwareService @@ -106,11 +106,11 @@ class VideoSinkView @JvmOverloads constructor(context: Context, attrs: Attribute val nw = nativeWindow if (nw != -1L) { disposableBag.add(hardwareService!!.connectSink(id, nw) - .observeOn(AndroidSchedulers.mainThread()) + .observeOn(DeviceUtils.uiScheduler) .subscribe { size -> setAspectRatio(size.first, size.second) }) } else { disposableBag.add(hardwareService!!.getSinkSize(id) - .observeOn(AndroidSchedulers.mainThread()) + .observeOn(DeviceUtils.uiScheduler) .subscribe { c -> setAspectRatio(c.first, c.second) }) } } diff --git a/ring-android/libjamiclient/src/main/kotlin/net/jami/services/AccountService.kt b/ring-android/libjamiclient/src/main/kotlin/net/jami/services/AccountService.kt index b071b8bf23892ae0a3524c0fc0fae3bbc61a3056..7e5c20fd442dbb2f003897d0356fc61a87f04a84 100644 --- a/ring-android/libjamiclient/src/main/kotlin/net/jami/services/AccountService.kt +++ b/ring-android/libjamiclient/src/main/kotlin/net/jami/services/AccountService.kt @@ -705,7 +705,7 @@ class AccountService( val activePayloads = JamiService.getActiveCodecList(accountId) JamiService.getCodecList() .map { Codec(it, JamiService.getCodecDetails(accountId, it), activePayloads.contains(it)) } - }.subscribeOn(Schedulers.from(mExecutor)) + } fun validateCertificatePath( accountID: String, diff --git a/ring-android/libjamiclient/src/main/kotlin/net/jami/settings/MediaPreferencePresenter.kt b/ring-android/libjamiclient/src/main/kotlin/net/jami/settings/MediaPreferencePresenter.kt index 89f631cd058ad46aafa2a149f65fa3131741ce15..4bead7efd8692f73d2fcc307997fedba63dfe86e 100644 --- a/ring-android/libjamiclient/src/main/kotlin/net/jami/settings/MediaPreferencePresenter.kt +++ b/ring-android/libjamiclient/src/main/kotlin/net/jami/settings/MediaPreferencePresenter.kt @@ -33,18 +33,17 @@ import javax.inject.Named class MediaPreferencePresenter @Inject constructor( private var mAccountService: AccountService, - private var mDeviceRuntimeService: DeviceRuntimeService, @Named("UiScheduler") private var mUiScheduler: Scheduler ) : RootPresenter<MediaPreferenceView>() { private var mAccount: Account? = null fun init(accountId: String) { - mAccount = mAccountService.getAccount(accountId) mCompositeDisposable.clear() mCompositeDisposable.add(mAccountService .getObservableAccount(accountId) .switchMapSingle { account: Account -> + mAccount = account mAccountService.getCodecList(accountId) .observeOn(mUiScheduler) .doOnSuccess { codecList: List<Codec> ->