Merged dev

This commit is contained in:
alansley 2024-08-02 15:20:19 +10:00
commit 1a2df3798a
14 changed files with 61 additions and 291 deletions

View File

@ -126,7 +126,7 @@
<activity <activity
android:name="org.thoughtcrime.securesms.home.HomeActivity" android:name="org.thoughtcrime.securesms.home.HomeActivity"
android:screenOrientation="portrait" android:screenOrientation="portrait"
android:launchMode="standard" android:launchMode="singleTask"
android:theme="@style/Theme.Session.DayNight.NoActionBar" /> android:theme="@style/Theme.Session.DayNight.NoActionBar" />
<activity <activity
android:name="org.thoughtcrime.securesms.messagerequests.MessageRequestsActivity" android:name="org.thoughtcrime.securesms.messagerequests.MessageRequestsActivity"
@ -328,7 +328,6 @@
<action android:name="android.service.chooser.ChooserTargetService" /> <action android:name="android.service.chooser.ChooserTargetService" />
</intent-filter> </intent-filter>
</service> </service>
<service android:name="org.thoughtcrime.securesms.service.GenericForegroundService" />
<receiver <receiver
android:name="org.thoughtcrime.securesms.notifications.MarkReadReceiver" android:name="org.thoughtcrime.securesms.notifications.MarkReadReceiver"
android:enabled="true" android:enabled="true"
@ -440,9 +439,7 @@
<action android:name="android.intent.action.BOOT_COMPLETED" /> <action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter> </intent-filter>
</receiver> </receiver>
<service
android:name="org.thoughtcrime.securesms.jobmanager.KeepAliveService"
android:enabled="@bool/enable_alarm_manager" />
<uses-library <uses-library
android:name="com.sec.android.app.multiwindow" android:name="com.sec.android.app.multiwindow"
android:required="false" /> android:required="false" />

View File

@ -215,16 +215,6 @@ public class ApplicationContext extends Application implements DefaultLifecycleO
MessagingModuleConfiguration.configure(this); MessagingModuleConfiguration.configure(this);
super.onCreate(); super.onCreate();
// we need to clear the snode and onionrequest databases once on first launch
// in order to apply a patch that adds a version number to the Snode objects.
if(!TextSecurePreferences.hasAppliedPatchSnodeVersion(this)) {
ThreadUtils.queue(() -> {
lokiAPIDatabase.clearSnodePool();
lokiAPIDatabase.clearOnionRequestPaths();
TextSecurePreferences.setHasAppliedPatchSnodeVersion(this, true);
});
}
messagingModuleConfiguration = new MessagingModuleConfiguration( messagingModuleConfiguration = new MessagingModuleConfiguration(
this, this,
storage, storage,

View File

@ -154,9 +154,6 @@ class HomeActivity : PassphraseRequiredActionBarActivity(),
override fun onCreate(savedInstanceState: Bundle?, isReady: Boolean) { override fun onCreate(savedInstanceState: Bundle?, isReady: Boolean) {
super.onCreate(savedInstanceState, isReady) super.onCreate(savedInstanceState, isReady)
// Bail if there is already an instance of the application running
if (!isTaskRoot) { finish(); return }
// Set content view // Set content view
binding = ActivityHomeBinding.inflate(layoutInflater) binding = ActivityHomeBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)

View File

@ -1,24 +0,0 @@
package org.thoughtcrime.securesms.jobmanager;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import androidx.annotation.Nullable;
/**
* Service that keeps the application in memory while the app is closed.
*
* Important: Should only be used on API < 26.
*/
public class KeepAliveService extends Service {
@Override
public @Nullable IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
}

View File

@ -8,7 +8,6 @@ import app.cash.copper.Query
import app.cash.copper.flow.observeQuery import app.cash.copper.flow.observeQuery
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import kotlin.coroutines.resume import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine import kotlin.coroutines.suspendCoroutine
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
@ -59,15 +58,15 @@ interface ConversationRepository {
fun deleteLocally(recipient: Recipient, message: MessageRecord) fun deleteLocally(recipient: Recipient, message: MessageRecord)
fun deleteAllLocalMessagesInThreadFromSenderOfMessage(messageRecord: MessageRecord) fun deleteAllLocalMessagesInThreadFromSenderOfMessage(messageRecord: MessageRecord)
fun setApproved(recipient: Recipient, isApproved: Boolean) fun setApproved(recipient: Recipient, isApproved: Boolean)
suspend fun deleteForEveryone(threadId: Long, recipient: Recipient, message: MessageRecord): ResultOf<Unit> suspend fun deleteForEveryone(threadId: Long, recipient: Recipient, message: MessageRecord): Result<Unit>
fun buildUnsendRequest(recipient: Recipient, message: MessageRecord): UnsendRequest? fun buildUnsendRequest(recipient: Recipient, message: MessageRecord): UnsendRequest?
suspend fun deleteMessageWithoutUnsendRequest(threadId: Long, messages: Set<MessageRecord>): ResultOf<Unit> suspend fun deleteMessageWithoutUnsendRequest(threadId: Long, messages: Set<MessageRecord>): Result<Unit>
suspend fun banUser(threadId: Long, recipient: Recipient): ResultOf<Unit> suspend fun banUser(threadId: Long, recipient: Recipient): Result<Unit>
suspend fun banAndDeleteAll(threadId: Long, recipient: Recipient): ResultOf<Unit> suspend fun banAndDeleteAll(threadId: Long, recipient: Recipient): Result<Unit>
suspend fun deleteThread(threadId: Long): ResultOf<Unit> suspend fun deleteThread(threadId: Long): Result<Unit>
suspend fun deleteMessageRequest(thread: ThreadRecord): ResultOf<Unit> suspend fun deleteMessageRequest(thread: ThreadRecord): Result<Unit>
suspend fun clearAllMessageRequests(block: Boolean): ResultOf<Unit> suspend fun clearAllMessageRequests(block: Boolean): Result<Unit>
suspend fun acceptMessageRequest(threadId: Long, recipient: Recipient): ResultOf<Unit> suspend fun acceptMessageRequest(threadId: Long, recipient: Recipient): Result<Unit>
fun declineMessageRequest(threadId: Long) fun declineMessageRequest(threadId: Long)
fun hasReceived(threadId: Long): Boolean fun hasReceived(threadId: Long): Boolean
} }
@ -185,7 +184,7 @@ class DefaultConversationRepository @Inject constructor(
threadId: Long, threadId: Long,
recipient: Recipient, recipient: Recipient,
message: MessageRecord message: MessageRecord
): ResultOf<Unit> = suspendCoroutine { continuation -> ): Result<Unit> = suspendCoroutine { continuation ->
buildUnsendRequest(recipient, message)?.let { unsendRequest -> buildUnsendRequest(recipient, message)?.let { unsendRequest ->
MessageSender.send(unsendRequest, recipient.address) MessageSender.send(unsendRequest, recipient.address)
} }
@ -196,10 +195,10 @@ class DefaultConversationRepository @Inject constructor(
OpenGroupApi.deleteMessage(messageServerID, openGroup.room, openGroup.server) OpenGroupApi.deleteMessage(messageServerID, openGroup.room, openGroup.server)
.success { .success {
messageDataProvider.deleteMessage(message.id, !message.isMms) messageDataProvider.deleteMessage(message.id, !message.isMms)
continuation.resume(ResultOf.Success(Unit)) continuation.resume(Result.success(Unit))
}.fail { error -> }.fail { error ->
Log.w("TAG", "Call to OpenGroupApi.deleteForEveryone failed - attempting to resume..") Log.w("TAG", "Call to OpenGroupApi.deleteForEveryone failed - attempting to resume..")
continuation.resumeWithException(error) continuation.resume(Result.failure(error))
} }
} }
@ -229,10 +228,10 @@ class DefaultConversationRepository @Inject constructor(
} }
SnodeAPI.deleteMessage(publicKey, listOf(serverHash)) SnodeAPI.deleteMessage(publicKey, listOf(serverHash))
.success { .success {
continuation.resume(ResultOf.Success(Unit)) continuation.resume(Result.success(Unit))
}.fail { error -> }.fail { error ->
Log.w("ConversationRepository", "Call to SnodeAPI.deleteMessage failed - attempting to resume..") Log.w("ConversationRepository", "Call to SnodeAPI.deleteMessage failed - attempting to resume..")
continuation.resumeWithException(error) continuation.resume(Result.failure(error))
} }
} }
} }
@ -250,7 +249,7 @@ class DefaultConversationRepository @Inject constructor(
override suspend fun deleteMessageWithoutUnsendRequest( override suspend fun deleteMessageWithoutUnsendRequest(
threadId: Long, threadId: Long,
messages: Set<MessageRecord> messages: Set<MessageRecord>
): ResultOf<Unit> = suspendCoroutine { continuation -> ): Result<Unit> = suspendCoroutine { continuation ->
val openGroup = lokiThreadDb.getOpenGroupChat(threadId) val openGroup = lokiThreadDb.getOpenGroupChat(threadId)
if (openGroup != null) { if (openGroup != null) {
val messageServerIDs = mutableMapOf<Long, MessageRecord>() val messageServerIDs = mutableMapOf<Long, MessageRecord>()
@ -264,7 +263,7 @@ class DefaultConversationRepository @Inject constructor(
.success { .success {
messageDataProvider.deleteMessage(message.id, !message.isMms) messageDataProvider.deleteMessage(message.id, !message.isMms)
}.fail { error -> }.fail { error ->
continuation.resumeWithException(error) continuation.resume(Result.failure(error))
} }
} }
} else { } else {
@ -276,22 +275,22 @@ class DefaultConversationRepository @Inject constructor(
} }
} }
} }
continuation.resume(ResultOf.Success(Unit)) continuation.resume(Result.success(Unit))
} }
override suspend fun banUser(threadId: Long, recipient: Recipient): ResultOf<Unit> = override suspend fun banUser(threadId: Long, recipient: Recipient): Result<Unit> =
suspendCoroutine { continuation -> suspendCoroutine { continuation ->
val accountID = recipient.address.toString() val accountID = recipient.address.toString()
val openGroup = lokiThreadDb.getOpenGroupChat(threadId)!! val openGroup = lokiThreadDb.getOpenGroupChat(threadId)!!
OpenGroupApi.ban(accountID, openGroup.room, openGroup.server) OpenGroupApi.ban(accountID, openGroup.room, openGroup.server)
.success { .success {
continuation.resume(ResultOf.Success(Unit)) continuation.resume(Result.success(Unit))
}.fail { error -> }.fail { error ->
continuation.resumeWithException(error) continuation.resume(Result.failure(error))
} }
} }
override suspend fun banAndDeleteAll(threadId: Long, recipient: Recipient): ResultOf<Unit> = override suspend fun banAndDeleteAll(threadId: Long, recipient: Recipient): Result<Unit> =
suspendCoroutine { continuation -> suspendCoroutine { continuation ->
// Note: This accountId could be the blinded Id // Note: This accountId could be the blinded Id
val accountID = recipient.address.toString() val accountID = recipient.address.toString()
@ -299,25 +298,25 @@ class DefaultConversationRepository @Inject constructor(
OpenGroupApi.banAndDeleteAll(accountID, openGroup.room, openGroup.server) OpenGroupApi.banAndDeleteAll(accountID, openGroup.room, openGroup.server)
.success { .success {
continuation.resume(ResultOf.Success(Unit)) continuation.resume(Result.success(Unit))
}.fail { error -> }.fail { error ->
continuation.resumeWithException(error) continuation.resume(Result.failure(error))
} }
} }
override suspend fun deleteThread(threadId: Long): ResultOf<Unit> { override suspend fun deleteThread(threadId: Long): Result<Unit> {
sessionJobDb.cancelPendingMessageSendJobs(threadId) sessionJobDb.cancelPendingMessageSendJobs(threadId)
storage.deleteConversation(threadId) storage.deleteConversation(threadId)
return ResultOf.Success(Unit) return Result.success(Unit)
} }
override suspend fun deleteMessageRequest(thread: ThreadRecord): ResultOf<Unit> { override suspend fun deleteMessageRequest(thread: ThreadRecord): Result<Unit> {
sessionJobDb.cancelPendingMessageSendJobs(thread.threadId) sessionJobDb.cancelPendingMessageSendJobs(thread.threadId)
storage.deleteConversation(thread.threadId) storage.deleteConversation(thread.threadId)
return ResultOf.Success(Unit) return Result.success(Unit)
} }
override suspend fun clearAllMessageRequests(block: Boolean): ResultOf<Unit> { override suspend fun clearAllMessageRequests(block: Boolean): Result<Unit> {
threadDb.readerFor(threadDb.unapprovedConversationList).use { reader -> threadDb.readerFor(threadDb.unapprovedConversationList).use { reader ->
while (reader.next != null) { while (reader.next != null) {
deleteMessageRequest(reader.current) deleteMessageRequest(reader.current)
@ -325,18 +324,18 @@ class DefaultConversationRepository @Inject constructor(
if (block) { setBlocked(recipient, true) } if (block) { setBlocked(recipient, true) }
} }
} }
return ResultOf.Success(Unit) return Result.success(Unit)
} }
override suspend fun acceptMessageRequest(threadId: Long, recipient: Recipient): ResultOf<Unit> = suspendCoroutine { continuation -> override suspend fun acceptMessageRequest(threadId: Long, recipient: Recipient): Result<Unit> = suspendCoroutine { continuation ->
storage.setRecipientApproved(recipient, true) storage.setRecipientApproved(recipient, true)
val message = MessageRequestResponse(true) val message = MessageRequestResponse(true)
MessageSender.send(message, Destination.from(recipient.address), isSyncMessage = recipient.isLocalNumber) MessageSender.send(message, Destination.from(recipient.address), isSyncMessage = recipient.isLocalNumber)
.success { .success {
threadDb.setHasSent(threadId, true) threadDb.setHasSent(threadId, true)
continuation.resume(ResultOf.Success(Unit)) continuation.resume(Result.success(Unit))
}.fail { error -> }.fail { error ->
continuation.resumeWithException(error) continuation.resume(Result.failure(error))
} }
} }

View File

@ -1,43 +0,0 @@
package org.thoughtcrime.securesms.repository
import kotlinx.coroutines.CancellationException
sealed class ResultOf<out T> {
data class Success<out R>(val value: R) : ResultOf<R>()
data class Failure(val throwable: Throwable) : ResultOf<Nothing>()
inline fun onFailure(block: (throwable: Throwable) -> Unit) = this.also {
if (this is Failure) {
block(throwable)
}
}
inline fun onSuccess(block: (value: T) -> Unit) = this.also {
if (this is Success) {
block(value)
}
}
inline fun <R> flatMap(mapper: (T) -> R): ResultOf<R> = when (this) {
is Success -> wrap { mapper(value) }
is Failure -> Failure(throwable)
}
fun getOrThrow(): T = when (this) {
is Success -> value
is Failure -> throw throwable
}
companion object {
inline fun <T> wrap(block: () -> T): ResultOf<T> =
try {
Success(block())
} catch (e: CancellationException) {
throw e
} catch (e: Exception) {
Failure(e)
}
}
}

View File

@ -1,128 +0,0 @@
package org.thoughtcrime.securesms.service;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
import androidx.core.content.ContextCompat;
import org.session.libsignal.utilities.Log;
import org.session.libsignal.utilities.guava.Preconditions;
import org.thoughtcrime.securesms.home.HomeActivity;
import org.thoughtcrime.securesms.notifications.NotificationChannels;
import network.loki.messenger.R;
public class GenericForegroundService extends Service {
private static final String TAG = GenericForegroundService.class.getSimpleName();
private static final int NOTIFICATION_ID = 827353982;
private static final String EXTRA_TITLE = "extra_title";
private static final String EXTRA_CHANNEL_ID = "extra_channel_id";
private static final String EXTRA_ICON_RES = "extra_icon_res";
private static final String ACTION_START = "start";
private static final String ACTION_STOP = "stop";
private int foregroundCount;
private String activeTitle;
private String activeChannelId;
private int activeIconRes;
@Override
public void onCreate() {
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
synchronized (GenericForegroundService.class) {
if (intent != null && ACTION_START.equals(intent.getAction())) handleStart(intent);
else if (intent != null && ACTION_STOP.equals(intent.getAction())) handleStop();
else throw new IllegalStateException("Action needs to be START or STOP.");
return START_NOT_STICKY;
}
}
private void handleStart(@NonNull Intent intent) {
String title = Preconditions.checkNotNull(intent.getStringExtra(EXTRA_TITLE));
String channelId = Preconditions.checkNotNull(intent.getStringExtra(EXTRA_CHANNEL_ID));
int iconRes = intent.getIntExtra(EXTRA_ICON_RES, R.drawable.ic_notification);
Log.i(TAG, "handleStart() Title: " + title + " ChannelId: " + channelId);
foregroundCount++;
if (foregroundCount == 1) {
Log.d(TAG, "First request. Title: " + title + " ChannelId: " + channelId);
activeTitle = title;
activeChannelId = channelId;
activeIconRes = iconRes;
}
postObligatoryForegroundNotification(activeTitle, activeChannelId, activeIconRes);
}
private void handleStop() {
Log.i(TAG, "handleStop()");
postObligatoryForegroundNotification(activeTitle, activeChannelId, activeIconRes);
foregroundCount--;
if (foregroundCount == 0) {
Log.d(TAG, "Last request. Ending foreground service.");
stopForeground(true);
stopSelf();
}
}
private void postObligatoryForegroundNotification(String title, String channelId, @DrawableRes int iconRes) {
startForeground(NOTIFICATION_ID, new NotificationCompat.Builder(this, channelId)
.setSmallIcon(iconRes)
.setContentTitle(title)
.setContentIntent(PendingIntent.getActivity(this, 0, new Intent(this, HomeActivity.class), PendingIntent.FLAG_IMMUTABLE))
.build());
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
public static void startForegroundTask(@NonNull Context context, @NonNull String task) {
startForegroundTask(context, task, NotificationChannels.OTHER);
}
public static void startForegroundTask(@NonNull Context context, @NonNull String task, @NonNull String channelId) {
startForegroundTask(context, task, channelId, R.drawable.ic_notification);
}
public static void startForegroundTask(@NonNull Context context, @NonNull String task, @NonNull String channelId, @DrawableRes int iconRes) {
Intent intent = new Intent(context, GenericForegroundService.class);
intent.setAction(ACTION_START);
intent.putExtra(EXTRA_TITLE, task);
intent.putExtra(EXTRA_CHANNEL_ID, channelId);
intent.putExtra(EXTRA_ICON_RES, iconRes);
ContextCompat.startForegroundService(context, intent);
}
public static void stopForegroundTask(@NonNull Context context) {
Intent intent = new Intent(context, GenericForegroundService.class);
intent.setAction(ACTION_STOP);
ContextCompat.startForegroundService(context, intent);
}
}

View File

@ -36,7 +36,10 @@ import android.os.SystemClock;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationCompat;
import androidx.core.app.ServiceCompat;
import com.squareup.phrase.Phrase; import com.squareup.phrase.Phrase;
import java.util.concurrent.TimeUnit;
import network.loki.messenger.R;
import org.session.libsession.utilities.ServiceUtil; import org.session.libsession.utilities.ServiceUtil;
import org.session.libsession.utilities.TextSecurePreferences; import org.session.libsession.utilities.TextSecurePreferences;
import org.session.libsignal.utilities.Log; import org.session.libsignal.utilities.Log;
@ -45,8 +48,6 @@ import org.thoughtcrime.securesms.DatabaseUpgradeActivity;
import org.thoughtcrime.securesms.DummyActivity; import org.thoughtcrime.securesms.DummyActivity;
import org.thoughtcrime.securesms.home.HomeActivity; import org.thoughtcrime.securesms.home.HomeActivity;
import org.thoughtcrime.securesms.notifications.NotificationChannels; import org.thoughtcrime.securesms.notifications.NotificationChannels;
import java.util.concurrent.TimeUnit;
import network.loki.messenger.R;
/** /**
* Small service that stays running to keep a key cached in memory. * Small service that stays running to keep a key cached in memory.
@ -121,7 +122,7 @@ public class KeyCachingService extends Service {
KeyCachingService.masterSecret = masterSecret; KeyCachingService.masterSecret = masterSecret;
foregroundService(); foregroundService();
new AsyncTask<Void, Void, Void>() { new AsyncTask<Void, Void, Void>() {
@Override @Override
protected Void doInBackground(Void... params) { protected Void doInBackground(Void... params) {
@ -257,11 +258,18 @@ public class KeyCachingService extends Service {
builder.setContentIntent(buildLaunchIntent()); builder.setContentIntent(buildLaunchIntent());
stopForeground(true); stopForeground(true);
int type = 0;
if (Build.VERSION.SDK_INT >= 34) { if (Build.VERSION.SDK_INT >= 34) {
startForeground(SERVICE_RUNNING_ID, builder.build(), ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE); type = ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE;
} else {
startForeground(SERVICE_RUNNING_ID, builder.build());
} }
ServiceCompat.startForeground(
this,
SERVICE_RUNNING_ID,
builder.build(),
type
);
} }
private PendingIntent buildLockIntent() { private PendingIntent buildLockIntent() {

View File

@ -7,9 +7,12 @@ import android.content.Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
import android.content.IntentFilter import android.content.IntentFilter
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.content.pm.ServiceInfo
import android.media.AudioManager import android.media.AudioManager
import android.os.Build
import android.os.ResultReceiver import android.os.ResultReceiver
import android.telephony.TelephonyManager import android.telephony.TelephonyManager
import androidx.core.app.ServiceCompat
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
import androidx.lifecycle.LifecycleService import androidx.lifecycle.LifecycleService
@ -723,9 +726,11 @@ class WebRtcCallService : LifecycleService(), CallManager.WebRtcListener {
private fun setCallInProgressNotification(type: Int, recipient: Recipient?) { private fun setCallInProgressNotification(type: Int, recipient: Recipient?) {
try { try {
startForeground( ServiceCompat.startForeground(
this,
CallNotificationBuilder.WEBRTC_NOTIFICATION, CallNotificationBuilder.WEBRTC_NOTIFICATION,
CallNotificationBuilder.getCallInProgressNotification(this, type, recipient) CallNotificationBuilder.getCallInProgressNotification(this, type, recipient),
if (Build.VERSION.SDK_INT >= 30) ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE else 0
) )
} catch (e: IllegalStateException) { } catch (e: IllegalStateException) {
Log.e(TAG, "Failed to setCallInProgressNotification as a foreground service for type: ${type}, trying to update instead", e) Log.e(TAG, "Failed to setCallInProgressNotification as a foreground service for type: ${type}, trying to update instead", e)

View File

@ -1,7 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<bool name="enable_alarm_manager">true</bool>
<bool name="enable_job_service">false</bool>
<attr name="searchBackgroundColor" format="color"/> <attr name="searchBackgroundColor" format="color"/>
<attr name="searchIconColor" format="color|reference"/> <attr name="searchIconColor" format="color|reference"/>
<attr name="searchTextColor" format="color|reference"/> <attr name="searchTextColor" format="color|reference"/>

View File

@ -3,14 +3,12 @@ package org.thoughtcrime.securesms.conversation.v2
import com.goterl.lazysodium.utils.KeyPair import com.goterl.lazysodium.utils.KeyPair
import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import org.hamcrest.CoreMatchers.endsWith import org.hamcrest.CoreMatchers.endsWith
import org.hamcrest.CoreMatchers.equalTo import org.hamcrest.CoreMatchers.equalTo
import org.hamcrest.CoreMatchers.notNullValue import org.hamcrest.CoreMatchers.notNullValue
import org.hamcrest.CoreMatchers.nullValue import org.hamcrest.CoreMatchers.nullValue
import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.MatcherAssert.assertThat
import org.junit.Before import org.junit.Before
import org.junit.BeforeClass
import org.junit.Test import org.junit.Test
import org.mockito.Mockito import org.mockito.Mockito
import org.mockito.Mockito.anyLong import org.mockito.Mockito.anyLong
@ -20,14 +18,11 @@ import org.mockito.kotlin.any
import org.mockito.kotlin.mock import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever import org.mockito.kotlin.whenever
import org.session.libsession.utilities.recipients.Recipient import org.session.libsession.utilities.recipients.Recipient
import org.session.libsignal.utilities.Log
import org.thoughtcrime.securesms.BaseViewModelTest import org.thoughtcrime.securesms.BaseViewModelTest
import org.thoughtcrime.securesms.NoOpLogger
import org.thoughtcrime.securesms.database.MmsDatabase import org.thoughtcrime.securesms.database.MmsDatabase
import org.thoughtcrime.securesms.database.Storage import org.thoughtcrime.securesms.database.Storage
import org.thoughtcrime.securesms.database.model.MessageRecord import org.thoughtcrime.securesms.database.model.MessageRecord
import org.thoughtcrime.securesms.repository.ConversationRepository import org.thoughtcrime.securesms.repository.ConversationRepository
import org.thoughtcrime.securesms.repository.ResultOf
class ConversationViewModelTest: BaseViewModelTest() { class ConversationViewModelTest: BaseViewModelTest() {
@ -107,7 +102,7 @@ class ConversationViewModelTest: BaseViewModelTest() {
val message = mock<MessageRecord>() val message = mock<MessageRecord>()
val error = Throwable() val error = Throwable()
whenever(repository.deleteForEveryone(anyLong(), any(), any())) whenever(repository.deleteForEveryone(anyLong(), any(), any()))
.thenReturn(ResultOf.Failure(error)) .thenReturn(Result.failure(error))
viewModel.deleteForEveryone(message) viewModel.deleteForEveryone(message)
@ -120,7 +115,7 @@ class ConversationViewModelTest: BaseViewModelTest() {
val message = mock<MessageRecord>() val message = mock<MessageRecord>()
val error = Throwable() val error = Throwable()
whenever(repository.deleteMessageWithoutUnsendRequest(anyLong(), anySet())) whenever(repository.deleteMessageWithoutUnsendRequest(anyLong(), anySet()))
.thenReturn(ResultOf.Failure(error)) .thenReturn(Result.failure(error))
viewModel.deleteMessagesWithoutUnsendRequest(setOf(message)) viewModel.deleteMessagesWithoutUnsendRequest(setOf(message))
@ -130,7 +125,7 @@ class ConversationViewModelTest: BaseViewModelTest() {
@Test @Test
fun `should emit error message on ban user failure`() = runBlockingTest { fun `should emit error message on ban user failure`() = runBlockingTest {
val error = Throwable() val error = Throwable()
whenever(repository.banUser(anyLong(), any())).thenReturn(ResultOf.Failure(error)) whenever(repository.banUser(anyLong(), any())).thenReturn(Result.failure(error))
viewModel.banUser(recipient) viewModel.banUser(recipient)
@ -139,7 +134,7 @@ class ConversationViewModelTest: BaseViewModelTest() {
@Test @Test
fun `should emit a message on ban user success`() = runBlockingTest { fun `should emit a message on ban user success`() = runBlockingTest {
whenever(repository.banUser(anyLong(), any())).thenReturn(ResultOf.Success(Unit)) whenever(repository.banUser(anyLong(), any())).thenReturn(Result.success(Unit))
viewModel.banUser(recipient) viewModel.banUser(recipient)
@ -152,7 +147,7 @@ class ConversationViewModelTest: BaseViewModelTest() {
@Test @Test
fun `should emit error message on ban user and delete all failure`() = runBlockingTest { fun `should emit error message on ban user and delete all failure`() = runBlockingTest {
val error = Throwable() val error = Throwable()
whenever(repository.banAndDeleteAll(anyLong(), any())).thenReturn(ResultOf.Failure(error)) whenever(repository.banAndDeleteAll(anyLong(), any())).thenReturn(Result.failure(error))
viewModel.banAndDeleteAll(messageRecord) viewModel.banAndDeleteAll(messageRecord)
@ -161,7 +156,7 @@ class ConversationViewModelTest: BaseViewModelTest() {
@Test @Test
fun `should emit a message on ban user and delete all success`() = runBlockingTest { fun `should emit a message on ban user and delete all success`() = runBlockingTest {
whenever(repository.banAndDeleteAll(anyLong(), any())).thenReturn(ResultOf.Success(Unit)) whenever(repository.banAndDeleteAll(anyLong(), any())).thenReturn(Result.success(Unit))
viewModel.banAndDeleteAll(messageRecord) viewModel.banAndDeleteAll(messageRecord)
@ -188,7 +183,7 @@ class ConversationViewModelTest: BaseViewModelTest() {
@Test @Test
fun `should remove shown message`() = runBlockingTest { fun `should remove shown message`() = runBlockingTest {
// Given that a message is generated // Given that a message is generated
whenever(repository.banUser(anyLong(), any())).thenReturn(ResultOf.Success(Unit)) whenever(repository.banUser(anyLong(), any())).thenReturn(Result.success(Unit))
viewModel.banUser(recipient) viewModel.banUser(recipient)
assertThat(viewModel.uiState.value.uiMessages.size, equalTo(1)) assertThat(viewModel.uiState.value.uiMessages.size, equalTo(1))
// When the message is shown // When the message is shown

View File

@ -193,17 +193,6 @@ object OnionRequestAPI {
val result = listOf( guardSnode ) + (0 until (pathSize - 1)).mapIndexed() { index, _ -> val result = listOf( guardSnode ) + (0 until (pathSize - 1)).mapIndexed() { index, _ ->
var pathSnode = unusedSnodes.getRandomElement() var pathSnode = unusedSnodes.getRandomElement()
// For the last node: We need to make sure the version is >= 2.8.0
// to help with an issue that will disappear once the nodes are all updated
if(index == pathSize - 2) {
val suitableSnodes = unusedSnodes.filter { Util.compareVersions(it.version, "2.8.0") >= 0 }
pathSnode = if (suitableSnodes.isNotEmpty()) {
suitableSnodes.random()
} else {
throw InsufficientSnodesException()
}
}
// remove the snode from the unused list and return it // remove the snode from the unused list and return it
unusedSnodes = unusedSnodes.minus(pathSnode) unusedSnodes = unusedSnodes.minus(pathSnode)
pathSnode pathSnode

View File

@ -296,8 +296,6 @@ interface TextSecurePreferences {
const val ALLOW_MESSAGE_REQUESTS = "libsession.ALLOW_MESSAGE_REQUESTS" const val ALLOW_MESSAGE_REQUESTS = "libsession.ALLOW_MESSAGE_REQUESTS"
const val PATCH_SNODE_VERSION_2024_07_23 = "libsession.patch_snode_version_2024_07_23"
@JvmStatic @JvmStatic
fun getLastConfigurationSyncTime(context: Context): Long { fun getLastConfigurationSyncTime(context: Context): Long {
return getLongPreference(context, LAST_CONFIGURATION_SYNC_TIME, 0) return getLongPreference(context, LAST_CONFIGURATION_SYNC_TIME, 0)
@ -982,16 +980,6 @@ interface TextSecurePreferences {
fun clearAll(context: Context) { fun clearAll(context: Context) {
getDefaultSharedPreferences(context).edit().clear().commit() getDefaultSharedPreferences(context).edit().clear().commit()
} }
@JvmStatic
fun hasAppliedPatchSnodeVersion(context: Context): Boolean {
return getBooleanPreference(context, PATCH_SNODE_VERSION_2024_07_23, false)
}
@JvmStatic
fun setHasAppliedPatchSnodeVersion(context: Context, applied: Boolean) {
setBooleanPreference(context, PATCH_SNODE_VERSION_2024_07_23, applied)
}
} }
} }

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<bool name="enable_alarm_manager">true</bool>
<bool name="enable_job_service">false</bool> <bool name="enable_job_service">false</bool>
<bool name="screen_security_default">true</bool> <bool name="screen_security_default">true</bool>
</resources> </resources>