mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-20 08:39:22 +01:00
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:
committed by
Cody Henthorne
parent
ab55fec6bd
commit
658de3b6e7
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -291,7 +291,6 @@ public class ThreadDatabase extends Database {
|
||||
}
|
||||
|
||||
notifyAttachmentListeners();
|
||||
notifyStickerListeners();
|
||||
notifyStickerPackListeners();
|
||||
}
|
||||
|
||||
@@ -326,7 +325,6 @@ public class ThreadDatabase extends Database {
|
||||
}
|
||||
|
||||
notifyAttachmentListeners();
|
||||
notifyStickerListeners();
|
||||
notifyStickerPackListeners();
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user