diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
deleted file mode 100644
index 7c17252c2d..0000000000
--- a/.github/ISSUE_TEMPLATE.md
+++ /dev/null
@@ -1,45 +0,0 @@
-
-
-- [ ] I have read and agree to adhere to the [Code of Conduct](https://github.com/oxen-io/session-android/blob/master/CODE_OF_CONDUCT.md).
-- [ ] I have searched open and closed issues for duplicates
-- [ ] I am submitting a bug report for existing functionality that does not work as intended
-- [ ] This isn't a feature request or a discussion topic
-
-----------------------------------------
-
-### Bug description
-Describe here the issue that you are experiencing.
-
-### Steps to reproduce
-- using hyphens as bullet points
-- list the steps
-- that reproduce the bug
-
-**Actual result:**
-
-Describe here what happens after you run the steps above (i.e. the buggy behaviour)
-
-**Expected result:**
-
-Describe here what should happen after you run the steps above (i.e. what would be the correct behaviour)
-
-### Screenshots
-
-
-### Device info
-
-
-**Device:** Manufacturer Model XVI
-
-**Android version:** 0.0.0
-
-**Session version:** 0.0.0
-
-### Link to debug log
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
deleted file mode 100644
index 74bbafd0f6..0000000000
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ /dev/null
@@ -1,34 +0,0 @@
----
-name: Bug report
-about: Create a report to help us improve
-title: ''
-labels: bug
-assignees: ''
-
----
-
-**Code of conduct**
-
-- [ ] I have read and agree to adhere to the [Code of Conduct](https://github.com/oxen-io/session-android/blob/master/CODE_OF_CONDUCT.md).
-
-**Describe the bug**
-
-A clear and concise description of what the bug is.
-
-**To reproduce**
-
-Steps to reproduce the behavior:
-
-**Screenshots or logs**
-
-If applicable, add screenshots or logs to help explain your problem.
-
-**Smartphone (please complete the following information):**
-
- - Device: [e.g. Samsung Galaxy S8]
- - OS: [e.g. Android Pie]
- - Version of Session or latest commit hash
-
-**Additional context**
-
-Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
new file mode 100644
index 0000000000..883f792482
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -0,0 +1,74 @@
+name: 🐞 Bug Report
+description: Create a report to help us improve
+title: "[BUG]
"
+labels: [bug]
+body:
+- type: checkboxes
+ attributes:
+ label: Code of conduct
+ description: I have read and agree to adhere to the [Code of Conduct](https://github.com/oxen-io/session-android/blob/master/CODE_OF_CONDUCT.md).
+ options:
+ - label: I have read and agree to adhere to the [Code of Conduct](https://github.com/oxen-io/session-android/blob/master/CODE_OF_CONDUCT.md)
+ required: true
+
+- type: checkboxes
+ attributes:
+ label: Self-training on how to write a bug report
+ description: High quality bug reports can help the team save time and improve the chance of getting your issue fixed. Please read [how to write a bug report](https://www.browserstack.com/guide/how-to-write-a-bug-report) before submitting your issue.
+ options:
+ - label: I have learned [how to write a bug report](https://www.browserstack.com/guide/how-to-write-a-bug-report)
+ required: true
+
+- type: checkboxes
+ attributes:
+ label: Is there an existing issue for this?
+ description: Please search to see if an issue already exists for the bug you encountered.
+ options:
+ - label: I have searched the existing issues
+ required: true
+- type: textarea
+ attributes:
+ label: Current Behavior
+ description: A concise description of what you're experiencing.
+ validations:
+ required: false
+- type: textarea
+ attributes:
+ label: Expected Behavior
+ description: A concise description of what you expected to happen.
+ validations:
+ required: false
+- type: textarea
+ attributes:
+ label: Steps To Reproduce
+ description: Steps to reproduce the behavior.
+ placeholder: |
+ 1. In this environment...
+ 2. With this config...
+ 3. Run '...'
+ 4. See error...
+ validations:
+ required: false
+- type: input
+ attributes:
+ label: Android Version
+ description: What version of Android are you running?
+ placeholder: ex. Android 11
+ validations:
+ required: false
+- type: input
+ attributes:
+ label: Session Version
+ description: What version of Session are you running? (This can be found at the bottom of the app settings)
+ placeholder: ex. 1.17.0 (3425)
+ validations:
+ required: false
+- type: textarea
+ attributes:
+ label: Anything else?
+ description: |
+ Add any other context about the problem here.
+
+ Tip: You can attach screenshots or log files to help explain your problem by clicking this area to highlight it and then dragging files in.
+ validations:
+ required: false
diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml
new file mode 100644
index 0000000000..3c9712e52a
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.yml
@@ -0,0 +1,26 @@
+name: 🚀 Feature request
+description: Suggest an idea for Session
+title: '[Feature] '
+labels: [feature-request]
+body:
+- type: checkboxes
+ attributes:
+ label: Is there an existing request for feature?
+ description: Please search to see if an issue already exists for the feature you are requesting.
+ options:
+ - label: I have searched the existing issues
+ required: true
+- type: textarea
+ attributes:
+ label: What feature would you like?
+ description: |
+ A clear and concise description of the feature you would like added to Session
+ validations:
+ required: true
+- type: textarea
+ attributes:
+ label: Anything else?
+ description: |
+ Add any other context or screenshots about the feature request here
+ validations:
+ required: false
diff --git a/app/build.gradle b/app/build.gradle
index 2bf496cd49..bc3ffe10dd 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -122,6 +122,7 @@ android {
minifyEnabled false
}
debug {
+ isDefault true
minifyEnabled false
}
}
@@ -129,6 +130,7 @@ android {
flavorDimensions "distribution"
productFlavors {
play {
+ isDefault true
dimension "distribution"
apply plugin: 'com.google.gms.google-services'
ext.websiteUpdateUrl = "null"
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 331cd53e00..c8eacf463a 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -242,10 +242,6 @@
android:screenOrientation="portrait"
android:theme="@style/Theme.Session.DayNight">
-
= 33 &&
+ (getSystemService(NOTIFICATION_SERVICE) as NotificationManager).areNotificationsEnabled().not()) {
Permissions.with(this)
.request(Manifest.permission.POST_NOTIFICATIONS)
.execute()
diff --git a/app/src/main/java/org/thoughtcrime/securesms/longmessage/LongMessage.java b/app/src/main/java/org/thoughtcrime/securesms/longmessage/LongMessage.java
deleted file mode 100644
index 7369405d11..0000000000
--- a/app/src/main/java/org/thoughtcrime/securesms/longmessage/LongMessage.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package org.thoughtcrime.securesms.longmessage;
-
-import android.text.TextUtils;
-
-import org.thoughtcrime.securesms.database.model.MessageRecord;
-
-/**
- * A wrapper around a {@link MessageRecord} and its extra text attachment expanded into a string
- * held in memory.
- */
-class LongMessage {
-
- private final MessageRecord messageRecord;
- private final String fullBody;
-
- LongMessage(MessageRecord messageRecord, String fullBody) {
- this.messageRecord = messageRecord;
- this.fullBody = fullBody;
- }
-
- MessageRecord getMessageRecord() {
- return messageRecord;
- }
-
- String getFullBody() {
- return !TextUtils.isEmpty(fullBody) ? fullBody : messageRecord.getBody();
- }
-}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/longmessage/LongMessageActivity.java b/app/src/main/java/org/thoughtcrime/securesms/longmessage/LongMessageActivity.java
deleted file mode 100644
index 68c568bb33..0000000000
--- a/app/src/main/java/org/thoughtcrime/securesms/longmessage/LongMessageActivity.java
+++ /dev/null
@@ -1,91 +0,0 @@
-package org.thoughtcrime.securesms.longmessage;
-
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.text.Spannable;
-import android.text.method.LinkMovementMethod;
-import android.view.MenuItem;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import androidx.annotation.NonNull;
-import androidx.lifecycle.ViewModelProvider;
-
-import org.session.libsession.utilities.Address;
-import org.session.libsession.utilities.Util;
-import org.session.libsession.utilities.recipients.Recipient;
-import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity;
-import org.thoughtcrime.securesms.conversation.v2.messages.VisibleMessageContentView;
-
-import network.loki.messenger.R;
-
-public class LongMessageActivity extends PassphraseRequiredActionBarActivity {
-
- private static final String KEY_ADDRESS = "address";
- private static final String KEY_MESSAGE_ID = "message_id";
- private static final String KEY_IS_MMS = "is_mms";
-
- private static final int MAX_DISPLAY_LENGTH = 64 * 1024;
-
- private TextView textBody;
-
- private LongMessageViewModel viewModel;
-
- public static Intent getIntent(@NonNull Context context, @NonNull Address conversationAddress, long messageId, boolean isMms) {
- Intent intent = new Intent(context, LongMessageActivity.class);
- intent.putExtra(KEY_ADDRESS, conversationAddress.serialize());
- intent.putExtra(KEY_MESSAGE_ID, messageId);
- intent.putExtra(KEY_IS_MMS, isMms);
- return intent;
- }
-
- @Override
- protected void onCreate(Bundle savedInstanceState, boolean ready) {
- super.onCreate(savedInstanceState, ready);
- setContentView(R.layout.longmessage_activity);
- textBody = findViewById(R.id.longmessage_text);
-
- initViewModel(getIntent().getLongExtra(KEY_MESSAGE_ID, -1), getIntent().getBooleanExtra(KEY_IS_MMS, false));
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- super.onOptionsItemSelected(item);
-
- switch (item.getItemId()) {
- case android.R.id.home:
- finish();
- return true;
- }
-
- return false;
- }
-
- private void initViewModel(long messageId, boolean isMms) {
- viewModel = new ViewModelProvider(this, new LongMessageViewModel.Factory(getApplication(), new LongMessageRepository(this), messageId, isMms))
- .get(LongMessageViewModel.class);
-
- viewModel.getMessage().observe(this, message -> {
- if (message == null) return;
-
- if (!message.isPresent()) {
- Toast.makeText(this, R.string.LongMessageActivity_unable_to_find_message, Toast.LENGTH_SHORT).show();
- finish();
- return;
- }
-
- if (message.get().getMessageRecord().isOutgoing()) {
- getSupportActionBar().setTitle(getString(R.string.LongMessageActivity_your_message));
- } else {
- Recipient recipient = message.get().getMessageRecord().getRecipient();
- String name = Util.getFirstNonEmpty(recipient.getName(), recipient.getProfileName(), recipient.getAddress().serialize());
- getSupportActionBar().setTitle(getString(R.string.LongMessageActivity_message_from_s, name));
- }
- Spannable bodySpans = VisibleMessageContentView.Companion.getBodySpans(this, message.get().getMessageRecord(), null);
- textBody.setText(bodySpans);
- textBody.setMovementMethod(LinkMovementMethod.getInstance());
- });
- }
-
-}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/longmessage/LongMessageRepository.java b/app/src/main/java/org/thoughtcrime/securesms/longmessage/LongMessageRepository.java
deleted file mode 100644
index 4f3e1e6ec3..0000000000
--- a/app/src/main/java/org/thoughtcrime/securesms/longmessage/LongMessageRepository.java
+++ /dev/null
@@ -1,102 +0,0 @@
-package org.thoughtcrime.securesms.longmessage;
-
-import android.content.Context;
-import android.database.Cursor;
-import android.net.Uri;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.WorkerThread;
-
-import org.session.libsession.utilities.Util;
-import org.session.libsession.utilities.concurrent.SignalExecutors;
-import org.session.libsignal.utilities.Log;
-import org.session.libsignal.utilities.guava.Optional;
-import org.thoughtcrime.securesms.database.MmsDatabase;
-import org.thoughtcrime.securesms.database.SmsDatabase;
-import org.thoughtcrime.securesms.database.model.MessageRecord;
-import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
-import org.thoughtcrime.securesms.dependencies.DatabaseComponent;
-import org.thoughtcrime.securesms.mms.PartAuthority;
-import org.thoughtcrime.securesms.mms.TextSlide;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-class LongMessageRepository {
-
- private final static String TAG = LongMessageRepository.class.getSimpleName();
-
- private final MmsDatabase mmsDatabase;
- private final SmsDatabase smsDatabase;
-
- LongMessageRepository(@NonNull Context context) {
- this.mmsDatabase = DatabaseComponent.get(context).mmsDatabase();
- this.smsDatabase = DatabaseComponent.get(context).smsDatabase();
- }
-
- void getMessage(@NonNull Context context, long messageId, boolean isMms, @NonNull Callback> callback) {
- SignalExecutors.BOUNDED.execute(() -> {
- if (isMms) {
- callback.onComplete(getMmsLongMessage(context, mmsDatabase, messageId));
- } else {
- callback.onComplete(getSmsLongMessage(smsDatabase, messageId));
- }
- });
- }
-
- @WorkerThread
- private Optional getMmsLongMessage(@NonNull Context context, @NonNull MmsDatabase mmsDatabase, long messageId) {
- Optional record = getMmsMessage(mmsDatabase, messageId);
-
- if (record.isPresent()) {
- TextSlide textSlide = record.get().getSlideDeck().getTextSlide();
-
- if (textSlide != null && textSlide.getUri() != null) {
- return Optional.of(new LongMessage(record.get(), readFullBody(context, textSlide.getUri())));
- } else {
- return Optional.of(new LongMessage(record.get(), ""));
- }
- } else {
- return Optional.absent();
- }
- }
-
- @WorkerThread
- private Optional getSmsLongMessage(@NonNull SmsDatabase smsDatabase, long messageId) {
- Optional record = getSmsMessage(smsDatabase, messageId);
-
- if (record.isPresent()) {
- return Optional.of(new LongMessage(record.get(), ""));
- } else {
- return Optional.absent();
- }
- }
-
-
- @WorkerThread
- private Optional getMmsMessage(@NonNull MmsDatabase mmsDatabase, long messageId) {
- try (Cursor cursor = mmsDatabase.getMessage(messageId)) {
- return Optional.fromNullable((MmsMessageRecord) mmsDatabase.readerFor(cursor).getNext());
- }
- }
-
- @WorkerThread
- private Optional getSmsMessage(@NonNull SmsDatabase smsDatabase, long messageId) {
- try (Cursor cursor = smsDatabase.getMessageCursor(messageId)) {
- return Optional.fromNullable(smsDatabase.readerFor(cursor).getNext());
- }
- }
-
- private String readFullBody(@NonNull Context context, @NonNull Uri uri) {
- try (InputStream stream = PartAuthority.getAttachmentStream(context, uri)) {
- return Util.readFullyAsString(stream);
- } catch (IOException e) {
- Log.w(TAG, "Failed to read full text body.", e);
- return "";
- }
- }
-
- interface Callback {
- void onComplete(T result);
- }
-}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/longmessage/LongMessageViewModel.java b/app/src/main/java/org/thoughtcrime/securesms/longmessage/LongMessageViewModel.java
deleted file mode 100644
index 27495a492a..0000000000
--- a/app/src/main/java/org/thoughtcrime/securesms/longmessage/LongMessageViewModel.java
+++ /dev/null
@@ -1,84 +0,0 @@
-package org.thoughtcrime.securesms.longmessage;
-
-import android.app.Application;
-import androidx.lifecycle.LiveData;
-import androidx.lifecycle.MutableLiveData;
-import androidx.lifecycle.ViewModel;
-import androidx.lifecycle.ViewModelProvider;
-
-import android.database.ContentObserver;
-import android.net.Uri;
-import android.os.Handler;
-import androidx.annotation.NonNull;
-
-import org.thoughtcrime.securesms.database.DatabaseContentProviders;
-import org.session.libsignal.utilities.guava.Optional;
-
-class LongMessageViewModel extends ViewModel {
-
- private final Application application;
- private final LongMessageRepository repository;
- private final long messageId;
- private final boolean isMms;
-
- private final MutableLiveData> message;
- private final MessageObserver messageObserver;
-
- private LongMessageViewModel(@NonNull Application application, @NonNull LongMessageRepository repository, long messageId, boolean isMms) {
- this.application = application;
- this.repository = repository;
- this.messageId = messageId;
- this.isMms = isMms;
- this.message = new MutableLiveData<>();
- this.messageObserver = new MessageObserver(new Handler());
-
- repository.getMessage(application, messageId, isMms, longMessage -> {
- if (longMessage.isPresent()) {
- Uri uri = DatabaseContentProviders.Conversation.getUriForThread(longMessage.get().getMessageRecord().getThreadId());
- application.getContentResolver().registerContentObserver(uri, true, messageObserver);
- }
-
- message.postValue(longMessage);
- });
- }
-
- LiveData> getMessage() {
- return message;
- }
-
- @Override
- protected void onCleared() {
- application.getContentResolver().unregisterContentObserver(messageObserver);
- }
-
- private class MessageObserver extends ContentObserver {
- MessageObserver(Handler handler) {
- super(handler);
- }
-
- @Override
- public void onChange(boolean selfChange) {
- repository.getMessage(application, messageId, isMms, message::postValue);
- }
- }
-
- static class Factory extends ViewModelProvider.NewInstanceFactory {
-
- private final Application context;
- private final LongMessageRepository repository;
- private final long messageId;
- private final boolean isMms;
-
- public Factory(@NonNull Application application, @NonNull LongMessageRepository repository, long messageId, boolean isMms) {
- this.context = application;
- this.repository = repository;
- this.messageId = messageId;
- this.isMms = isMms;
- }
-
- @Override
- public @NonNull T create(@NonNull Class modelClass) {
- return modelClass.cast(new LongMessageViewModel(context, repository, messageId, isMms));
- }
- }
-}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/notifications/PushReceiver.kt b/app/src/main/java/org/thoughtcrime/securesms/notifications/PushReceiver.kt
index 3982113985..7fb9c12ab4 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/notifications/PushReceiver.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/notifications/PushReceiver.kt
@@ -10,6 +10,7 @@ import com.goterl.lazysodium.utils.Key
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
+import kotlinx.serialization.json.JsonBuilder
import org.session.libsession.messaging.jobs.BatchMessageReceiveJob
import org.session.libsession.messaging.jobs.JobQueue
import org.session.libsession.messaging.jobs.MessageReceiveParameters
@@ -28,6 +29,7 @@ private const val TAG = "PushHandler"
class PushReceiver @Inject constructor(@ApplicationContext val context: Context) {
private val sodium = LazySodiumAndroid(SodiumAndroid())
+ private val json = Json { ignoreUnknownKeys = true }
fun onPush(dataMap: Map?) {
onPush(dataMap?.asByteArray())
@@ -89,7 +91,7 @@ class PushReceiver @Inject constructor(@ApplicationContext val context: Context)
?: error("Failed to decode bencoded list from payload")
val metadataJson = (expectedList[0] as? BencodeString)?.value ?: error("no metadata")
- val metadata: PushNotificationMetadata = Json.decodeFromString(String(metadataJson))
+ val metadata: PushNotificationMetadata = json.decodeFromString(String(metadataJson))
return (expectedList.getOrNull(1) as? BencodeString)?.value.also {
// null content is valid only if we got a "data_too_long" flag
diff --git a/app/src/main/res/layout/activity_home.xml b/app/src/main/res/layout/activity_home.xml
index bf308612c5..124a44b374 100644
--- a/app/src/main/res/layout/activity_home.xml
+++ b/app/src/main/res/layout/activity_home.xml
@@ -110,7 +110,7 @@
android:layout_gravity="center"
android:textColor="?message_sent_text_color"
android:background="?colorAccent"
- android:textSize="9sp"
+ android:textSize="11sp"
android:paddingVertical="4dp"
android:paddingHorizontal="64dp"
android:gravity="center"
diff --git a/app/src/main/res/layout/longmessage_activity.xml b/app/src/main/res/layout/longmessage_activity.xml
deleted file mode 100644
index 0436fdae2f..0000000000
--- a/app/src/main/res/layout/longmessage_activity.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/libsession/src/main/java/org/session/libsession/messaging/jobs/AttachmentDownloadJob.kt b/libsession/src/main/java/org/session/libsession/messaging/jobs/AttachmentDownloadJob.kt
index fdeb3b4172..451081fd1a 100644
--- a/libsession/src/main/java/org/session/libsession/messaging/jobs/AttachmentDownloadJob.kt
+++ b/libsession/src/main/java/org/session/libsession/messaging/jobs/AttachmentDownloadJob.kt
@@ -89,16 +89,22 @@ class AttachmentDownloadJob(val attachmentID: Long, val databaseMessageID: Long)
}
val threadRecipient = storage.getRecipientForThread(threadID)
- val sender = if (messageDataProvider.isMmsOutgoing(databaseMessageID)) {
+ val selfSend = messageDataProvider.isMmsOutgoing(databaseMessageID)
+ val sender = if (selfSend) {
storage.getUserPublicKey()
} else {
messageDataProvider.getIndividualRecipientForMms(databaseMessageID)?.address?.serialize()
}
val contact = sender?.let { storage.getContactWithSessionID(it) }
- if (threadRecipient == null || sender == null || contact == null) {
+ if (threadRecipient == null || sender == null || (contact == null && !selfSend)) {
handleFailure(Error.NoSender, null)
return
}
+ if (!threadRecipient.isGroupRecipient && (contact?.isTrusted == true || storage.getUserPublicKey() != sender)) {
+ // if we aren't receiving a group message, a message from ourselves (self-send) and the contact sending is not trusted:
+ // do not continue, but do not fail
+ return
+ }
var tempFile: File? = null
try {