Convert all database notifiers to use DatabaseObserver.

Lots of red in this diff to celebrate the release of Red (Taylor's Version).
This commit is contained in:
Greyson Parrelli
2021-11-12 12:14:59 -05:00
committed by Cody Henthorne
parent ab55fec6bd
commit 658de3b6e7
30 changed files with 179 additions and 729 deletions

View File

@@ -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<DatabaseAttachment> getPendingAttachments() {
final SQLiteDatabase database = databaseHelper.getSignalReadableDatabase();
final List<DatabaseAttachment> 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) {

View File

@@ -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<T> implements List<T>, ObservableContent {
private final Cursor cursor;
private final ModelBuilder<T> modelBuilder;
public CursorList(@NonNull Cursor cursor, @NonNull ModelBuilder<T> modelBuilder) {
this.cursor = cursor;
this.modelBuilder = modelBuilder;
forceQueryLoad();
}
public static <T> CursorList<T> emptyList() {
//noinspection ConstantConditions,unchecked
return (CursorList<T>) 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<T> iterator() {
return new Iterator<T>() {
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<T> listIterator() {
throw new UnsupportedOperationException();
}
@Override
public @NonNull ListIterator<T> listIterator(int i) {
throw new UnsupportedOperationException();
}
@Override
public @NonNull List<T> 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> {
T build(@NonNull Cursor cursor);
}
}

View File

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

View File

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

View File

@@ -31,7 +31,9 @@ public final class DatabaseObserver {
private final Map<UUID, Set<Observer>> paymentObservers;
private final Set<Observer> allPaymentsObservers;
private final Set<Observer> chatColorsObservers;
private final Set<Observer> stickerObservers;
private final Set<Observer> stickerPackObservers;
private final Set<Observer> attachmentObservers;
private final Set<MessageObserver> messageUpdateObservers;
private final Map<Long, Set<MessageObserver>> 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);
});
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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<String> getAllStickerFiles() {

View File

@@ -291,7 +291,6 @@ public class ThreadDatabase extends Database {
}
notifyAttachmentListeners();
notifyStickerListeners();
notifyStickerPackListeners();
}
@@ -326,7 +325,6 @@ public class ThreadDatabase extends Database {
}
notifyAttachmentListeners();
notifyStickerListeners();
notifyStickerPackListeners();
}

View File

@@ -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<GroupedThrea
@SuppressWarnings("unused")
private static final String TAG = Log.tag(GroupedThreadMediaLoader.class);
private final ContentObserver observer;
private final MediaLoader.MediaType mediaType;
private final MediaDatabase.Sorting sorting;
private final long threadId;
private final DatabaseObserver.Observer observer;
private final MediaLoader.MediaType mediaType;
private final MediaDatabase.Sorting sorting;
private final long threadId;
public GroupedThreadMediaLoader(@NonNull Context context,
long threadId,
@@ -39,7 +42,7 @@ public final class GroupedThreadMediaLoader extends AsyncTaskLoader<GroupedThrea
this.threadId = threadId;
this.mediaType = mediaType;
this.sorting = sorting;
this.observer = new ForceLoadContentObserver();
this.observer = () -> ThreadUtil.runOnMain(this::onContentChanged);
onContentChanged();
}
@@ -58,7 +61,7 @@ public final class GroupedThreadMediaLoader extends AsyncTaskLoader<GroupedThrea
@Override
protected void onAbandon() {
DatabaseFactory.getMediaDatabase(getContext()).unsubscribeToMediaChanges(observer);
ApplicationDependencies.getDatabaseObserver().unregisterObserver(observer);
}
@Override
@@ -70,7 +73,8 @@ public final class GroupedThreadMediaLoader extends AsyncTaskLoader<GroupedThrea
PopulatedGroupedThreadMedia mediaGrouping = new PopulatedGroupedThreadMedia(groupingMethod);
DatabaseFactory.getMediaDatabase(context).subscribeToMediaChanges(observer);
ApplicationDependencies.getDatabaseObserver().registerAttachmentObserver(observer);
try (Cursor cursor = ThreadMediaLoader.createThreadMediaCursor(context, threadId, mediaType, sorting)) {
while (cursor != null && cursor.moveToNext()) {
mediaGrouping.add(MediaDatabase.MediaRecord.from(context, cursor));

View File

@@ -1,47 +0,0 @@
/**
* Copyright (C) 2015 Open Whisper Systems
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
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");
}
}
}

View File

@@ -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<Pair<Cursor, Integer>>
@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<Pair<Cursor, Integer>>
this.uri = uri;
this.leftIsRecent = leftIsRecent;
this.sorting = sorting;
this.observer = () -> {
ThreadUtil.runOnMain(this::onContentChanged);
};
}
@Override
public @Nullable Pair<Cursor, Integer> 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<Pair<Cursor, Integer>>
return null;
}
@Override
protected void onAbandon() {
ApplicationDependencies.getDatabaseObserver().unregisterObserver(observer);
}
}