mirror of
https://github.com/oxen-io/session-android.git
synced 2024-11-24 10:35:19 +00:00
Merged dev
This commit is contained in:
commit
1a2df3798a
@ -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" />
|
||||||
|
@ -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,
|
||||||
|
@ -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)
|
||||||
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
@ -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() {
|
||||||
|
@ -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)
|
||||||
|
@ -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"/>
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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>
|
||||||
|
Loading…
Reference in New Issue
Block a user