feat: add a first call missed control message and info popup with link to privacy settings

This commit is contained in:
Harris 2022-04-06 16:38:55 +10:00
parent e7b0707377
commit 34863c5cab
9 changed files with 61 additions and 9 deletions

View File

@ -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)
}
}
}
}

View File

@ -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))

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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); }

View File

@ -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()));
}

View File

@ -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)
}
continue
}
when (nextMessage.type) {
@ -63,11 +65,15 @@ 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
if (isFirstCall) {
storage.insertCallMessage(sender, CallMessageType.CALL_FIRST_MISSED, sentTimestamp)
} else {
storage.insertCallMessage(sender, CallMessageType.CALL_MISSED, sentTimestamp)
}
}
private fun incomingHangup(callMessage: CallMessage) {
val callId = callMessage.callId ?: return

View File

@ -3,5 +3,6 @@ package org.session.libsession.messaging.calls
enum class CallMessageType {
CALL_MISSED,
CALL_INCOMING,
CALL_OUTGOING
CALL_OUTGOING,
CALL_FIRST_MISSED,
}

View File

@ -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)
}
}
}