diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationAdapter.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationAdapter.kt index 0c8bda33f..c90739ab1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationAdapter.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationAdapter.kt @@ -1,10 +1,13 @@ package org.thoughtcrime.securesms.conversation.v2 +import android.app.AlertDialog import android.content.Context +import android.content.Intent import android.database.Cursor import android.view.MotionEvent import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView.ViewHolder +import network.loki.messenger.R import org.thoughtcrime.securesms.conversation.v2.messages.ControlMessageView import org.thoughtcrime.securesms.conversation.v2.messages.VisibleMessageContentViewDelegate import org.thoughtcrime.securesms.conversation.v2.messages.VisibleMessageView @@ -12,6 +15,7 @@ import org.thoughtcrime.securesms.database.CursorRecyclerViewAdapter import org.thoughtcrime.securesms.database.model.MessageRecord import org.thoughtcrime.securesms.dependencies.DatabaseComponent import org.thoughtcrime.securesms.mms.GlideRequests +import org.thoughtcrime.securesms.preferences.PrivacySettingsActivity class ConversationAdapter(context: Context, cursor: Cursor, private val onItemPress: (MessageRecord, Int, VisibleMessageView, MotionEvent) -> Unit, private val onItemSwipeToReply: (MessageRecord, Int) -> Unit, private val onItemLongPress: (MessageRecord, Int) -> Unit, @@ -76,7 +80,26 @@ class ConversationAdapter(context: Context, cursor: Cursor, private val onItemPr } view.contentViewDelegate = visibleMessageContentViewDelegate } - is ControlMessageViewHolder -> viewHolder.view.bind(message, messageBefore) + is ControlMessageViewHolder -> { + viewHolder.view.bind(message, messageBefore) + if (message.isCallLog && message.isFirstMissedCall) { + viewHolder.view.setOnClickListener { + AlertDialog.Builder(context) + .setTitle(R.string.CallNotificationBuilder_first_call_title) + .setMessage(R.string.CallNotificationBuilder_first_call_message) + .setPositiveButton(R.string.activity_settings_title) { _, _ -> + val intent = Intent(context, PrivacySettingsActivity::class.java) + context.startActivity(intent) + } + .setNeutralButton(R.string.cancel) { d, _ -> + d.dismiss() + } + .show() + } + } else { + viewHolder.view.setOnClickListener(null) + } + } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/ControlMessageView.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/ControlMessageView.kt index a944ccb7f..a4e4a52d5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/ControlMessageView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/messages/ControlMessageView.kt @@ -1,12 +1,10 @@ package org.thoughtcrime.securesms.conversation.v2.messages import android.content.Context -import android.content.res.ColorStateList import android.util.AttributeSet import android.view.LayoutInflater import android.view.View import android.widget.LinearLayout -import androidx.core.content.ContextCompat import androidx.core.content.res.ResourcesCompat import androidx.recyclerview.widget.RecyclerView import network.loki.messenger.R @@ -53,6 +51,7 @@ class ControlMessageView : LinearLayout { val drawable = when { message.isIncomingCall -> R.drawable.ic_incoming_call message.isOutgoingCall -> R.drawable.ic_outgoing_call + message.isFirstMissedCall -> R.drawable.ic_info_outline_light else -> R.drawable.ic_missed_call } binding.iconImageView.setImageDrawable(ResourcesCompat.getDrawable(resources, drawable, context.theme)) diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsColumns.java b/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsColumns.java index 45d42d791..5905433b9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsColumns.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsColumns.java @@ -32,6 +32,7 @@ public interface MmsSmsColumns { protected static final long OUTGOING_CALL_TYPE = 2; protected static final long MISSED_CALL_TYPE = 3; protected static final long JOINED_TYPE = 4; + protected static final long FIRST_MISSED_CALL_TYPE = 5; protected static final long BASE_INBOX_TYPE = 20; protected static final long BASE_OUTBOX_TYPE = 21; @@ -208,7 +209,7 @@ public interface MmsSmsColumns { public static boolean isCallLog(long type) { long baseType = type & BASE_TYPE_MASK; - return baseType == INCOMING_CALL_TYPE || baseType == OUTGOING_CALL_TYPE || baseType == MISSED_CALL_TYPE; + return baseType == INCOMING_CALL_TYPE || baseType == OUTGOING_CALL_TYPE || baseType == MISSED_CALL_TYPE || baseType == FIRST_MISSED_CALL_TYPE; } public static boolean isExpirationTimerUpdate(long type) { @@ -239,6 +240,11 @@ public interface MmsSmsColumns { return (type & BASE_TYPE_MASK) == MISSED_CALL_TYPE; } + public static boolean isFirstMissedCall(long type) { + return (type & BASE_TYPE_MASK) == FIRST_MISSED_CALL_TYPE; + } + + public static boolean isGroupUpdate(long type) { return (type & GROUP_UPDATE_BIT) != 0; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java index 12705be0c..a34de25a9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java @@ -386,6 +386,9 @@ public class SmsDatabase extends MessagingDatabase { case CALL_MISSED: type |= Types.MISSED_CALL_TYPE; break; + case CALL_FIRST_MISSED: + type |= Types.FIRST_MISSED_CALL_TYPE; + break; } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/DisplayRecord.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/DisplayRecord.java index 5bec3b720..ef0f4b54f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/DisplayRecord.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/DisplayRecord.java @@ -117,6 +117,9 @@ public abstract class DisplayRecord { public boolean isMissedCall() { return SmsDatabase.Types.isMissedCall(type); } + public boolean isFirstMissedCall() { + return SmsDatabase.Types.isFirstMissedCall(type); + } public boolean isDeleted() { return MmsSmsColumns.Types.isDeletedMessage(type); } public boolean isMessageRequestResponse() { return MmsSmsColumns.Types.isMessageRequestResponse(type); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java index 7c7bcb6fd..0f5247cf8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/MessageRecord.java @@ -114,7 +114,16 @@ public abstract class MessageRecord extends DisplayRecord { if (isScreenshotNotification()) return new SpannableString((UpdateMessageBuilder.INSTANCE.buildDataExtractionMessage(context, DataExtractionNotificationInfoMessage.Kind.SCREENSHOT, getIndividualRecipient().getAddress().serialize()))); else if (isMediaSavedNotification()) return new SpannableString((UpdateMessageBuilder.INSTANCE.buildDataExtractionMessage(context, DataExtractionNotificationInfoMessage.Kind.MEDIA_SAVED, getIndividualRecipient().getAddress().serialize()))); } else if (isCallLog()) { - CallMessageType callType = isIncomingCall() ? CallMessageType.CALL_INCOMING : isOutgoingCall() ? CallMessageType.CALL_OUTGOING : CallMessageType.CALL_MISSED; + CallMessageType callType; + if (isIncomingCall()) { + callType = CallMessageType.CALL_INCOMING; + } else if (isOutgoingCall()) { + callType = CallMessageType.CALL_OUTGOING; + } else if (isMissedCall()) { + callType = CallMessageType.CALL_MISSED; + } else { + callType = CallMessageType.CALL_FIRST_MISSED; + } return new SpannableString(UpdateMessageBuilder.INSTANCE.buildCallMessage(context, callType, getIndividualRecipient().getAddress().serialize())); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/webrtc/CallMessageProcessor.kt b/app/src/main/java/org/thoughtcrime/securesms/webrtc/CallMessageProcessor.kt index 6201ae2bf..a66dd591f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/webrtc/CallMessageProcessor.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/webrtc/CallMessageProcessor.kt @@ -47,8 +47,10 @@ class CallMessageProcessor(private val context: Context, private val textSecureP // first time call notification encountered val notification = CallNotificationBuilder.getFirstCallNotification(context) context.getSystemService(NotificationManager::class.java).notify(CallNotificationBuilder.WEBRTC_NOTIFICATION, notification) + insertMissedCall(sender, sentTimestamp, isFirstCall = true) + } else { + insertMissedCall(sender, sentTimestamp) } - insertMissedCall(sender, sentTimestamp) continue } when (nextMessage.type) { @@ -63,10 +65,14 @@ class CallMessageProcessor(private val context: Context, private val textSecureP } } - private fun insertMissedCall(sender: String, sentTimestamp: Long) { + private fun insertMissedCall(sender: String, sentTimestamp: Long, isFirstCall: Boolean = false) { val currentUserPublicKey = storage.getUserPublicKey() if (sender == currentUserPublicKey) return // don't insert a "missed" due to call notifications disabled if it's our own sender - storage.insertCallMessage(sender, CallMessageType.CALL_MISSED, sentTimestamp) + if (isFirstCall) { + storage.insertCallMessage(sender, CallMessageType.CALL_FIRST_MISSED, sentTimestamp) + } else { + storage.insertCallMessage(sender, CallMessageType.CALL_MISSED, sentTimestamp) + } } private fun incomingHangup(callMessage: CallMessage) { diff --git a/libsession/src/main/java/org/session/libsession/messaging/calls/CallMessageType.kt b/libsession/src/main/java/org/session/libsession/messaging/calls/CallMessageType.kt index c3c954a3a..7192bade8 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/calls/CallMessageType.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/calls/CallMessageType.kt @@ -3,5 +3,6 @@ package org.session.libsession.messaging.calls enum class CallMessageType { CALL_MISSED, CALL_INCOMING, - CALL_OUTGOING + CALL_OUTGOING, + CALL_FIRST_MISSED, } \ No newline at end of file diff --git a/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageBuilder.kt b/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageBuilder.kt index 0036ba10d..52fe83170 100644 --- a/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageBuilder.kt +++ b/libsession/src/main/java/org/session/libsession/messaging/utilities/UpdateMessageBuilder.kt @@ -114,6 +114,8 @@ object UpdateMessageBuilder { context.getString(R.string.MessageRecord_s_called_you, senderName) CallMessageType.CALL_OUTGOING -> context.getString(R.string.MessageRecord_called_s, senderName) + CallMessageType.CALL_FIRST_MISSED -> + context.getString(R.string.MessageRecord_missed_call_from, senderName) } } }