diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index afa349d56d..3bf92947d0 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -770,22 +770,6 @@
-
-
-
-
-
-
-
-
diff --git a/app/src/main/java/org/thoughtcrime/securesms/MediaPreviewActivity.java b/app/src/main/java/org/thoughtcrime/securesms/MediaPreviewActivity.java
index 551eda0ccc..6cdd5f61f9 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/MediaPreviewActivity.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/MediaPreviewActivity.java
@@ -568,26 +568,11 @@ public final class MediaPreviewActivity extends PassphraseRequiredActivity
if (item == 0) {
viewPagerListener.onPageSelected(0);
}
-
- cursor.registerContentObserver(new ContentObserver(new Handler(getMainLooper())) {
- @Override
- public void onChange(boolean selfChange) {
- onMediaChange();
- }
- });
} else {
mediaNotAvailable();
}
}
- private void onMediaChange() {
- MediaItemAdapter adapter = (MediaItemAdapter) mediaPager.getAdapter();
-
- if (adapter != null) {
- adapter.checkMedia(mediaPager.getCurrentItem());
- }
- }
-
@Override
public void onLoaderReset(@NonNull Loader> loader) {
@@ -701,11 +686,6 @@ public final class MediaPreviewActivity extends PassphraseRequiredActivity
public boolean hasFragmentFor(int position) {
return mediaPreviewFragment != null;
}
-
- @Override
- public void checkMedia(int currentItem) {
-
- }
}
private static void anchorMarginsToBottomInsets(@NonNull View viewToAnchor) {
@@ -824,14 +804,6 @@ public final class MediaPreviewActivity extends PassphraseRequiredActivity
return mediaFragments.containsKey(position);
}
- @Override
- public void checkMedia(int position) {
- MediaPreviewFragment fragment = mediaFragments.get(position);
- if (fragment != null) {
- fragment.checkMediaStillAvailable();
- }
- }
-
private int getCursorPosition(int position) {
if (leftIsRecent) return position;
else return cursor.getCount() - 1 - position;
@@ -870,6 +842,5 @@ public final class MediaPreviewActivity extends PassphraseRequiredActivity
void pause(int position);
@Nullable View getPlaybackControls(int position);
boolean hasFragmentFor(int position);
- void checkMedia(int currentItem);
}
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationSearchViewModel.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationSearchViewModel.java
index 6c6a53a4fb..bf609f5c3b 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationSearchViewModel.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationSearchViewModel.java
@@ -9,10 +9,10 @@ import androidx.lifecycle.MutableLiveData;
import org.signal.core.util.ThreadUtil;
import org.thoughtcrime.securesms.search.MessageResult;
-import org.thoughtcrime.securesms.database.CursorList;
import org.thoughtcrime.securesms.search.SearchRepository;
import org.thoughtcrime.securesms.util.Debouncer;
+import java.util.Collections;
import java.util.List;
public class ConversationSearchViewModel extends AndroidViewModel {
@@ -39,7 +39,7 @@ public class ConversationSearchViewModel extends AndroidViewModel {
void onQueryUpdated(@NonNull String query, long threadId, boolean forced) {
if (firstSearch && query.length() < 2) {
- result.postValue(new SearchResult(CursorList.emptyList(), 0));
+ result.postValue(new SearchResult(Collections.emptyList(), 0));
return;
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationStickerViewModel.java b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationStickerViewModel.java
index ca6bd16b71..d13fd12f5a 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationStickerViewModel.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/ConversationStickerViewModel.java
@@ -1,9 +1,6 @@
package org.thoughtcrime.securesms.conversation;
import android.app.Application;
-import android.database.ContentObserver;
-import android.os.Handler;
-import android.os.Looper;
import android.text.TextUtils;
import androidx.annotation.NonNull;
@@ -12,39 +9,34 @@ import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
-import org.thoughtcrime.securesms.components.emoji.EmojiUtil;
-import org.thoughtcrime.securesms.database.CursorList;
-import org.thoughtcrime.securesms.database.DatabaseContentProviders;
+import org.thoughtcrime.securesms.database.DatabaseObserver;
import org.thoughtcrime.securesms.database.model.StickerRecord;
+import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.emoji.EmojiSource;
import org.thoughtcrime.securesms.stickers.StickerSearchRepository;
import org.thoughtcrime.securesms.util.Throttler;
+import java.util.Collections;
import java.util.List;
class ConversationStickerViewModel extends ViewModel {
- private final Application application;
private final StickerSearchRepository repository;
private final MutableLiveData> stickers;
private final MutableLiveData stickersAvailable;
private final Throttler availabilityThrottler;
- private final ContentObserver packObserver;
+ private final DatabaseObserver.Observer packObserver;
private ConversationStickerViewModel(@NonNull Application application, @NonNull StickerSearchRepository repository) {
- this.application = application;
this.repository = repository;
this.stickers = new MutableLiveData<>();
this.stickersAvailable = new MutableLiveData<>();
this.availabilityThrottler = new Throttler(500);
- this.packObserver = new ContentObserver(new Handler(Looper.getMainLooper())) {
- @Override
- public void onChange(boolean selfChange) {
- availabilityThrottler.publish(() -> repository.getStickerFeatureAvailability(stickersAvailable::postValue));
- }
+ this.packObserver = () -> {
+ availabilityThrottler.publish(() -> repository.getStickerFeatureAvailability(stickersAvailable::postValue));
};
- application.getContentResolver().registerContentObserver(DatabaseContentProviders.StickerPack.CONTENT_URI, true, packObserver);
+ ApplicationDependencies.getDatabaseObserver().registerStickerPackObserver(packObserver);
}
@NonNull LiveData> getStickerResults() {
@@ -58,7 +50,7 @@ class ConversationStickerViewModel extends ViewModel {
void onInputTextUpdated(@NonNull String text) {
if (TextUtils.isEmpty(text) || text.length() > EmojiSource.getLatest().getMaxEmojiLength()) {
- stickers.setValue(CursorList.emptyList());
+ stickers.setValue(Collections.emptyList());
} else {
repository.searchByEmoji(text, stickers::postValue);
}
@@ -66,7 +58,7 @@ class ConversationStickerViewModel extends ViewModel {
@Override
protected void onCleared() {
- application.getContentResolver().unregisterContentObserver(packObserver);
+ ApplicationDependencies.getDatabaseObserver().unregisterObserver(packObserver);
}
static class Factory extends ViewModelProvider.NewInstanceFactory {
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/AttachmentDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/AttachmentDatabase.java
index a8bb37fc46..03dbd44676 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/AttachmentDatabase.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/AttachmentDatabase.java
@@ -317,15 +317,6 @@ public class AttachmentDatabase extends Database {
return false;
}
- public boolean hasAttachmentFilesForMessage(long mmsId) {
- String selection = MMS_ID + " = ? AND (" + DATA + " NOT NULL OR " + TRANSFER_STATE + " != ?)";
- String[] args = new String[] { String.valueOf(mmsId), String.valueOf(TRANSFER_PROGRESS_DONE) };
-
- try (Cursor cursor = databaseHelper.getSignalReadableDatabase().query(TABLE_NAME, null, selection, args, null, null, "1")) {
- return cursor != null && cursor.moveToFirst();
- }
- }
-
public @NonNull List getPendingAttachments() {
final SQLiteDatabase database = databaseHelper.getSignalReadableDatabase();
final List attachments = new LinkedList<>();
@@ -343,8 +334,7 @@ public class AttachmentDatabase extends Database {
return attachments;
}
- @SuppressWarnings("ResultOfMethodCallIgnored")
- public void deleteAttachmentsForMessage(long mmsId) {
+ public boolean deleteAttachmentsForMessage(long mmsId) {
Log.d(TAG, "[deleteAttachmentsForMessage] mmsId: " + mmsId);
SQLiteDatabase database = databaseHelper.getSignalWritableDatabase();
@@ -365,8 +355,10 @@ public class AttachmentDatabase extends Database {
cursor.close();
}
- database.delete(TABLE_NAME, MMS_ID + " = ?", new String[] {mmsId + ""});
+ int deleteCount = database.delete(TABLE_NAME, MMS_ID + " = ?", new String[] {mmsId + ""});
notifyAttachmentListeners();
+
+ return deleteCount > 0;
}
/**
@@ -631,6 +623,7 @@ public class AttachmentDatabase extends Database {
notifyConversationListeners(threadId);
notifyConversationListListeners();
+ notifyAttachmentListeners();
}
if (transferFile != null) {
@@ -1273,6 +1266,9 @@ public class AttachmentDatabase extends Database {
Log.d(TAG, "Inserting attachment for mms id: " + mmsId);
SQLiteDatabase database = databaseHelper.getSignalWritableDatabase();
+ AttachmentId attachmentId = null;
+ boolean notifyPacks = false;
+
database.beginTransaction();
try {
DataInfo dataInfo = null;
@@ -1347,20 +1343,23 @@ public class AttachmentDatabase extends Database {
}
}
- boolean notifyPacks = attachment.isSticker() && !hasStickerAttachments();
- long rowId = database.insert(TABLE_NAME, null, contentValues);
- AttachmentId attachmentId = new AttachmentId(rowId, uniqueId);
+ long rowId = database.insert(TABLE_NAME, null, contentValues);
- if (notifyPacks) {
- notifyStickerPackListeners();
- }
+ attachmentId = new AttachmentId(rowId, uniqueId);
+ notifyPacks = attachment.isSticker() && !hasStickerAttachments();
database.setTransactionSuccessful();
-
- return attachmentId;
} finally {
database.endTransaction();
}
+
+ if (notifyPacks) {
+ notifyStickerPackListeners();
+ }
+
+ notifyAttachmentListeners();
+
+ return attachmentId;
}
private @Nullable DatabaseAttachment findTemplateAttachment(@NonNull String dataHash) {
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/CursorList.java b/app/src/main/java/org/thoughtcrime/securesms/database/CursorList.java
deleted file mode 100644
index 9c40e19ecd..0000000000
--- a/app/src/main/java/org/thoughtcrime/securesms/database/CursorList.java
+++ /dev/null
@@ -1,205 +0,0 @@
-package org.thoughtcrime.securesms.database;
-
-import android.database.ContentObserver;
-import android.database.Cursor;
-import android.database.MatrixCursor;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.ListIterator;
-
-/**
- * A list backed by a {@link Cursor} that retrieves models using a provided {@link ModelBuilder}.
- * Allows you to abstract away the use of a {@link Cursor} while still getting the benefits of a
- * {@link Cursor} (e.g. windowing).
- *
- * The one special consideration that must be made is that because this contains a cursor, you must
- * call {@link #close()} when you are finished with it.
- *
- * Given that this is cursor-backed, it is effectively immutable.
- */
-public class CursorList implements List, ObservableContent {
-
- private final Cursor cursor;
- private final ModelBuilder modelBuilder;
-
- public CursorList(@NonNull Cursor cursor, @NonNull ModelBuilder modelBuilder) {
- this.cursor = cursor;
- this.modelBuilder = modelBuilder;
-
- forceQueryLoad();
- }
-
- public static CursorList emptyList() {
- //noinspection ConstantConditions,unchecked
- return (CursorList) new CursorList(emptyCursor(), null);
- }
-
- private static Cursor emptyCursor() {
- return new MatrixCursor(new String[] { "a" }, 0);
- }
-
- @Override
- public int size() {
- return cursor.getCount();
- }
-
- @Override
- public boolean isEmpty() {
- return size() == 0;
- }
-
- @Override
- public boolean contains(Object o) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public @NonNull Iterator iterator() {
- return new Iterator() {
- int index = 0;
-
- @Override
- public boolean hasNext() {
- return cursor.getCount() > 0 && !cursor.isLast();
- }
-
- @Override
- public T next() {
- cursor.moveToPosition(index++);
- return modelBuilder.build(cursor);
- }
- };
- }
-
- @Override
- public @NonNull Object[] toArray() {
- Object[] out = new Object[size()];
- for (int i = 0; i < cursor.getCount(); i++) {
- cursor.moveToPosition(i);
- out[i] = modelBuilder.build(cursor);
- }
- return out;
- }
-
- @Override
- public boolean add(T o) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean remove(Object o) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean addAll(@NonNull Collection collection) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean addAll(int i, @NonNull Collection collection) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void clear() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public T get(int i) {
- cursor.moveToPosition(i);
- return modelBuilder.build(cursor);
- }
-
- @Override
- public T set(int i, T o) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void add(int i, T o) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public T remove(int i) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int indexOf(Object o) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public int lastIndexOf(Object o) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public @NonNull ListIterator listIterator() {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public @NonNull ListIterator listIterator(int i) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public @NonNull List subList(int i, int i1) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean retainAll(@NonNull Collection collection) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean removeAll(@NonNull Collection collection) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public boolean containsAll(@NonNull Collection collection) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public @NonNull T[] toArray(@Nullable Object[] objects) {
- throw new UnsupportedOperationException();
- }
-
- @Override
- public void close() {
- if (!cursor.isClosed()) {
- cursor.close();
- }
- }
-
- @Override
- public void registerContentObserver(@NonNull ContentObserver observer) {
- cursor.registerContentObserver(observer);
- }
-
- @Override
- public void unregisterContentObserver(@NonNull ContentObserver observer) {
- cursor.unregisterContentObserver(observer);
- }
-
- private void forceQueryLoad() {
- cursor.getCount();
- }
-
- public interface ModelBuilder {
- T build(@NonNull Cursor cursor);
- }
-}
-
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/Database.java b/app/src/main/java/org/thoughtcrime/securesms/database/Database.java
index ef9b971c7d..f0220f4813 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/Database.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/Database.java
@@ -64,47 +64,16 @@ public abstract class Database {
ApplicationDependencies.getDatabaseObserver().notifyConversationListListeners();
}
- protected void notifyStickerListeners() {
- context.getContentResolver().notifyChange(DatabaseContentProviders.Sticker.CONTENT_URI, null);
- }
-
protected void notifyStickerPackListeners() {
ApplicationDependencies.getDatabaseObserver().notifyStickerPackObservers();
}
- @Deprecated
- protected void setNotifyConversationListeners(Cursor cursor, long threadId) {
- cursor.setNotificationUri(context.getContentResolver(), DatabaseContentProviders.Conversation.getUriForThread(threadId));
- }
-
- @Deprecated
- protected void setNotifyConversationListeners(Cursor cursor) {
- cursor.setNotificationUri(context.getContentResolver(), DatabaseContentProviders.Conversation.getUriForAllThreads());
- }
-
- @Deprecated
- protected void setNotifyVerboseConversationListeners(Cursor cursor, long threadId) {
- cursor.setNotificationUri(context.getContentResolver(), DatabaseContentProviders.Conversation.getVerboseUriForThread(threadId));
- }
-
- @Deprecated
- protected void setNotifyStickerListeners(Cursor cursor) {
- cursor.setNotificationUri(context.getContentResolver(), DatabaseContentProviders.Sticker.CONTENT_URI);
- }
-
- @Deprecated
- protected void setNotifyStickerPackListeners(Cursor cursor) {
- cursor.setNotificationUri(context.getContentResolver(), DatabaseContentProviders.StickerPack.CONTENT_URI);
- }
-
- protected void registerAttachmentListeners(@NonNull ContentObserver observer) {
- context.getContentResolver().registerContentObserver(DatabaseContentProviders.Attachment.CONTENT_URI,
- true,
- observer);
+ protected void notifyStickerListeners() {
+ ApplicationDependencies.getDatabaseObserver().notifyStickerObservers();
}
protected void notifyAttachmentListeners() {
- context.getContentResolver().notifyChange(DatabaseContentProviders.Attachment.CONTENT_URI, null);
+ ApplicationDependencies.getDatabaseObserver().notifyAttachmentObservers();
}
public void reset(SQLCipherOpenHelper databaseHelper) {
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/DatabaseContentProviders.java b/app/src/main/java/org/thoughtcrime/securesms/database/DatabaseContentProviders.java
deleted file mode 100644
index e0d14d585c..0000000000
--- a/app/src/main/java/org/thoughtcrime/securesms/database/DatabaseContentProviders.java
+++ /dev/null
@@ -1,92 +0,0 @@
-package org.thoughtcrime.securesms.database;
-
-import android.content.ContentProvider;
-import android.content.ContentValues;
-import android.database.Cursor;
-import android.net.Uri;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import org.thoughtcrime.securesms.BuildConfig;
-
-/**
- * Starting in API 26, a {@link ContentProvider} needs to be defined for each authority you wish to
- * observe changes on. These classes essentially do nothing except exist so Android doesn't complain.
- */
-public class DatabaseContentProviders {
-
- public static class Conversation extends NoopContentProvider {
- private static final String CONTENT_AUTHORITY = BuildConfig.APPLICATION_ID + ".database.conversation";
- private static final String CONTENT_URI_STRING = "content://" + CONTENT_AUTHORITY + "/";
-
- public static Uri getUriForThread(long threadId) {
- return Uri.parse(CONTENT_URI_STRING + threadId);
- }
-
- public static Uri getVerboseUriForThread(long threadId) {
- return Uri.parse(CONTENT_URI_STRING + "verbose/" + threadId);
- }
-
- public static Uri getUriForAllThreads() {
- return Uri.parse(CONTENT_URI_STRING);
- }
- }
-
- public static class Attachment extends NoopContentProvider {
- private static final String CONTENT_AUTHORITY = BuildConfig.APPLICATION_ID + ".database.attachment";
- private static final String CONTENT_URI_STRING = "content://" + CONTENT_AUTHORITY;
-
- public static final Uri CONTENT_URI = Uri.parse(CONTENT_URI_STRING);
- }
-
- public static class Sticker extends NoopContentProvider {
- private static final String CONTENT_AUTHORITY = BuildConfig.APPLICATION_ID + ".database.sticker";
- private static final String CONTENT_URI_STRING = "content://" + CONTENT_AUTHORITY;
-
- public static final Uri CONTENT_URI = Uri.parse(CONTENT_URI_STRING);
- }
-
- public static class StickerPack extends NoopContentProvider {
- private static final String CONTENT_AUTHORITY = BuildConfig.APPLICATION_ID + ".database.stickerpack";
- private static final String CONTENT_URI_STRING = "content://" + CONTENT_AUTHORITY;
-
- public static final Uri CONTENT_URI = Uri.parse(CONTENT_URI_STRING);
- }
-
- private static abstract class NoopContentProvider extends ContentProvider {
-
- @Override
- public boolean onCreate() {
- return false;
- }
-
- @Nullable
- @Override
- public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
- return null;
- }
-
- @Nullable
- @Override
- public String getType(@NonNull Uri uri) {
- return null;
- }
-
- @Nullable
- @Override
- public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
- return null;
- }
-
- @Override
- public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
- return 0;
- }
-
- @Override
- public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
- return 0;
- }
- }
-}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/DatabaseObserver.java b/app/src/main/java/org/thoughtcrime/securesms/database/DatabaseObserver.java
index 4de69505a3..26d2335492 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/DatabaseObserver.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/DatabaseObserver.java
@@ -31,7 +31,9 @@ public final class DatabaseObserver {
private final Map> paymentObservers;
private final Set allPaymentsObservers;
private final Set chatColorsObservers;
+ private final Set stickerObservers;
private final Set stickerPackObservers;
+ private final Set attachmentObservers;
private final Set messageUpdateObservers;
private final Map> messageInsertObservers;
@@ -44,7 +46,9 @@ public final class DatabaseObserver {
this.paymentObservers = new HashMap<>();
this.allPaymentsObservers = new HashSet<>();
this.chatColorsObservers = new HashSet<>();
+ this.stickerObservers = new HashSet<>();
this.stickerPackObservers = new HashSet<>();
+ this.attachmentObservers = new HashSet<>();
this.messageUpdateObservers = new HashSet<>();
this.messageInsertObservers = new HashMap<>();
}
@@ -85,12 +89,24 @@ public final class DatabaseObserver {
});
}
+ public void registerStickerObserver(@NonNull Observer listener) {
+ executor.execute(() -> {
+ stickerObservers.add(listener);
+ });
+ }
+
public void registerStickerPackObserver(@NonNull Observer listener) {
executor.execute(() -> {
stickerPackObservers.add(listener);
});
}
+ public void registerAttachmentObserver(@NonNull Observer listener) {
+ executor.execute(() -> {
+ attachmentObservers.add(listener);
+ });
+ }
+
public void registerMessageUpdateObserver(@NonNull MessageObserver listener) {
executor.execute(() -> {
messageUpdateObservers.add(listener);
@@ -110,7 +126,9 @@ public final class DatabaseObserver {
unregisterMapped(verboseConversationObservers, listener);
unregisterMapped(paymentObservers, listener);
chatColorsObservers.remove(listener);
+ stickerObservers.remove(listener);
stickerPackObservers.remove(listener);
+ attachmentObservers.remove(listener);
});
}
@@ -127,11 +145,6 @@ public final class DatabaseObserver {
notifyMapped(conversationObservers, threadId);
notifyMapped(verboseConversationObservers, threadId);
}
-
- for (long threadId : threadIds) {
- application.getContentResolver().notifyChange(DatabaseContentProviders.Conversation.getUriForThread(threadId), null);
- application.getContentResolver().notifyChange(DatabaseContentProviders.Conversation.getVerboseUriForThread(threadId), null);
- }
});
}
@@ -139,9 +152,6 @@ public final class DatabaseObserver {
executor.execute(() -> {
notifyMapped(conversationObservers, threadId);
notifyMapped(verboseConversationObservers, threadId);
-
- application.getContentResolver().notifyChange(DatabaseContentProviders.Conversation.getUriForThread(threadId), null);
- application.getContentResolver().notifyChange(DatabaseContentProviders.Conversation.getVerboseUriForThread(threadId), null);
});
}
@@ -150,18 +160,12 @@ public final class DatabaseObserver {
for (long threadId : threadIds) {
notifyMapped(verboseConversationObservers, threadId);
}
-
- for (long threadId : threadIds) {
- application.getContentResolver().notifyChange(DatabaseContentProviders.Conversation.getVerboseUriForThread(threadId), null);
- }
});
}
public void notifyVerboseConversationListeners(long threadId) {
executor.execute(() -> {
notifyMapped(verboseConversationObservers, threadId);
-
- application.getContentResolver().notifyChange(DatabaseContentProviders.Conversation.getVerboseUriForThread(threadId), null);
});
}
@@ -193,11 +197,21 @@ public final class DatabaseObserver {
});
}
+ public void notifyStickerObservers() {
+ executor.execute(() -> {
+ notifySet(stickerObservers);
+ });
+ }
+
public void notifyStickerPackObservers() {
executor.execute(() -> {
notifySet(stickerPackObservers);
+ });
+ }
- application.getContentResolver().notifyChange(DatabaseContentProviders.StickerPack.CONTENT_URI, null);
+ public void notifyAttachmentObservers() {
+ executor.execute(() -> {
+ notifySet(attachmentObservers);
});
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MediaDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/MediaDatabase.java
index 2c67c11f47..41ac2392f0 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/MediaDatabase.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/MediaDatabase.java
@@ -9,6 +9,7 @@ import androidx.annotation.Nullable;
import org.thoughtcrime.securesms.attachments.DatabaseAttachment;
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
+import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.MediaUtil;
@@ -96,54 +97,38 @@ public class MediaDatabase extends Database {
SQLiteDatabase database = databaseHelper.getSignalReadableDatabase();
String query = sorting.applyToQuery(applyEqualityOperator(threadId, GALLERY_MEDIA_QUERY));
String[] args = {threadId + ""};
- Cursor cursor = database.rawQuery(query, args);
- if (listenToAllThreads) {
- setNotifyConversationListeners(cursor);
- } else {
- setNotifyConversationListeners(cursor, threadId);
- }
- return cursor;
+
+ return database.rawQuery(query, args);
}
public @NonNull Cursor getDocumentMediaForThread(long threadId, @NonNull Sorting sorting) {
SQLiteDatabase database = databaseHelper.getSignalReadableDatabase();
String query = sorting.applyToQuery(applyEqualityOperator(threadId, DOCUMENT_MEDIA_QUERY));
String[] args = {threadId + ""};
- Cursor cursor = database.rawQuery(query, args);
- setNotifyConversationListeners(cursor, threadId);
- return cursor;
+
+ return database.rawQuery(query, args);
}
public @NonNull Cursor getAudioMediaForThread(long threadId, @NonNull Sorting sorting) {
SQLiteDatabase database = databaseHelper.getSignalReadableDatabase();
String query = sorting.applyToQuery(applyEqualityOperator(threadId, AUDIO_MEDIA_QUERY));
String[] args = {threadId + ""};
- Cursor cursor = database.rawQuery(query, args);
- setNotifyConversationListeners(cursor, threadId);
- return cursor;
+
+ return database.rawQuery(query, args);
}
public @NonNull Cursor getAllMediaForThread(long threadId, @NonNull Sorting sorting) {
SQLiteDatabase database = databaseHelper.getSignalReadableDatabase();
String query = sorting.applyToQuery(applyEqualityOperator(threadId, ALL_MEDIA_QUERY));
String[] args = {threadId + ""};
- Cursor cursor = database.rawQuery(query, args);
- setNotifyConversationListeners(cursor, threadId);
- return cursor;
+
+ return database.rawQuery(query, args);
}
private static String applyEqualityOperator(long threadId, String query) {
return query.replace("__EQUALITY__", threadId == ALL_THREADS ? "!=" : "=");
}
- public void subscribeToMediaChanges(@NonNull ContentObserver observer) {
- registerAttachmentListeners(observer);
- }
-
- public void unsubscribeToMediaChanges(@NonNull ContentObserver observer) {
- context.getContentResolver().unregisterContentObserver(observer);
- }
-
public StorageBreakdown getStorageBreakdown() {
StorageBreakdown storageBreakdown = new StorageBreakdown();
SQLiteDatabase database = databaseHelper.getSignalReadableDatabase();
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MessageDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/MessageDatabase.java
index 1bdef942e0..1ac30b66e8 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/MessageDatabase.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/MessageDatabase.java
@@ -90,7 +90,6 @@ public abstract class MessageDatabase extends Database implements MmsSmsColumns
public abstract OutgoingMediaMessage getOutgoingMessage(long messageId) throws MmsException, NoSuchMessageException;
public abstract MessageRecord getMessageRecord(long messageId) throws NoSuchMessageException;
public abstract @Nullable MessageRecord getMessageRecordOrNull(long messageId);
- public abstract Cursor getVerboseMessageCursor(long messageId);
public abstract boolean hasReceivedAnyCallsSince(long threadId, long timestamp);
public abstract @Nullable ViewOnceExpirationInfo getNearestExpiringViewOnceMessage();
public abstract boolean isSent(long messageId);
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.java
index aabc7b1938..a061a392f6 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/MmsDatabase.java
@@ -275,16 +275,7 @@ public class MmsDatabase extends MessageDatabase {
@Override
public Cursor getMessageCursor(long messageId) {
- Cursor cursor = internalGetMessage(messageId);
- setNotifyConversationListeners(cursor, getThreadIdForMessage(messageId));
- return cursor;
- }
-
- @Override
- public Cursor getVerboseMessageCursor(long messageId) {
- Cursor cursor = internalGetMessage(messageId);
- setNotifyVerboseConversationListeners(cursor, getThreadIdForMessage(messageId));
- return cursor;
+ return internalGetMessage(messageId);
}
@Override
@@ -843,6 +834,8 @@ public class MmsDatabase extends MessageDatabase {
long threadId;
+ boolean deletedAttachments = false;
+
db.beginTransaction();
try {
ContentValues values = new ContentValues();
@@ -856,7 +849,7 @@ public class MmsDatabase extends MessageDatabase {
values.putNull(SHARED_CONTACTS);
db.update(TABLE_NAME, values, ID_WHERE, new String[] { String.valueOf(messageId) });
- DatabaseFactory.getAttachmentDatabase(context).deleteAttachmentsForMessage(messageId);
+ deletedAttachments = DatabaseFactory.getAttachmentDatabase(context).deleteAttachmentsForMessage(messageId);
DatabaseFactory.getMentionDatabase(context).deleteMentionsForMessage(messageId);
DatabaseFactory.getMessageLogDatabase(context).deleteAllRelatedToMessage(messageId, true);
@@ -866,8 +859,13 @@ public class MmsDatabase extends MessageDatabase {
} finally {
db.endTransaction();
}
+
ApplicationDependencies.getDatabaseObserver().notifyMessageUpdateObservers(new MessageId(messageId, true));
ApplicationDependencies.getDatabaseObserver().notifyConversationListListeners();
+
+ if (deletedAttachments) {
+ ApplicationDependencies.getDatabaseObserver().notifyAttachmentObservers();
+ }
}
@Override
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsDatabase.java
index 62f7d80ccd..70fd59fa42 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsDatabase.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsDatabase.java
@@ -200,26 +200,13 @@ public class MmsSmsDatabase extends Database {
String limitStr = limit > 0 || offset > 0 ? offset + ", " + limit : null;
String query = buildQuery(PROJECTION, selection, order, limitStr, false);
- Cursor cursor = db.rawQuery(query, null);
- setNotifyConversationListeners(cursor, threadId);
-
- return cursor;
+ return db.rawQuery(query, null);
}
public Cursor getConversation(long threadId) {
return getConversation(threadId, 0, 0);
}
- public Cursor getIdentityConflictMessagesForThread(long threadId) {
- String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " ASC";
- String selection = MmsSmsColumns.THREAD_ID + " = " + threadId + " AND " + MmsSmsColumns.MISMATCHED_IDENTITIES + " IS NOT NULL";
-
- Cursor cursor = queryTables(PROJECTION, selection, order, null);
- setNotifyConversationListeners(cursor, threadId);
-
- return cursor;
- }
-
public @NonNull MessageRecord getConversationSnippet(long threadId) throws NoSuchMessageException {
try (Cursor cursor = getConversationSnippetCursor(threadId)) {
if (cursor.moveToFirst()) {
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java
index 76bf4842fd..324d915a16 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/SmsDatabase.java
@@ -1320,13 +1320,6 @@ public class SmsDatabase extends MessageDatabase {
else return record;
}
- @Override
- public Cursor getVerboseMessageCursor(long messageId) {
- Cursor cursor = getMessageCursor(messageId);
- setNotifyVerboseConversationListeners(cursor, getThreadIdForMessage(messageId));
- return cursor;
- }
-
@Override
public Cursor getMessageCursor(long messageId) {
SQLiteDatabase db = databaseHelper.getSignalReadableDatabase();
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/StickerDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/StickerDatabase.java
index cedb115140..2ff7bf382c 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/StickerDatabase.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/StickerDatabase.java
@@ -145,20 +145,15 @@ public class StickerDatabase extends Database {
public @Nullable Cursor getInstalledStickerPacks() {
String selection = COVER + " = ? AND " + INSTALLED + " = ?";
String[] args = new String[] { "1", "1" };
- Cursor cursor = databaseHelper.getSignalReadableDatabase().query(TABLE_NAME, null, selection, args, null, null, PACK_ORDER + " ASC");
- setNotifyStickerPackListeners(cursor);
- return cursor;
+ return databaseHelper.getSignalReadableDatabase().query(TABLE_NAME, null, selection, args, null, null, PACK_ORDER + " ASC");
}
public @Nullable Cursor getStickersByEmoji(@NonNull String emoji) {
String selection = EMOJI + " LIKE ? AND " + COVER + " = ?";
String[] args = new String[] { "%"+emoji+"%", "0" };
- Cursor cursor = databaseHelper.getSignalReadableDatabase().query(TABLE_NAME, null, selection, args, null, null, null);
- setNotifyStickerListeners(cursor);
-
- return cursor;
+ return databaseHelper.getSignalReadableDatabase().query(TABLE_NAME, null, selection, args, null, null, null);
}
public @Nullable Cursor getAllStickerPacks() {
@@ -168,10 +163,8 @@ public class StickerDatabase extends Database {
public @Nullable Cursor getAllStickerPacks(@Nullable String limit) {
String query = COVER + " = ?";
String[] args = new String[] { "1" };
- Cursor cursor = databaseHelper.getSignalReadableDatabase().query(TABLE_NAME, null, query, args, null, null, PACK_ORDER + " ASC", limit);
- setNotifyStickerPackListeners(cursor);
- return cursor;
+ return databaseHelper.getSignalReadableDatabase().query(TABLE_NAME, null, query, args, null, null, PACK_ORDER + " ASC", limit);
}
public @Nullable Cursor getStickersForPack(@NonNull String packId) {
@@ -179,10 +172,7 @@ public class StickerDatabase extends Database {
String selection = PACK_ID + " = ? AND " + COVER + " = ?";
String[] args = new String[] { packId, "0" };
- Cursor cursor = db.query(TABLE_NAME, null, selection, args, null, null, null);
- setNotifyStickerListeners(cursor);
-
- return cursor;
+ return db.query(TABLE_NAME, null, selection, args, null, null, null);
}
public @Nullable Cursor getRecentlyUsedStickers(int limit) {
@@ -190,10 +180,7 @@ public class StickerDatabase extends Database {
String selection = LAST_USED + " > ? AND " + COVER + " = ?";
String[] args = new String[] { "0", "0" };
- Cursor cursor = db.query(TABLE_NAME, null, selection, args, null, null, LAST_USED + " DESC", String.valueOf(limit));
- setNotifyStickerListeners(cursor);
-
- return cursor;
+ return db.query(TABLE_NAME, null, selection, args, null, null, LAST_USED + " DESC", String.valueOf(limit));
}
public @NonNull Set getAllStickerFiles() {
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java b/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java
index 54f14cd6ab..37b592881e 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/ThreadDatabase.java
@@ -291,7 +291,6 @@ public class ThreadDatabase extends Database {
}
notifyAttachmentListeners();
- notifyStickerListeners();
notifyStickerPackListeners();
}
@@ -326,7 +325,6 @@ public class ThreadDatabase extends Database {
}
notifyAttachmentListeners();
- notifyStickerListeners();
notifyStickerPackListeners();
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/loaders/GroupedThreadMediaLoader.java b/app/src/main/java/org/thoughtcrime/securesms/database/loaders/GroupedThreadMediaLoader.java
index 6800d8e9a7..e8ef3a9d21 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/loaders/GroupedThreadMediaLoader.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/loaders/GroupedThreadMediaLoader.java
@@ -8,10 +8,13 @@ import android.util.SparseArray;
import androidx.annotation.NonNull;
import androidx.loader.content.AsyncTaskLoader;
+import org.signal.core.util.ThreadUtil;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.database.DatabaseFactory;
+import org.thoughtcrime.securesms.database.DatabaseObserver;
import org.thoughtcrime.securesms.database.MediaDatabase;
+import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.util.CalendarDateOnly;
import java.text.SimpleDateFormat;
@@ -25,10 +28,10 @@ public final class GroupedThreadMediaLoader extends AsyncTaskLoader ThreadUtil.runOnMain(this::onContentChanged);
onContentChanged();
}
@@ -58,7 +61,7 @@ public final class GroupedThreadMediaLoader extends AsyncTaskLoader.
- */
-package org.thoughtcrime.securesms.database.loaders;
-
-import android.content.Context;
-import android.database.Cursor;
-
-import org.thoughtcrime.securesms.database.DatabaseFactory;
-import org.thoughtcrime.securesms.database.MmsSmsDatabase;
-import org.thoughtcrime.securesms.util.AbstractCursorLoader;
-
-public class MessageDetailsLoader extends AbstractCursorLoader {
- private final String type;
- private final long messageId;
-
- public MessageDetailsLoader(Context context, String type, long messageId) {
- super(context);
- this.type = type;
- this.messageId = messageId;
- }
-
- @Override
- public Cursor getCursor() {
- switch (type) {
- case MmsSmsDatabase.SMS_TRANSPORT:
- return DatabaseFactory.getSmsDatabase(context).getVerboseMessageCursor(messageId);
- case MmsSmsDatabase.MMS_TRANSPORT:
- return DatabaseFactory.getMmsDatabase(context).getVerboseMessageCursor(messageId);
- default:
- throw new AssertionError("no valid message type specified");
- }
- }
-}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/loaders/PagingMediaLoader.java b/app/src/main/java/org/thoughtcrime/securesms/database/loaders/PagingMediaLoader.java
index c50fa6d497..fba59c637a 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/database/loaders/PagingMediaLoader.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/database/loaders/PagingMediaLoader.java
@@ -8,12 +8,15 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.util.Pair;
+import org.signal.core.util.ThreadUtil;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.attachments.AttachmentId;
import org.thoughtcrime.securesms.database.AttachmentDatabase;
import org.thoughtcrime.securesms.database.DatabaseFactory;
+import org.thoughtcrime.securesms.database.DatabaseObserver;
import org.thoughtcrime.securesms.database.MediaDatabase;
import org.thoughtcrime.securesms.database.MediaDatabase.Sorting;
+import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.mms.PartAuthority;
import org.thoughtcrime.securesms.util.AsyncLoader;
@@ -22,10 +25,11 @@ public final class PagingMediaLoader extends AsyncLoader>
@SuppressWarnings("unused")
private static final String TAG = Log.tag(PagingMediaLoader.class);
- private final Uri uri;
- private final boolean leftIsRecent;
- private final Sorting sorting;
- private final long threadId;
+ private final Uri uri;
+ private final boolean leftIsRecent;
+ private final Sorting sorting;
+ private final long threadId;
+ private final DatabaseObserver.Observer observer;
public PagingMediaLoader(@NonNull Context context, long threadId, @NonNull Uri uri, boolean leftIsRecent, @NonNull Sorting sorting) {
super(context);
@@ -33,10 +37,15 @@ public final class PagingMediaLoader extends AsyncLoader>
this.uri = uri;
this.leftIsRecent = leftIsRecent;
this.sorting = sorting;
+ this.observer = () -> {
+ ThreadUtil.runOnMain(this::onContentChanged);
+ };
}
@Override
public @Nullable Pair loadInBackground() {
+ ApplicationDependencies.getDatabaseObserver().registerConversationObserver(threadId, observer);
+
Cursor cursor = DatabaseFactory.getMediaDatabase(getContext()).getGalleryMediaForThread(threadId, sorting, threadId == MediaDatabase.ALL_THREADS);
while (cursor.moveToNext()) {
@@ -50,4 +59,9 @@ public final class PagingMediaLoader extends AsyncLoader>
return null;
}
+
+ @Override
+ protected void onAbandon() {
+ ApplicationDependencies.getDatabaseObserver().unregisterObserver(observer);
+ }
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/keyboard/sticker/StickerKeyboardPageFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/keyboard/sticker/StickerKeyboardPageFragment.kt
index 2332b218d8..a974638ad7 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/keyboard/sticker/StickerKeyboardPageFragment.kt
+++ b/app/src/main/java/org/thoughtcrime/securesms/keyboard/sticker/StickerKeyboardPageFragment.kt
@@ -94,6 +94,7 @@ class StickerKeyboardPageFragment :
view.findViewById(R.id.sticker_search).setOnClickListener { StickerSearchDialogFragment.show(requireActivity().supportFragmentManager) }
view.findViewById(R.id.sticker_manage).setOnClickListener { findListener()?.onStickerManagementClicked() }
+ ApplicationDependencies.getDatabaseObserver().registerStickerObserver(this)
ApplicationDependencies.getDatabaseObserver().registerStickerPackObserver(this)
view.addOnLayoutChangeListener(this)
diff --git a/app/src/main/java/org/thoughtcrime/securesms/longmessage/LongMessageViewModel.java b/app/src/main/java/org/thoughtcrime/securesms/longmessage/LongMessageViewModel.java
index 61dba86bde..f9636527b4 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/longmessage/LongMessageViewModel.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/longmessage/LongMessageViewModel.java
@@ -1,10 +1,6 @@
package org.thoughtcrime.securesms.longmessage;
import android.app.Application;
-import android.database.ContentObserver;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.Looper;
import androidx.annotation.NonNull;
import androidx.lifecycle.LiveData;
@@ -12,31 +8,22 @@ import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
-import org.thoughtcrime.securesms.database.DatabaseContentProviders;
+import org.thoughtcrime.securesms.database.DatabaseObserver;
+import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.whispersystems.libsignal.util.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 final DatabaseObserver.Observer threadObserver;
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(Looper.getMainLooper()));
+ this.message = new MutableLiveData<>();
+ this.threadObserver = () -> repository.getMessage(application, messageId, isMms, message::postValue);
repository.getMessage(application, messageId, isMms, longMessage -> {
if (longMessage.isPresent()) {
- Uri uri = DatabaseContentProviders.Conversation.getUriForThread(longMessage.get().getMessageRecord().getThreadId());
- application.getContentResolver().registerContentObserver(uri, true, messageObserver);
+ ApplicationDependencies.getDatabaseObserver().registerConversationObserver(longMessage.get().getMessageRecord().getThreadId(), threadObserver);
}
message.postValue(longMessage);
@@ -49,18 +36,7 @@ class LongMessageViewModel extends ViewModel {
@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);
- }
+ ApplicationDependencies.getDatabaseObserver().unregisterObserver(threadObserver);
}
static class Factory extends ViewModelProvider.NewInstanceFactory {
@@ -79,6 +55,7 @@ class LongMessageViewModel extends ViewModel {
@Override
public @NonNull T create(@NonNull Class modelClass) {
+ //noinspection ConstantConditions
return modelClass.cast(new LongMessageViewModel(context, repository, messageId, isMms));
}
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/messagedetails/MessageRecordLiveData.java b/app/src/main/java/org/thoughtcrime/securesms/messagedetails/MessageRecordLiveData.java
index 791231dd5d..7fa2106549 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/messagedetails/MessageRecordLiveData.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/messagedetails/MessageRecordLiveData.java
@@ -1,7 +1,6 @@
package org.thoughtcrime.securesms.messagedetails;
import android.content.Context;
-import android.database.ContentObserver;
import android.database.Cursor;
import androidx.annotation.Nullable;
@@ -10,18 +9,20 @@ import androidx.lifecycle.LiveData;
import org.signal.core.util.concurrent.SignalExecutors;
import org.thoughtcrime.securesms.database.DatabaseFactory;
+import org.thoughtcrime.securesms.database.DatabaseObserver;
import org.thoughtcrime.securesms.database.MessageDatabase;
import org.thoughtcrime.securesms.database.MmsDatabase;
import org.thoughtcrime.securesms.database.MmsSmsDatabase;
import org.thoughtcrime.securesms.database.SmsDatabase;
import org.thoughtcrime.securesms.database.model.MessageRecord;
+import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
final class MessageRecordLiveData extends LiveData {
- private final Context context;
- private final String type;
- private final Long messageId;
- private final ContentObserver obs;
+ private final Context context;
+ private final String type;
+ private final Long messageId;
+ private final DatabaseObserver.Observer observer;
private @Nullable Cursor cursor;
@@ -29,13 +30,7 @@ final class MessageRecordLiveData extends LiveData {
this.context = context;
this.type = type;
this.messageId = messageId;
-
- obs = new ContentObserver(null) {
- @Override
- public void onChange(boolean selfChange) {
- SignalExecutors.BOUNDED.execute(() -> resetCursor());
- }
- };
+ this.observer = () -> SignalExecutors.BOUNDED.execute(this::resetCursor);
}
@Override
@@ -54,8 +49,9 @@ final class MessageRecordLiveData extends LiveData {
@WorkerThread
private synchronized void destroyCursor() {
+ ApplicationDependencies.getDatabaseObserver().unregisterObserver(observer);
+
if (cursor != null) {
- cursor.unregisterContentObserver(obs);
cursor.close();
cursor = null;
}
@@ -87,22 +83,22 @@ final class MessageRecordLiveData extends LiveData {
@WorkerThread
private synchronized void handleSms() {
final MessageDatabase db = DatabaseFactory.getSmsDatabase(context);
- final Cursor cursor = db.getVerboseMessageCursor(messageId);
+ final Cursor cursor = db.getMessageCursor(messageId);
final MessageRecord record = SmsDatabase.readerFor(cursor).getNext();
postValue(record);
- cursor.registerContentObserver(obs);
+ ApplicationDependencies.getDatabaseObserver().registerVerboseConversationObserver(record.getThreadId(), observer);
this.cursor = cursor;
}
@WorkerThread
private synchronized void handleMms() {
final MessageDatabase db = DatabaseFactory.getMmsDatabase(context);
- final Cursor cursor = db.getVerboseMessageCursor(messageId);
+ final Cursor cursor = db.getMessageCursor(messageId);
final MessageRecord record = MmsDatabase.readerFor(cursor).getNext();
postValue(record);
- cursor.registerContentObserver(obs);
+ ApplicationDependencies.getDatabaseObserver().registerVerboseConversationObserver(record.getThreadId(), observer);
this.cursor = cursor;
}
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/revealable/ViewOnceMessageActivity.java b/app/src/main/java/org/thoughtcrime/securesms/revealable/ViewOnceMessageActivity.java
index d89c700177..441253cacf 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/revealable/ViewOnceMessageActivity.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/revealable/ViewOnceMessageActivity.java
@@ -99,7 +99,7 @@ public class ViewOnceMessageActivity extends PassphraseRequiredActivity implemen
private void initViewModel(long messageId, @NonNull Uri uri) {
ViewOnceMessageRepository repository = new ViewOnceMessageRepository(this);
- viewModel = ViewModelProviders.of(this, new ViewOnceMessageViewModel.Factory(getApplication(), messageId, repository))
+ viewModel = ViewModelProviders.of(this, new ViewOnceMessageViewModel.Factory(messageId, repository))
.get(ViewOnceMessageViewModel.class);
viewModel.getMessage().observe(this, (message) -> {
diff --git a/app/src/main/java/org/thoughtcrime/securesms/revealable/ViewOnceMessageRepository.java b/app/src/main/java/org/thoughtcrime/securesms/revealable/ViewOnceMessageRepository.java
index 755fc44aef..5c1ad1b140 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/revealable/ViewOnceMessageRepository.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/revealable/ViewOnceMessageRepository.java
@@ -9,6 +9,7 @@ import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.MessageDatabase;
import org.thoughtcrime.securesms.database.MmsDatabase;
+import org.thoughtcrime.securesms.database.NoSuchMessageException;
import org.thoughtcrime.securesms.database.model.MessageId;
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
@@ -31,8 +32,8 @@ class ViewOnceMessageRepository {
void getMessage(long messageId, @NonNull Callback> callback) {
SignalExecutors.BOUNDED.execute(() -> {
- try (MmsDatabase.Reader reader = MmsDatabase.readerFor(mmsDatabase.getMessageCursor(messageId))) {
- MmsMessageRecord record = (MmsMessageRecord) reader.getNext();
+ try {
+ MmsMessageRecord record = (MmsMessageRecord) mmsDatabase.getMessageRecord(messageId);
MessageDatabase.MarkedMessageInfo info = mmsDatabase.setIncomingMessageViewed(record.getId());
if (info != null) {
@@ -44,6 +45,8 @@ class ViewOnceMessageRepository {
}
callback.onComplete(Optional.fromNullable(record));
+ } catch (NoSuchMessageException e) {
+ callback.onComplete(Optional.absent());
}
});
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/revealable/ViewOnceMessageViewModel.java b/app/src/main/java/org/thoughtcrime/securesms/revealable/ViewOnceMessageViewModel.java
index 8247fe9498..78f9b0ce12 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/revealable/ViewOnceMessageViewModel.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/revealable/ViewOnceMessageViewModel.java
@@ -1,8 +1,6 @@
package org.thoughtcrime.securesms.revealable;
import android.app.Application;
-import android.database.ContentObserver;
-import android.net.Uri;
import androidx.annotation.NonNull;
import androidx.lifecycle.LiveData;
@@ -12,37 +10,25 @@ import androidx.lifecycle.ViewModelProvider;
import org.signal.core.util.ThreadUtil;
import org.signal.core.util.logging.Log;
-import org.thoughtcrime.securesms.database.DatabaseContentProviders;
+import org.thoughtcrime.securesms.database.DatabaseObserver;
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
+import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.whispersystems.libsignal.util.guava.Optional;
class ViewOnceMessageViewModel extends ViewModel {
private static final String TAG = Log.tag(ViewOnceMessageViewModel.class);
- private final Application application;
- private final ViewOnceMessageRepository repository;
private final MutableLiveData> message;
- private final ContentObserver observer;
+ private final DatabaseObserver.Observer observer;
- private ViewOnceMessageViewModel(@NonNull Application application,
- long messageId,
- @NonNull ViewOnceMessageRepository repository)
- {
- this.application = application;
- this.repository = repository;
- this.message = new MutableLiveData<>();
- this.observer = new ContentObserver(null) {
- @Override
- public void onChange(boolean selfChange) {
- repository.getMessage(messageId, optionalMessage -> onMessageRetrieved(optionalMessage));
- }
- };
+ private ViewOnceMessageViewModel(long messageId, @NonNull ViewOnceMessageRepository repository) {
+ this.message = new MutableLiveData<>();
+ this.observer = () -> repository.getMessage(messageId, this::onMessageRetrieved);
repository.getMessage(messageId, message -> {
if (message.isPresent()) {
- Uri uri = DatabaseContentProviders.Conversation.getUriForThread(message.get().getThreadId());
- application.getContentResolver().registerContentObserver(uri, true, observer);
+ ApplicationDependencies.getDatabaseObserver().registerConversationObserver(message.get().getThreadId(), observer);
}
onMessageRetrieved(message);
@@ -55,7 +41,7 @@ class ViewOnceMessageViewModel extends ViewModel {
@Override
protected void onCleared() {
- application.getContentResolver().unregisterContentObserver(observer);
+ ApplicationDependencies.getDatabaseObserver().unregisterObserver(observer);
}
private void onMessageRetrieved(@NonNull Optional optionalMessage) {
@@ -73,15 +59,10 @@ class ViewOnceMessageViewModel extends ViewModel {
static class Factory extends ViewModelProvider.NewInstanceFactory {
- private final Application application;
private final long messageId;
private final ViewOnceMessageRepository repository;
- Factory(@NonNull Application application,
- long messageId,
- @NonNull ViewOnceMessageRepository repository)
- {
- this.application = application;
+ Factory(long messageId, @NonNull ViewOnceMessageRepository repository) {
this.messageId = messageId;
this.repository = repository;
}
@@ -89,7 +70,7 @@ class ViewOnceMessageViewModel extends ViewModel {
@Override
public @NonNull T create(@NonNull Class modelClass) {
//noinspection ConstantConditions
- return modelClass.cast(new ViewOnceMessageViewModel(application, messageId, repository));
+ return modelClass.cast(new ViewOnceMessageViewModel(messageId, repository));
}
}
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/search/SearchRepository.java b/app/src/main/java/org/thoughtcrime/securesms/search/SearchRepository.java
index 9676ed2c47..bc4891233d 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/search/SearchRepository.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/search/SearchRepository.java
@@ -14,7 +14,6 @@ import org.signal.core.util.concurrent.SignalExecutors;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.contacts.ContactRepository;
-import org.thoughtcrime.securesms.database.CursorList;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.GroupDatabase;
import org.thoughtcrime.securesms.database.MentionDatabase;
@@ -118,7 +117,7 @@ public class SearchRepository {
public void query(@NonNull String query, long threadId, @NonNull Callback> callback) {
if (TextUtils.isEmpty(query)) {
- callback.onResult(CursorList.emptyList());
+ callback.onResult(Collections.emptyList());
return;
}
@@ -345,11 +344,11 @@ public class SearchRepository {
return body;
}
- private @NonNull List readToList(@Nullable Cursor cursor, @NonNull CursorList.ModelBuilder builder) {
+ private @NonNull List readToList(@Nullable Cursor cursor, @NonNull ModelBuilder builder) {
return readToList(cursor, builder, -1);
}
- private @NonNull List readToList(@Nullable Cursor cursor, @NonNull CursorList.ModelBuilder builder, int limit) {
+ private @NonNull List readToList(@Nullable Cursor cursor, @NonNull ModelBuilder builder, int limit) {
if (cursor == null) {
return Collections.emptyList();
}
@@ -396,7 +395,7 @@ public class SearchRepository {
return combined;
}
- private static class RecipientModelBuilder implements CursorList.ModelBuilder {
+ private static class RecipientModelBuilder implements ModelBuilder {
@Override
public Recipient build(@NonNull Cursor cursor) {
@@ -405,7 +404,7 @@ public class SearchRepository {
}
}
- private static class ThreadModelBuilder implements CursorList.ModelBuilder {
+ private static class ThreadModelBuilder implements ModelBuilder {
private final ThreadDatabase threadDatabase;
@@ -419,7 +418,7 @@ public class SearchRepository {
}
}
- private static class MessageModelBuilder implements CursorList.ModelBuilder {
+ private static class MessageModelBuilder implements ModelBuilder {
@Override
public MessageResult build(@NonNull Cursor cursor) {
@@ -441,4 +440,8 @@ public class SearchRepository {
public interface Callback {
void onResult(@NonNull E result);
}
+
+ public interface ModelBuilder {
+ T build(@NonNull Cursor cursor);
+ }
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/stickers/StickerManagementViewModel.java b/app/src/main/java/org/thoughtcrime/securesms/stickers/StickerManagementViewModel.java
index d33b3aab98..4bc5564c38 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/stickers/StickerManagementViewModel.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/stickers/StickerManagementViewModel.java
@@ -1,7 +1,6 @@
package org.thoughtcrime.securesms.stickers;
import android.app.Application;
-import android.database.ContentObserver;
import androidx.annotation.NonNull;
import androidx.lifecycle.LiveData;
@@ -9,8 +8,9 @@ import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
-import org.thoughtcrime.securesms.database.DatabaseContentProviders;
+import org.thoughtcrime.securesms.database.DatabaseObserver;
import org.thoughtcrime.securesms.database.model.StickerPackRecord;
+import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.stickers.StickerManagementRepository.PackResult;
import java.util.List;
@@ -20,21 +20,18 @@ final class StickerManagementViewModel extends ViewModel {
private final Application application;
private final StickerManagementRepository repository;
private final MutableLiveData packs;
- private final ContentObserver observer;
+ private final DatabaseObserver.Observer observer;
private StickerManagementViewModel(@NonNull Application application, @NonNull StickerManagementRepository repository) {
this.application = application;
this.repository = repository;
this.packs = new MutableLiveData<>();
- this.observer = new ContentObserver(null) {
- @Override
- public void onChange(boolean selfChange) {
- repository.deleteOrphanedStickerPacks();
- repository.getStickerPacks(packs::postValue);
- }
+ this.observer = () -> {
+ repository.deleteOrphanedStickerPacks();
+ repository.getStickerPacks(packs::postValue);
};
- application.getContentResolver().registerContentObserver(DatabaseContentProviders.StickerPack.CONTENT_URI, true, observer);
+ ApplicationDependencies.getDatabaseObserver().registerStickerPackObserver(observer);
}
void init() {
@@ -65,7 +62,7 @@ final class StickerManagementViewModel extends ViewModel {
@Override
protected void onCleared() {
- application.getContentResolver().unregisterContentObserver(observer);
+ ApplicationDependencies.getDatabaseObserver().unregisterObserver(observer);
}
static class Factory extends ViewModelProvider.NewInstanceFactory {
diff --git a/app/src/main/java/org/thoughtcrime/securesms/stickers/StickerPackPreviewViewModel.java b/app/src/main/java/org/thoughtcrime/securesms/stickers/StickerPackPreviewViewModel.java
index c8b8041419..e64d8d5bb3 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/stickers/StickerPackPreviewViewModel.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/stickers/StickerPackPreviewViewModel.java
@@ -1,7 +1,6 @@
package org.thoughtcrime.securesms.stickers;
import android.app.Application;
-import android.database.ContentObserver;
import android.text.TextUtils;
import androidx.annotation.NonNull;
@@ -10,7 +9,8 @@ import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
-import org.thoughtcrime.securesms.database.DatabaseContentProviders;
+import org.thoughtcrime.securesms.database.DatabaseObserver;
+import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.stickers.StickerPackPreviewRepository.StickerManifestResult;
import org.whispersystems.libsignal.util.guava.Optional;
@@ -20,7 +20,7 @@ final class StickerPackPreviewViewModel extends ViewModel {
private final StickerPackPreviewRepository previewRepository;
private final StickerManagementRepository managementRepository;
private final MutableLiveData> stickerManifest;
- private final ContentObserver packObserver;
+ private final DatabaseObserver.Observer packObserver;
private String packId;
private String packKey;
@@ -33,16 +33,13 @@ final class StickerPackPreviewViewModel extends ViewModel {
this.previewRepository = previewRepository;
this.managementRepository = managementRepository;
this.stickerManifest = new MutableLiveData<>();
- this.packObserver = new ContentObserver(null) {
- @Override
- public void onChange(boolean selfChange) {
- if (!TextUtils.isEmpty(packId) && !TextUtils.isEmpty(packKey)) {
- previewRepository.getStickerManifest(packId, packKey, stickerManifest::postValue);
- }
+ this.packObserver = () -> {
+ if (!TextUtils.isEmpty(packId) && !TextUtils.isEmpty(packKey)) {
+ previewRepository.getStickerManifest(packId, packKey, stickerManifest::postValue);
}
};
- application.getContentResolver().registerContentObserver(DatabaseContentProviders.StickerPack.CONTENT_URI, true, packObserver);
+ ApplicationDependencies.getDatabaseObserver().registerStickerPackObserver(packObserver);
}
LiveData> getStickerManifest(@NonNull String packId, @NonNull String packKey) {
@@ -64,7 +61,7 @@ final class StickerPackPreviewViewModel extends ViewModel {
@Override
protected void onCleared() {
- application.getContentResolver().unregisterContentObserver(packObserver);
+ ApplicationDependencies.getDatabaseObserver().unregisterObserver(packObserver);
}
static class Factory extends ViewModelProvider.NewInstanceFactory {
diff --git a/app/src/main/java/org/thoughtcrime/securesms/stickers/StickerSearchRepository.java b/app/src/main/java/org/thoughtcrime/securesms/stickers/StickerSearchRepository.java
index e48b3b3dac..c8b21501fb 100644
--- a/app/src/main/java/org/thoughtcrime/securesms/stickers/StickerSearchRepository.java
+++ b/app/src/main/java/org/thoughtcrime/securesms/stickers/StickerSearchRepository.java
@@ -8,7 +8,6 @@ import androidx.annotation.NonNull;
import org.signal.core.util.concurrent.SignalExecutors;
import org.thoughtcrime.securesms.components.emoji.EmojiUtil;
import org.thoughtcrime.securesms.database.AttachmentDatabase;
-import org.thoughtcrime.securesms.database.CursorList;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.StickerDatabase;
import org.thoughtcrime.securesms.database.StickerDatabase.StickerRecordReader;
@@ -59,13 +58,6 @@ public final class StickerSearchRepository {
});
}
- private static class StickerModelBuilder implements CursorList.ModelBuilder {
- @Override
- public StickerRecord build(@NonNull Cursor cursor) {
- return new StickerRecordReader(cursor).getCurrent();
- }
- }
-
public interface Callback {
void onResult(T result);
}
diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/ObservingLiveData.java b/app/src/main/java/org/thoughtcrime/securesms/util/ObservingLiveData.java
deleted file mode 100644
index 7bc2e2eb41..0000000000
--- a/app/src/main/java/org/thoughtcrime/securesms/util/ObservingLiveData.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package org.thoughtcrime.securesms.util;
-
-import android.database.ContentObserver;
-
-import androidx.annotation.NonNull;
-import androidx.lifecycle.MutableLiveData;
-
-import org.signal.core.util.StreamUtil;
-import org.thoughtcrime.securesms.database.ObservableContent;
-
-import java.io.Closeable;
-
-/**
- * Implementation of {@link androidx.lifecycle.LiveData} that will handle closing the contained
- * {@link Closeable} when the value changes.
- */
-public class ObservingLiveData extends MutableLiveData {
-
- private ContentObserver observer;
-
- @Override
- public void setValue(E value) {
- E previous = getValue();
-
- if (previous != null) {
- previous.unregisterContentObserver(observer);
- StreamUtil.close(previous);
- }
-
- value.registerContentObserver(observer);
-
- super.setValue(value);
- }
-
- public void close() {
- E value = getValue();
-
- if (value != null) {
- value.unregisterContentObserver(observer);
- StreamUtil.close(value);
- }
- }
-
- public void registerContentObserver(@NonNull ContentObserver observer) {
- this.observer = observer;
- }
-}