diff --git a/ring-android/app/src/main/java/cx/ring/adapters/ConfParticipantAdapter.kt b/ring-android/app/src/main/java/cx/ring/adapters/ConfParticipantAdapter.kt index e498a044d5035bcc5a96a224e1ba9cb8fb00fd82..d343a748c4c831bf9fb0a95c6e1e0dfc1b0bab81 100644 --- a/ring-android/app/src/main/java/cx/ring/adapters/ConfParticipantAdapter.kt +++ b/ring-android/app/src/main/java/cx/ring/adapters/ConfParticipantAdapter.kt @@ -19,6 +19,7 @@ */ package cx.ring.adapters +import android.text.TextUtils import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -30,68 +31,74 @@ import cx.ring.views.AvatarDrawable import cx.ring.views.ParticipantView import net.jami.model.Call import net.jami.model.Conference.ParticipantInfo +import java.util.* -class ConfParticipantAdapter(private val onSelectedCallback: ConfParticipantSelected) : +class ConfParticipantAdapter(private var calls: List<ParticipantInfo>, private val onSelectedCallback: ConfParticipantSelected) : RecyclerView.Adapter<ParticipantView>() { - private var calls: List<ParticipantInfo>? = null + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ParticipantView { return ParticipantView(ItemConferenceParticipantBinding.inflate(LayoutInflater.from(parent.context), parent, false)) } override fun onBindViewHolder(holder: ParticipantView, position: Int) { - val info = calls!![position] + val info = calls[position] val contact = info.contact val context = holder.itemView.context val call = info.call - if (call != null && call.callStatus != Call.CallStatus.CURRENT) { - holder.binding.displayName.text = String.format("%s\n%s", contact.displayName, context.getText(CallFragment.callStateToHumanState(call.callStatus))) + val displayName = TextUtils.ellipsize(contact.displayName, + holder.binding.displayName.paint, + holder.binding.displayName.maxWidth.toFloat(), + TextUtils.TruncateAt.MIDDLE) + if (call != null && info.pending) { + holder.binding.displayName.text = String.format("%s\n%s", displayName, context.getText(CallFragment.callStateToHumanState(call.callStatus))) holder.binding.photo.alpha = .5f } else { - holder.binding.displayName.text = contact.displayName + holder.binding.displayName.text = displayName holder.binding.photo.alpha = 1f } holder.disposable?.dispose() holder.binding.photo.setImageDrawable(AvatarDrawable.Builder() - .withContact(contact) - .withCircleCrop(true) - .withPresence(false) - .build(context)) - /*; - holder.disposable = AvatarFactory.getAvatar(context, contact) + .withContact(contact) + .withCircleCrop(true) + .withPresence(false) + .build(context)) + + /*holder.disposable = AvatarFactory.getAvatar(context, contact) .subscribe(holder.binding.photo::setImageDrawable);*/ holder.itemView.setOnClickListener { view: View -> onSelectedCallback.onParticipantSelected(view, info) } } + override fun getItemId(position: Int): Long { + val info = calls[position] + return Objects.hash(info.contact.uri, info.call?.daemonIdString).toLong() + } + override fun getItemCount(): Int { - return if (calls == null) 0 else calls!!.size + return calls.size } fun updateFromCalls(contacts: List<ParticipantInfo>) { val oldCalls = calls calls = contacts - if (oldCalls != null) { - DiffUtil.calculateDiff(object : DiffUtil.Callback() { - override fun getOldListSize(): Int { - return oldCalls.size - } + DiffUtil.calculateDiff(object : DiffUtil.Callback() { + override fun getOldListSize(): Int { + return oldCalls.size + } - override fun getNewListSize(): Int { - return contacts.size - } + override fun getNewListSize(): Int { + return contacts.size + } - override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { - return oldCalls[oldItemPosition] === contacts[newItemPosition] - } + override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { + return oldCalls[oldItemPosition].contact === contacts[newItemPosition].contact + } - override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { - return false - } - }).dispatchUpdatesTo(this) - } else { - notifyDataSetChanged() - } + override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { + return false + } + }).dispatchUpdatesTo(this) } interface ConfParticipantSelected { diff --git a/ring-android/app/src/main/java/cx/ring/fragments/CallFragment.kt b/ring-android/app/src/main/java/cx/ring/fragments/CallFragment.kt index 1c6bbfb7d162c9e2caeec645073162ec68ed7ec9..69b49bb8d9803c8abb200c15a240e4151e5568a8 100644 --- a/ring-android/app/src/main/java/cx/ring/fragments/CallFragment.kt +++ b/ring-android/app/src/main/java/cx/ring/fragments/CallFragment.kt @@ -84,7 +84,6 @@ import io.reactivex.rxjava3.disposables.CompositeDisposable import net.jami.call.CallPresenter import net.jami.call.CallView import net.jami.daemon.JamiService -import net.jami.model.Call import net.jami.model.Call.CallStatus import net.jami.model.Conference.ParticipantInfo import net.jami.model.Contact @@ -486,25 +485,18 @@ class CallFragment : BaseSupportFragment<CallPresenter, CallView>(), CallView, params.removeRule(RelativeLayout.ALIGN_PARENT_BOTTOM) params.addRule(RelativeLayout.ALIGN_PARENT_TOP) params.addRule(RelativeLayout.ALIGN_PARENT_LEFT) - params.setMargins( - v.x.toInt(), - v.y.toInt(), + params.setMargins(v.x.toInt(), v.y.toInt(), parent.width - (v.x.toInt() + v.width), - parent.height - (v.y - .toInt() + v.height) - ) + parent.height - (v.y.toInt() + v.height)) v.layoutParams = params return@setOnTouchListener true } else if (action == MotionEvent.ACTION_MOVE) { if (previewDrag != null) { val currentXPosition = params.leftMargin + (event.x - previewDrag!!.x).toInt() val currentYPosition = params.topMargin + (event.y - previewDrag!!.y).toInt() - params.setMargins( - currentXPosition, - currentYPosition, + params.setMargins(currentXPosition, currentYPosition, -(currentXPosition + v.width - event.x.toInt()), - -(currentYPosition + v.height - event.y.toInt()) - ) + -(currentYPosition + v.height - event.y.toInt())) v.layoutParams = params val outPosition = binding.pluginPreviewContainer.width * 0.85f var drapOut = 0f @@ -788,7 +780,11 @@ class CallFragment : BaseSupportFragment<CallPresenter, CallView>(), CallView, binding?.apply { callControlGroup.visibility = if (display) View.VISIBLE else View.GONE callHangupBtn.visibility = if (display) View.VISIBLE else View.GONE - confControlGroup.visibility = if (mConferenceMode && display) View.VISIBLE else View.GONE + confControlGroup.visibility = when { + mConferenceMode && display -> View.VISIBLE + mConferenceMode -> View.INVISIBLE + else -> View.GONE + } } } @@ -817,65 +813,63 @@ class CallFragment : BaseSupportFragment<CallPresenter, CallView>(), CallView, override fun updateTime(duration: Long) { binding?.let { binding -> - binding.callStatusTxt.text = if (duration <= 0) null else String.format( - Locale.getDefault(), - "%d:%02d:%02d", + binding.callStatusTxt.text = if (duration <= 0) null else String.format("%d:%02d:%02d", duration / 3600, duration % 3600 / 60, - duration % 60 - ) + duration % 60) } } @SuppressLint("RestrictedApi") - override fun updateContactBubble(contacts: List<Call>) { - Log.w(TAG, "updateContactBubble " + contacts.size) - val username = if (contacts.size > 1) - "Conference with " + contacts.size + " people" - else contacts[0].contact!!.displayName - val displayName = if (contacts.size > 1) null else contacts[0].contact!!.displayName - val hasProfileName = displayName != null && !displayName.contentEquals(username) - val activity = activity as AppCompatActivity? - if (activity != null) { - val ab = activity.supportActionBar - if (ab != null) { - if (hasProfileName) { - ab.title = displayName - ab.subtitle = username - } else { - ab.title = username - ab.subtitle = null + override fun updateConfInfo(participantInfo: List<ParticipantInfo>) { + Log.w(TAG, "updateConfInfo $participantInfo") + val binding = binding ?: return + mConferenceMode = participantInfo.size > 1 + binding.participantLabelContainer.removeAllViews() + if (participantInfo.isNotEmpty()) { + val username = if (participantInfo.size > 1) + "Conference with ${participantInfo.size} people" + else participantInfo[0].contact.displayName + val displayName = if (participantInfo.size > 1) null else participantInfo[0].contact.displayName + val hasProfileName = displayName != null && !displayName.contentEquals(username) + val activity = activity as AppCompatActivity? + if (activity != null) { + val ab = activity.supportActionBar + if (ab != null) { + if (hasProfileName) { + ab.title = displayName + ab.subtitle = username + } else { + ab.title = username + ab.subtitle = null + } + ab.setDisplayShowTitleEnabled(true) + } + val call = participantInfo[0].call + if (call != null) { + val conversationUri = if (call.conversationId != null) + Uri(Uri.SWARM_SCHEME, call.conversationId!!) + else call.contact!!.conversationUri.blockingFirst() + activity.intent = Intent(Intent.ACTION_VIEW, + ConversationPath.toUri(call.account!!, conversationUri), context, CallActivity::class.java) + .apply { putExtra(NotificationService.KEY_CALL_ID, call.confId ?: call.daemonIdString) } } - ab.setDisplayShowTitleEnabled(true) } - val call = contacts[0] - val conversationUri = if (call.conversationId != null) Uri(Uri.SWARM_SCHEME, call.conversationId!!) else call.contact!!.conversationUri.blockingFirst() - activity.intent = Intent(Intent.ACTION_VIEW, ConversationPath.toUri(call.account!!, conversationUri)) - } - if (hasProfileName) { - binding!!.contactBubbleNumTxt.visibility = View.VISIBLE - binding!!.contactBubbleTxt.text = displayName - binding!!.contactBubbleNumTxt.text = username - } else { - binding!!.contactBubbleNumTxt.visibility = View.GONE - binding!!.contactBubbleTxt.text = username - } - binding!!.contactBubble.setImageDrawable( - AvatarDrawable.Builder() - .withContact(contacts[0].contact) + if (hasProfileName) { + binding.contactBubbleNumTxt.visibility = View.VISIBLE + binding.contactBubbleTxt.text = displayName + binding.contactBubbleNumTxt.text = username + } else { + binding.contactBubbleNumTxt.visibility = View.GONE + binding.contactBubbleTxt.text = username + } + binding.contactBubble.setImageDrawable(AvatarDrawable.Builder() + .withContact(participantInfo[0].contact) .withCircleCrop(true) .withPresence(false) - .build(requireActivity()) - ) - } + .build(requireActivity())) - @SuppressLint("RestrictedApi") - override fun updateConfInfo(participantInfo: List<ParticipantInfo>) { - Log.w(TAG, "updateConfInfo $participantInfo") - mConferenceMode = participantInfo.size > 1 - binding!!.participantLabelContainer.removeAllViews() - if (participantInfo.isNotEmpty()) { - val inflater = LayoutInflater.from(binding!!.participantLabelContainer.context) + val inflater = LayoutInflater.from(binding.participantLabelContainer.context) for (i in participantInfo) { val displayName = i.contact.displayName if (!TextUtils.isEmpty(displayName)) { @@ -889,60 +883,59 @@ class CallFragment : BaseSupportFragment<CallPresenter, CallView>(), CallView, label.participantName.text = displayName label.moderator.visibility = if (i.isModerator) View.VISIBLE else View.GONE label.mute.visibility = if (i.audioMuted) View.VISIBLE else View.GONE - binding!!.participantLabelContainer.addView(label.root, params) + binding.participantLabelContainer.addView(label.root, params) } } } - binding!!.participantLabelContainer.visibility = - if (participantInfo.isEmpty()) View.GONE else View.VISIBLE - if (participantInfo.isEmpty() || participantInfo.size < 2) { - binding!!.confControlGroup.visibility = View.GONE + binding.participantLabelContainer.visibility = if (participantInfo.isEmpty()) View.GONE else View.VISIBLE + if (!mConferenceMode) { + binding.confControlGroup.visibility = View.GONE } else { - binding!!.confControlGroup.visibility = View.VISIBLE - if (confAdapter == null) { - confAdapter = - ConfParticipantAdapter(object : ConfParticipantSelected { - override fun onParticipantSelected(view: View, contact: ParticipantInfo) { - val maximized = presenter.isMaximized(contact) - val popup = PopupMenu(view.context, view) - popup.inflate(R.menu.conference_participant_actions) - popup.setOnMenuItemClickListener { item -> - when (item.itemId) { - R.id.conv_contact_details -> presenter.openParticipantContact(contact) - R.id.conv_contact_hangup -> presenter.hangupParticipant(contact) - R.id.conv_mute -> presenter.muteParticipant(contact, !contact.audioMuted) - R.id.conv_contact_maximize -> presenter.maximizeParticipant(contact) - else -> return@setOnMenuItemClickListener false - } - true - } - val menu = popup.menu as MenuBuilder - val maxItem = menu.findItem(R.id.conv_contact_maximize) - val muteItem = menu.findItem(R.id.conv_mute) - if (maximized) { - maxItem.setTitle(R.string.action_call_minimize) - maxItem.setIcon(R.drawable.baseline_close_fullscreen_24) - } else { - maxItem.setTitle(R.string.action_call_maximize) - maxItem.setIcon(R.drawable.baseline_open_in_full_24) - } - if (!contact.audioMuted) { - muteItem.setTitle(R.string.action_call_mute) - muteItem.setIcon(R.drawable.baseline_mic_off_24) - } else { - muteItem.setTitle(R.string.action_call_unmute) - muteItem.setIcon(R.drawable.baseline_mic_24) - } - val menuHelper = MenuPopupHelper(view.context, menu, view) - menuHelper.gravity = Gravity.END - menuHelper.setForceShowIcon(true) - menuHelper.show() + binding.confControlGroup.visibility = View.VISIBLE + confAdapter?.apply { updateFromCalls(participantInfo) } + // Create new adapter + ?: ConfParticipantAdapter(participantInfo, object : ConfParticipantSelected { + override fun onParticipantSelected(view: View, contact: ParticipantInfo) { + val maximized = presenter.isMaximized(contact) + val popup = PopupMenu(view.context, view) + popup.inflate(R.menu.conference_participant_actions) + popup.setOnMenuItemClickListener { item -> + when (item.itemId) { + R.id.conv_contact_details -> presenter.openParticipantContact(contact) + R.id.conv_contact_hangup -> presenter.hangupParticipant(contact) + R.id.conv_mute -> presenter.muteParticipant(contact, !contact.audioMuted) + R.id.conv_contact_maximize -> presenter.maximizeParticipant(contact) + else -> return@setOnMenuItemClickListener false } - }) + true + } + val menu = popup.menu as MenuBuilder + val maxItem = menu.findItem(R.id.conv_contact_maximize) + val muteItem = menu.findItem(R.id.conv_mute) + if (maximized) { + maxItem.setTitle(R.string.action_call_minimize) + maxItem.setIcon(R.drawable.baseline_close_fullscreen_24) + } else { + maxItem.setTitle(R.string.action_call_maximize) + maxItem.setIcon(R.drawable.baseline_open_in_full_24) + } + if (!contact.audioMuted) { + muteItem.setTitle(R.string.action_call_mute) + muteItem.setIcon(R.drawable.baseline_mic_off_24) + } else { + muteItem.setTitle(R.string.action_call_unmute) + muteItem.setIcon(R.drawable.baseline_mic_24) + } + val menuHelper = MenuPopupHelper(view.context, menu, view) + menuHelper.gravity = Gravity.END + menuHelper.setForceShowIcon(true) + menuHelper.show() + } + }).apply { + setHasStableIds(true) + confAdapter = this + binding.confControlGroup.adapter = this } - confAdapter!!.updateFromCalls(participantInfo) - if (binding!!.confControlGroup.adapter == null) - binding!!.confControlGroup.adapter = confAdapter } } @@ -1114,15 +1107,12 @@ class CallFragment : BaseSupportFragment<CallPresenter, CallView>(), CallView, override fun goToConversation(accountId: String, conversationId: Uri) { val context = requireContext() if (isTablet(context)) { - startActivity( - Intent(DRingService.ACTION_CONV_ACCEPT, ConversationPath.toUri(accountId, conversationId), context, HomeActivity::class.java) - ) + startActivity(Intent(Intent.ACTION_VIEW, ConversationPath.toUri(accountId, conversationId), context, HomeActivity::class.java)) } else { startActivityForResult( Intent(Intent.ACTION_VIEW, ConversationPath.toUri(accountId, conversationId), context, ConversationActivity::class.java) .setFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT), - HomeActivity.REQUEST_CODE_CONVERSATION - ) + HomeActivity.REQUEST_CODE_CONVERSATION) } } @@ -1131,28 +1121,25 @@ class CallFragment : BaseSupportFragment<CallPresenter, CallView>(), CallView, } override fun goToContact(accountId: String, contact: Contact) { - startActivity( - Intent(Intent.ACTION_VIEW, ConversationPath.toUri(accountId, contact.uri)) - .setClass(requireContext(), ContactDetailsActivity::class.java) - ) + startActivity(Intent(Intent.ACTION_VIEW, ConversationPath.toUri(accountId, contact.uri), requireContext(), ContactDetailsActivity::class.java)) } /** * Checks if permissions are accepted for camera and microphone. Takes into account whether call is incoming and outgoing, and requests permissions if not available. * Initializes the call if permissions are accepted. * - * @param isIncoming true if call is incoming, false for outgoing + * @param acceptIncomingCall true if call is incoming, false for outgoing * @see .initializeCall */ - override fun prepareCall(isIncoming: Boolean) { + override fun prepareCall(acceptIncomingCall: Boolean) { val audioGranted = mDeviceRuntimeService.hasAudioPermission() val hasVideo = presenter.wantVideo - Log.w(TAG, "DEBUG fn prepareCall -> define the permission based on hasVideo : $hasVideo and then call initializeCall($isIncoming, $hasVideo) ") + Log.w(TAG, "DEBUG fn prepareCall -> define the permission based on hasVideo : $hasVideo and then call initializeCall($acceptIncomingCall, $hasVideo) ") //Log.w(TAG, "fn prepareCall [CallFragment.kt] -> value of presenter.hasVideo() : $hasVideo") val permissionType = - if (isIncoming) REQUEST_PERMISSION_INCOMING else REQUEST_PERMISSION_OUTGOING + if (acceptIncomingCall) REQUEST_PERMISSION_INCOMING else REQUEST_PERMISSION_OUTGOING if (hasVideo) { val videoGranted = mDeviceRuntimeService.hasVideoPermission() @@ -1166,15 +1153,15 @@ class CallFragment : BaseSupportFragment<CallPresenter, CallView>(), CallView, } requestPermissions(perms.toTypedArray(), permissionType) } else if (audioGranted && videoGranted) { - Log.w(TAG, "DEBUG fn prepareCall [CallFragment.kt] -> calling initializeCall($isIncoming, $hasVideo) ") - initializeCall(isIncoming, hasVideo) + Log.w(TAG, "DEBUG fn prepareCall [CallFragment.kt] -> calling initializeCall($acceptIncomingCall, $hasVideo) ") + initializeCall(acceptIncomingCall, hasVideo) } } else { if (!audioGranted && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { requestPermissions(arrayOf(Manifest.permission.RECORD_AUDIO), permissionType) } else if (audioGranted) { - Log.w(TAG, "DEBUG fn prepareCall [CallFragment.kt] -> calling initializeCall($isIncoming, $hasVideo) ") - initializeCall(isIncoming, hasVideo) + Log.w(TAG, "DEBUG fn prepareCall [CallFragment.kt] -> calling initializeCall($acceptIncomingCall, $hasVideo) ") + initializeCall(acceptIncomingCall, hasVideo) } } } @@ -1457,13 +1444,11 @@ class CallFragment : BaseSupportFragment<CallPresenter, CallView>(), CallView, } private val blinkingAnimation: Animation - get() { - return AlphaAnimation(1f, 0f).apply { - duration = 400 - interpolator = LinearInterpolator() - repeatCount = Animation.INFINITE - repeatMode = Animation.REVERSE - } + get() = AlphaAnimation(1f, 0f).apply { + duration = 400 + interpolator = LinearInterpolator() + repeatCount = Animation.INFINITE + repeatMode = Animation.REVERSE } companion object { @@ -1478,27 +1463,27 @@ class CallFragment : BaseSupportFragment<CallPresenter, CallView>(), CallView, private const val REQUEST_CODE_SCREEN_SHARE = 7 fun newInstance(action: String, path: ConversationPath?, contactId: String?, hasVideo: Boolean): CallFragment { - val bundle = Bundle() - bundle.putString(KEY_ACTION, action) - path?.toBundle(bundle) - bundle.putString(Intent.EXTRA_PHONE_NUMBER, contactId) - bundle.putBoolean(KEY_HAS_VIDEO, hasVideo) - val countDownFragment = CallFragment() - countDownFragment.arguments = bundle - return countDownFragment + return CallFragment().apply { + arguments = Bundle().apply { + putString(KEY_ACTION, action) + path?.toBundle(this) + putString(Intent.EXTRA_PHONE_NUMBER, contactId) + putBoolean(KEY_HAS_VIDEO, hasVideo) + } + } } fun newInstance(action: String, confId: String?, hasVideo: Boolean): CallFragment { - val countDownFragment = CallFragment() - countDownFragment.arguments = Bundle().apply { - putString(KEY_ACTION, action) - putString(KEY_CONF_ID, confId) - putBoolean(KEY_HAS_VIDEO, hasVideo) + return CallFragment().apply { + arguments = Bundle().apply { + putString(KEY_ACTION, action) + putString(KEY_CONF_ID, confId) + putBoolean(KEY_HAS_VIDEO, hasVideo) + } } - return countDownFragment } - fun callStateToHumanState(state: CallStatus?): Int { + fun callStateToHumanState(state: CallStatus): Int { return when (state) { CallStatus.SEARCHING -> R.string.call_human_state_searching CallStatus.CONNECTING -> R.string.call_human_state_connecting diff --git a/ring-android/app/src/main/java/cx/ring/tv/call/TVCallFragment.kt b/ring-android/app/src/main/java/cx/ring/tv/call/TVCallFragment.kt index 0e027af9651f7c4a86cacd3426b7ffe821bd3384..fce5146af0cb03690537a2706f3f2e30c1fbd3aa 100644 --- a/ring-android/app/src/main/java/cx/ring/tv/call/TVCallFragment.kt +++ b/ring-android/app/src/main/java/cx/ring/tv/call/TVCallFragment.kt @@ -313,62 +313,6 @@ class TVCallFragment : BaseSupportFragment<CallPresenter, CallView>(), CallView ) } - override fun updateContactBubble(calls: List<Call>) { - mConferenceMode = calls.size > 1 - val contact = calls[0].contact!! - val username = if (mConferenceMode) "Conference with " + calls.size + " people" else contact.ringUsername - val displayName = if (mConferenceMode) null else contact.displayName - Log.d(TAG, "updateContactBubble: username=" + username + ", uri=" + contact.uri + " photo:" + contact.photo) - mSession?.setMetadata(MediaMetadataCompat.Builder() - .putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, displayName) - .build()) - val hasProfileName = displayName != null && !displayName.contentEquals(username) - if (hasProfileName) { - binding!!.contactBubbleNumTxt.visibility = View.VISIBLE - binding!!.contactBubbleTxt.text = displayName - binding!!.contactBubbleNumTxt.text = username - } else { - binding!!.contactBubbleNumTxt.visibility = View.GONE - binding!!.contactBubbleTxt.text = username - } - binding!!.contactBubble.setImageDrawable( - AvatarDrawable.Builder() - .withContact(contact) - .withCircleCrop(true) - .build(requireActivity()) - ) - - /*if (!mConferenceMode) { - binding.confControlGroup.setVisibility(View.GONE); - } else { - binding.confControlGroup.setVisibility(View.VISIBLE); - if (confAdapter == null) { - confAdapter = new ConfParticipantAdapter((view, call) -> { - Context context = requireContext(); - PopupMenu popup = new PopupMenu(context, view); - popup.inflate(R.menu.conference_participant_actions); - popup.setOnMenuItemClickListener(item -> { - int itemId = item.getItemId(); - if (itemId == R.id.conv_contact_details) { - presenter.openParticipantContact(call); - } else if (itemId == R.id.conv_contact_hangup) { - presenter.hangupParticipant(call); - } else { - return false; - } - return true; - }); - MenuPopupHelper menuHelper = new MenuPopupHelper(context, (MenuBuilder) popup.getMenu(), view); - menuHelper.setForceShowIcon(true); - menuHelper.show(); - }); - } - confAdapter.updateFromCalls(calls); - if (binding.confControlGroup.getAdapter() == null) - binding.confControlGroup.setAdapter(confAdapter); - }*/ - } - override fun updateCallStatus(callStatus: CallStatus) { when (callStatus) { CallStatus.NONE -> binding!!.callStatusTxt.text = "" @@ -540,20 +484,14 @@ class TVCallFragment : BaseSupportFragment<CallPresenter, CallView>(), CallView } override fun goToContact(accountId: String, contact: Contact) { - startActivity(Intent(Intent.ACTION_VIEW, - android.net.Uri.withAppendedPath( - android.net.Uri.withAppendedPath( - ContentUriHandler.CONTACT_CONTENT_URI, - accountId - ), contact.primaryNumber)) - .setClass(requireContext(), ContactDetailsActivity::class.java) - ) + startActivity(Intent(Intent.ACTION_VIEW, ConversationPath.toUri(accountId, contact.uri), requireContext(), ContactDetailsActivity::class.java)) } override fun displayPluginsButton(): Boolean { return false } + @SuppressLint("RestrictedApi") override fun updateConfInfo(info: List<ParticipantInfo>) { val binding = binding!! binding.participantLabelContainer.removeAllViews() @@ -576,30 +514,50 @@ class TVCallFragment : BaseSupportFragment<CallPresenter, CallView>(), CallView binding.confControlGroup!!.visibility = View.GONE } else { binding.confControlGroup!!.visibility = View.VISIBLE - if (confAdapter == null) { - confAdapter = ConfParticipantAdapter(object : ConfParticipantSelected { - @SuppressLint("RestrictedApi") + confAdapter?.apply { updateFromCalls(info) } + // Create new adapter + ?: ConfParticipantAdapter(info, object : ConfParticipantSelected { override fun onParticipantSelected(view: View, contact: ParticipantInfo) { - val context = requireContext() - val popup = PopupMenu(context, view) + val maximized = presenter.isMaximized(contact) + val popup = PopupMenu(view.context, view) popup.inflate(R.menu.conference_participant_actions) - popup.setOnMenuItemClickListener { item: MenuItem -> + popup.setOnMenuItemClickListener { item -> when (item.itemId) { R.id.conv_contact_details -> presenter.openParticipantContact(contact) R.id.conv_contact_hangup -> presenter.hangupParticipant(contact) + R.id.conv_mute -> presenter.muteParticipant(contact, !contact.audioMuted) + R.id.conv_contact_maximize -> presenter.maximizeParticipant(contact) else -> return@setOnMenuItemClickListener false } true } - val menuHelper = MenuPopupHelper(context, (popup.menu as MenuBuilder), view) + val menu = popup.menu as MenuBuilder + val maxItem = menu.findItem(R.id.conv_contact_maximize) + val muteItem = menu.findItem(R.id.conv_mute) + if (maximized) { + maxItem.setTitle(R.string.action_call_minimize) + maxItem.setIcon(R.drawable.baseline_close_fullscreen_24) + } else { + maxItem.setTitle(R.string.action_call_maximize) + maxItem.setIcon(R.drawable.baseline_open_in_full_24) + } + if (!contact.audioMuted) { + muteItem.setTitle(R.string.action_call_mute) + muteItem.setIcon(R.drawable.baseline_mic_off_24) + } else { + muteItem.setTitle(R.string.action_call_unmute) + muteItem.setIcon(R.drawable.baseline_mic_24) + } + val menuHelper = MenuPopupHelper(view.context, menu, view) + menuHelper.gravity = Gravity.END menuHelper.setForceShowIcon(true) menuHelper.show() } - }) - } - confAdapter!!.updateFromCalls(info) - if (binding.confControlGroup.adapter == null) - binding.confControlGroup.adapter = confAdapter + }).apply { + setHasStableIds(true) + confAdapter = this + binding.confControlGroup.adapter = this + } } } diff --git a/ring-android/app/src/main/java/cx/ring/tv/contact/TVContactPresenter.kt b/ring-android/app/src/main/java/cx/ring/tv/contact/TVContactPresenter.kt index 46356b61b53cf2835b05c4a454903b41715d8755..16fdde6ef7e126b75b4a155e5c6d90f6aae81305 100644 --- a/ring-android/app/src/main/java/cx/ring/tv/contact/TVContactPresenter.kt +++ b/ring-android/app/src/main/java/cx/ring/tv/contact/TVContactPresenter.kt @@ -57,8 +57,7 @@ class TVContactPresenter @Inject constructor( } fun contactClicked() { - val account = mAccountService.getAccount(mAccountId!!) - if (account != null) { + mAccountService.getAccount(mAccountId)?.let { account -> val conversation = account.getByUri(mUri)!! val conf = conversation.currentCall val call = conf?.firstCall diff --git a/ring-android/app/src/main/res/layout/frag_call.xml b/ring-android/app/src/main/res/layout/frag_call.xml index ef5d20c9ae147c8f322f64bea7ddda449aebe0d9..42133fe78bb275ad1de538fdb9016bd3dd535c3c 100644 --- a/ring-android/app/src/main/res/layout/frag_call.xml +++ b/ring-android/app/src/main/res/layout/frag_call.xml @@ -131,7 +131,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" - android:animateLayoutChanges="true" android:clipToPadding="false" android:fitsSystemWindows="true"> diff --git a/ring-android/app/src/main/res/layout/item_conference_participant.xml b/ring-android/app/src/main/res/layout/item_conference_participant.xml index 5b4f76ca7fc6cf1e0f74b2b4dcc733815c8b60a4..b1ea9621d30029b3fe6d51684c6e762db40bb8c0 100644 --- a/ring-android/app/src/main/res/layout/item_conference_participant.xml +++ b/ring-android/app/src/main/res/layout/item_conference_participant.xml @@ -38,7 +38,7 @@ along with this program; if not, write to the Free Software android:layout_margin="@dimen/padding_large" android:background="@drawable/background_conference_participant" android:elevation="4dp" - android:ellipsize="end" + android:ellipsize="middle" android:maxLines="2" android:paddingStart="16dp" android:paddingTop="8dp" @@ -47,8 +47,10 @@ along with this program; if not, write to the Free Software android:textAlignment="center" android:textColor="@color/grey_800" android:textIsSelectable="false" + android:maxWidth="230dp" + android:scrollHorizontally="false" android:textSize="16sp" - tools:text="Thomas\nConnecting..." /> + tools:text="ring:21d85b6990d2f23663da147db28797ad26c478e421d85b6990d2f23663da147db28797ad26c478e4\nConnecting..." /> <com.google.android.material.floatingactionbutton.FloatingActionButton android:id="@+id/photo" @@ -60,7 +62,6 @@ along with this program; if not, write to the Free Software android:enabled="false" app:maxImageSize="64dp" app:useCompatPadding="true" - tools:src="@drawable/ic_contact_picture_fallback" /> </LinearLayout> diff --git a/ring-android/libjamiclient/src/main/kotlin/net/jami/call/CallPresenter.kt b/ring-android/libjamiclient/src/main/kotlin/net/jami/call/CallPresenter.kt index daa02e14b70a1aa329066f4c4819f979df7f5bde..b12a0c7ef8e88e1ced7aab3653f8879eccbbe888 100644 --- a/ring-android/libjamiclient/src/main/kotlin/net/jami/call/CallPresenter.kt +++ b/ring-android/libjamiclient/src/main/kotlin/net/jami/call/CallPresenter.kt @@ -53,8 +53,8 @@ class CallPresenter @Inject constructor( @param:Named("UiScheduler") private val mUiScheduler: Scheduler ) : RootPresenter<CallView>() { private var mConference: Conference? = null - private val mPendingCalls: MutableList<Call> = ArrayList() - private val mPendingSubject: Subject<List<Call>> = BehaviorSubject.createDefault(mPendingCalls) + private val mPendingCalls: MutableList<ParticipantInfo> = ArrayList() + private val mPendingSubject: Subject<List<ParticipantInfo>> = BehaviorSubject.createDefault(mPendingCalls) private var mOnGoingCall = false var wantVideo = false var videoIsMuted = false @@ -87,36 +87,14 @@ class CallPresenter @Inject constructor( } } - /*override fun unbindView() { - if (wantVideo) { - mHardwareService.endCapture() - } - super.unbindView() - }*/ - override fun bindView(view: CallView) { super.bindView(view) - /*mCompositeDisposable.add(mAccountService.getRegisteredNames() - .observeOn(mUiScheduler) - .subscribe(r -> { - if (mSipCall != null && mSipCall.getContact() != null) { - getView().updateContactBubble(mSipCall.getContact()); - } - }));*/ mCompositeDisposable.add(mHardwareService.getVideoEvents() .observeOn(mUiScheduler) .subscribe { event: VideoEvent -> onVideoEvent(event) }) mCompositeDisposable.add(mHardwareService.audioState .observeOn(mUiScheduler) .subscribe { state: AudioState -> this.view?.updateAudioState(state) }) - - /*mCompositeDisposable.add(mHardwareService - .getBluetoothEvents() - .subscribe(event -> { - if (!event.connected && mSipCall == null) { - hangupCall(); - } - }));*/ } fun initOutGoing(accountId: String?, conversationUri: Uri?, contactUri: String?, hasVideo: Boolean) { @@ -134,14 +112,11 @@ class CallPresenter @Inject constructor( //getView().blockScreenRotation(); val callObservable = mCallService .placeCall(accountId, conversationUri, fromString(toNumber(contactUri)!!), pHasVideo) - //.map(mCallService::getConference) .flatMapObservable { call: Call -> mCallService.getConfUpdates(call) } .share() mCompositeDisposable.add(callObservable .observeOn(mUiScheduler) - .subscribe({ conference: Conference -> - contactUpdate(conference) - confUpdate(conference) + .subscribe({ conference -> confUpdate(conference) }) { e: Throwable -> hangupCall() Log.e(TAG, "Error with initOutgoing: " + e.message, e) @@ -166,25 +141,24 @@ class CallPresenter @Inject constructor( .share() // Handles the case where the call has been accepted, emits a single so as to only check for permissions and start the call once - mCompositeDisposable.add(callObservable - .firstOrError() - .subscribe({ call: Conference -> - if (!actionViewOnly) { - contactUpdate(call) + + if (!actionViewOnly) { + mCompositeDisposable.add(callObservable + .firstOrError() + .subscribe({ call: Conference -> confUpdate(call) callInitialized = true view!!.prepareCall(true) - } - }) { e: Throwable -> - hangupCall() - Log.e(TAG, "Error with initIncoming, preparing call flow :", e) - }) + }) { e: Throwable -> + hangupCall() + Log.e(TAG, "Error with initIncoming, preparing call flow :", e) + }) + } // Handles retrieving call updates. Items emitted are only used if call is already in process or if user is returning to a call. mCompositeDisposable.add(callObservable .subscribe({ call: Conference -> if (callInitialized || actionViewOnly) { - contactUpdate(call) confUpdate(call) } }) { e: Throwable -> @@ -197,7 +171,13 @@ class CallPresenter @Inject constructor( private fun showConference(conference: Observable<Conference>) { val conference = conference.distinctUntilChanged() mCompositeDisposable.add(conference - .switchMap { obj: Conference -> obj.participantInfo } + .switchMap { obj: Conference -> Observable.combineLatest(obj.participantInfo, mPendingSubject, { participants, pending -> + val p = if (participants.isEmpty() && !obj.isConference) + listOf(ParticipantInfo(obj.call, obj.call!!.contact!!, emptyMap())) + else + participants + if (pending.isEmpty()) p else p + pending + })} .observeOn(mUiScheduler) .subscribe({ info: List<ParticipantInfo> -> view?.updateConfInfo(info) }) { e: Throwable -> Log.e(TAG, "Error with initIncoming, action view flow: ", e) }) @@ -222,10 +202,9 @@ class CallPresenter @Inject constructor( } fun chatClick() { - if (mConference == null || mConference!!.participants.isEmpty()) { - return - } - val firstCall = mConference!!.participants[0] ?: return + val conference = mConference ?: return + if (conference.participants.isEmpty()) return + val firstCall = conference.participants[0] val c = firstCall.conversation if (c is Conversation) { view?.goToConversation(c.accountId, c.uri) @@ -281,7 +260,7 @@ class CallPresenter @Inject constructor( mCallService.hangUp(conference.id) } for (call in mPendingCalls) { - mCallService.hangUp(call.daemonIdString!!) + mCallService.hangUp(call.call!!.daemonIdString!!) } finish() } @@ -292,17 +271,15 @@ class CallPresenter @Inject constructor( } fun videoSurfaceCreated(holder: Any) { - if (mConference == null) { - return - } - val newId = mConference!!.id + val conference = mConference ?: return + val newId = conference.id if (newId != currentSurfaceId) { currentSurfaceId?.let { id -> mHardwareService.removeVideoSurface(id) } currentSurfaceId = newId } - mHardwareService.addVideoSurface(mConference!!.id, holder) + mHardwareService.addVideoSurface(conference.id, holder) view?.displayContactBubble(false) } @@ -316,17 +293,15 @@ class CallPresenter @Inject constructor( } fun pluginSurfaceCreated(holder: Any) { - if (mConference == null) { - return - } - val newId = mConference!!.pluginId + val conference = mConference ?: return + val newId = conference.pluginId if (newId != currentPluginSurfaceId) { currentPluginSurfaceId?.let { id -> mHardwareService.removeVideoSurface(id) } currentPluginSurfaceId = newId } - mHardwareService.addVideoSurface(mConference!!.pluginId, holder) + mHardwareService.addVideoSurface(conference.pluginId, holder) view?.displayContactBubble(false) } @@ -363,14 +338,6 @@ class CallPresenter @Inject constructor( mHardwareService.endCapture() } - fun displayChanged() { - mHardwareService.switchInput(mConference!!.id, false) - } - - fun layoutChanged() { - //getView().resetVideoSize(videoWidth, videoHeight, previewWidth, previewHeight); - } - fun uiVisibilityChanged(displayed: Boolean) { Log.w(TAG, "uiVisibilityChanged $mOnGoingCall $displayed") view?.displayHangupButton(mOnGoingCall && displayed) @@ -387,51 +354,8 @@ class CallPresenter @Inject constructor( view?.finish() } - private var contactDisposable: Disposable? = null - private fun contactUpdate(conference: Conference) { - if (mConference !== conference) { - mConference = conference - contactDisposable?.apply { dispose() } - if (conference.participants.isEmpty()) return - - // Updates of participant (and pending participant) list - val callsObservable = mPendingSubject - .map<List<Call>> { pendingList: List<Call> -> - Log.w(TAG, "mPendingSubject onNext " + pendingList.size + " " + conference.participants.size) - if (pendingList.isEmpty()) return@map conference.participants - val newList: MutableList<Call> = ArrayList(conference.participants.size + pendingList.size) - newList.addAll(conference.participants) - newList.addAll(pendingList) - newList - } - - // Updates of individual contacts - val contactsObservable = callsObservable.flatMapSingle { calls: List<Call> -> - Observable.fromIterable(calls) - .map { call: Call -> mContactService.observeContact(call.account!!, call.contact!!, false) - .map { call } } - .toList(calls.size) - } - - // Combined updates of contacts as participant list updates - val contactUpdates = contactsObservable - .switchMap { list: List<Observable<Call>> -> Observable.combineLatest(list) { objects: Array<Any> -> - Log.w(TAG, "flatMapObservable " + objects.size) - val calls = ArrayList<Call>(objects.size) - for (call in objects) calls.add(call as Call) - calls - } } - .filter { list: List<Call> -> list.isNotEmpty() } - contactDisposable = contactUpdates - .observeOn(mUiScheduler) - .subscribe({ cs: List<Call> -> view?.updateContactBubble(cs) }) - { e: Throwable -> Log.e(TAG, "Error updating contact data", e) } - .apply { mCompositeDisposable.add(this) } - } - mPendingSubject.onNext(mPendingCalls) - } - private fun confUpdate(call: Conference) { + mConference = call Log.w(TAG, "confUpdate " + call.id + " " + call.state) val status = call.state if (status === CallStatus.HOLD) { @@ -482,27 +406,26 @@ class CallPresenter @Inject constructor( } fun maximizeParticipant(info: ParticipantInfo?) { - var info = info + val conference = mConference ?: return val contact = info?.contact - if (mConference!!.maximizedParticipant == contact) info = null - mConference!!.maximizedParticipant = contact - if (info != null) { - mCallService.setConfMaximizedParticipant(mConference!!.id, info.contact.uri) + val toMaximize = if (conference.maximizedParticipant == contact) null else info + conference.maximizedParticipant = contact + if (toMaximize != null) { + mCallService.setConfMaximizedParticipant(conference.id, toMaximize.contact.uri) } else { - mCallService.setConfGridLayout(mConference!!.id) + mCallService.setConfGridLayout(conference.id) } } private fun updateTime() { - val view = view - if (view != null && mConference != null) { - if (mConference!!.isOnGoing) { - val start = mConference!!.timestampStart - if (start != Long.MAX_VALUE) { - view.updateTime((System.currentTimeMillis() - start) / 1000) - } else { - view.updateTime(-1) - } + val conference = mConference ?: return + val view = view ?: return + if (conference.isOnGoing) { + val start = conference.timestampStart + if (start != Long.MAX_VALUE) { + view.updateTime((System.currentTimeMillis() - start) / 1000) + } else { + view.updateTime(-1) } } } @@ -547,7 +470,8 @@ class CallPresenter @Inject constructor( } fun positiveButtonClicked() { - if (mConference!!.isRinging && mConference!!.isIncoming) { + val conference = mConference ?: return + if (conference.isRinging && conference.isIncoming) { acceptCall(true) } else { hangupCall() @@ -555,7 +479,8 @@ class CallPresenter @Inject constructor( } fun negativeButtonClicked() { - if (mConference!!.isRinging && mConference!!.isIncoming) { + val conference = mConference ?: return + if (conference.isRinging && conference.isIncoming) { refuseCall() } else { hangupCall() @@ -563,14 +488,16 @@ class CallPresenter @Inject constructor( } fun toggleButtonClicked() { - if (mConference != null && !(mConference!!.isRinging && mConference!!.isIncoming)) { + val conference = mConference ?: return + if (!(conference.isRinging && conference.isIncoming)) { hangupCall() } } fun requestPipMode() { - if (mConference != null && mConference!!.isOnGoing && mConference!!.hasVideo()) { - view!!.enterPipMode(mConference!!.id) + val conference = mConference ?: return + if (conference.isOnGoing && conference.hasVideo()) { + view?.enterPipMode(conference.id) } } @@ -601,17 +528,18 @@ class CallPresenter @Inject constructor( } fun addConferenceParticipant(accountId: String, uri: Uri) { + val conference = mConference ?: return mCompositeDisposable.add(mConversationFacade.startConversation(accountId, uri) .subscribe { conversation: Conversation -> val conf = conversation.currentCall if (conf == null) { val pendingObserver: Observer<Call> = object : Observer<Call> { - private var call: Call? = null + private var call: ParticipantInfo? = null override fun onSubscribe(d: Disposable) {} override fun onNext(sipCall: Call) { if (call == null) { - call = sipCall - mPendingCalls.add(sipCall) + call = ParticipantInfo(sipCall, sipCall.contact ?: conversation.contact!!, emptyMap(), pending = true) + .apply { mPendingCalls.add(this) } } mPendingSubject.onNext(mPendingCalls) } @@ -635,24 +563,24 @@ class CallPresenter @Inject constructor( .delay(1, TimeUnit.SECONDS) .doOnEvent { v: Call?, e: Throwable? -> pendingObserver.onComplete() } mCompositeDisposable.add(newCall.subscribe { call: Call -> - val id = mConference!!.id - if (mConference!!.isConference) { + val id = conference.id + if (conference.isConference) { mCallService.addParticipant(call.daemonIdString!!, id) } else { mCallService.joinParticipant(id, call.daemonIdString!!).subscribe() } }) - } else if (conf !== mConference) { - if (mConference!!.isConference) { + } else if (conf !== conference) { + if (conference.isConference) { if (conf.isConference) - mCallService.joinConference(mConference!!.id, conf.id) + mCallService.joinConference(conference.id, conf.id) else - mCallService.addParticipant(conf.id, mConference!!.id) + mCallService.addParticipant(conf.id, conference.id) } else { if (conf.isConference) - mCallService.addParticipant(mConference!!.id, conf.id) + mCallService.addParticipant(conference.id, conf.id) else - mCallService.joinParticipant(mConference!!.id, conf.id).subscribe() + mCallService.joinParticipant(conference.id, conf.id).subscribe() } } }) diff --git a/ring-android/libjamiclient/src/main/kotlin/net/jami/call/CallView.kt b/ring-android/libjamiclient/src/main/kotlin/net/jami/call/CallView.kt index d6970fa4098cc8a351b477f95d8024580b801075..0f3905884b26a4589cec25d0829d6015132e58aa 100644 --- a/ring-android/libjamiclient/src/main/kotlin/net/jami/call/CallView.kt +++ b/ring-android/libjamiclient/src/main/kotlin/net/jami/call/CallView.kt @@ -19,8 +19,6 @@ */ package net.jami.call -import com.j256.ormlite.field.converter.BooleanNumberFieldConverter -import net.jami.model.Call import net.jami.model.Call.CallStatus import net.jami.model.Conference.ParticipantInfo import net.jami.model.Contact @@ -37,7 +35,6 @@ interface CallView { fun updateAudioState(state: AudioState) fun updateMenu() fun updateTime(duration: Long) - fun updateContactBubble(contact: List<Call>) fun updateCallStatus(callState: CallStatus) fun initMenu(isSpeakerOn: Boolean, hasMultipleCamera: Boolean, canDial: Boolean, showPluginBtn: Boolean, onGoingCall: Boolean, hasActiveVideo: Boolean) fun initNormalStateDisplay(audioOnly: Boolean, muted: Boolean) @@ -52,7 +49,7 @@ interface CallView { fun finish() fun onUserLeave() fun enterPipMode(callId: String) - fun prepareCall(isIncoming: Boolean) + fun prepareCall(acceptIncomingCall: Boolean) fun handleCallWakelock(isAudioOnly: Boolean) fun goToContact(accountId: String, contact: Contact) fun displayPluginsButton(): Boolean diff --git a/ring-android/libjamiclient/src/main/kotlin/net/jami/model/Conference.kt b/ring-android/libjamiclient/src/main/kotlin/net/jami/model/Conference.kt index e08e40ed09d8bca60bb4b089d2c1dc5f753a2819..21a0aee785fcd2e18150680bdf352a912d0c55fe 100644 --- a/ring-android/libjamiclient/src/main/kotlin/net/jami/model/Conference.kt +++ b/ring-android/libjamiclient/src/main/kotlin/net/jami/model/Conference.kt @@ -30,14 +30,14 @@ import java.util.* import kotlin.math.min class Conference { - class ParticipantInfo(val call: Call?, val contact: Contact, i: Map<String, String>) { - var x: Int = i["x"]?.toInt() ?: 0 - var y: Int = i["y"]?.toInt() ?: 0 - var w: Int = i["w"]?.toInt() ?: 0 - var h: Int = i["h"]?.toInt() ?: 0 - var videoMuted: Boolean = java.lang.Boolean.parseBoolean(i["videoMuted"]) - var audioMuted: Boolean = java.lang.Boolean.parseBoolean(i["audioMuted"]) - var isModerator: Boolean = java.lang.Boolean.parseBoolean(i["isModerator"]) + class ParticipantInfo(val call: Call?, val contact: Contact, i: Map<String, String>, val pending: Boolean = false) { + val x: Int = i["x"]?.toInt() ?: 0 + val y: Int = i["y"]?.toInt() ?: 0 + val w: Int = i["w"]?.toInt() ?: 0 + val h: Int = i["h"]?.toInt() ?: 0 + val videoMuted: Boolean = i["videoMuted"].toBoolean() + val audioMuted: Boolean = i["audioMuted"].toBoolean() + val isModerator: Boolean = i["isModerator"].toBoolean() val isEmpty: Boolean get() = x == 0 && y == 0 && w == 0 && h == 0 } 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 0bf203fcaffe18a31beccc620607e0be9b36b1d5..c5b127bc67012d06bb59b8fe2ce925d0be525a42 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 @@ -425,7 +425,10 @@ class AccountService( */ fun getAccount(accountId: String?): Account? { if (!StringUtils.isEmpty(accountId)) { - synchronized(mAccountList) { for (account in mAccountList) if (accountId == account.accountId) return account } + synchronized(mAccountList) { + for (account in mAccountList) + if (accountId == account.accountId) return account + } } return null } diff --git a/ring-android/libjamiclient/src/main/kotlin/net/jami/services/CallService.kt b/ring-android/libjamiclient/src/main/kotlin/net/jami/services/CallService.kt index 21ad4b92be601d489c2ea114af6a1e4602e312d9..eba8bf082c16dc72719b44ff04849fa19bafaca7 100644 --- a/ring-android/libjamiclient/src/main/kotlin/net/jami/services/CallService.kt +++ b/ring-android/libjamiclient/src/main/kotlin/net/jami/services/CallService.kt @@ -36,18 +36,10 @@ import net.jami.model.Conference.ParticipantInfo import net.jami.model.Media import net.jami.model.Uri import net.jami.utils.Log -import net.jami.utils.StringUtils.isEmpty -import net.jami.utils.SwigNativeConverter -import org.w3c.dom.stylesheets.MediaList +import net.jami.utils.StringUtils import java.util.* import java.util.concurrent.Callable import java.util.concurrent.ScheduledExecutorService -import javax.xml.transform.Source -import kotlin.collections.ArrayList - - - - class CallService( private val mExecutor: ScheduledExecutorService, @@ -515,7 +507,7 @@ class CallService( } else if (callState !== CallStatus.OVER && callState !== CallStatus.FAILURE) { val callDetails: Map<String, String> = JamiService.getCallDetails(callId) call = Call(callId, callDetails) - if (isEmpty(call.contactNumber)) { + if (StringUtils.isEmpty(call.contactNumber)) { Log.w(TAG, "No number") return null }