mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-22 01:40:07 +01:00
Use a new DatabaseObserver system.
This commit is contained in:
@@ -23,6 +23,7 @@ import android.database.Cursor;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.thoughtcrime.securesms.database.helpers.SQLCipherOpenHelper;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
@@ -39,20 +40,27 @@ public abstract class Database {
|
||||
}
|
||||
|
||||
protected void notifyConversationListeners(Set<Long> threadIds) {
|
||||
for (long threadId : threadIds)
|
||||
ApplicationDependencies.getDatabaseObserver().notifyConversationListeners(threadIds);
|
||||
|
||||
for (long threadId : threadIds) {
|
||||
notifyConversationListeners(threadId);
|
||||
}
|
||||
}
|
||||
|
||||
protected void notifyConversationListeners(long threadId) {
|
||||
ApplicationDependencies.getDatabaseObserver().notifyConversationListeners(threadId);
|
||||
|
||||
context.getContentResolver().notifyChange(DatabaseContentProviders.Conversation.getUriForThread(threadId), null);
|
||||
notifyVerboseConversationListeners(threadId);
|
||||
}
|
||||
|
||||
protected void notifyVerboseConversationListeners(long threadId) {
|
||||
ApplicationDependencies.getDatabaseObserver().notifyVerboseConversationListeners(threadId);
|
||||
context.getContentResolver().notifyChange(DatabaseContentProviders.Conversation.getVerboseUriForThread(threadId), null);
|
||||
}
|
||||
|
||||
protected void notifyConversationListListeners() {
|
||||
ApplicationDependencies.getDatabaseObserver().notifyConversationListListeners();
|
||||
context.getContentResolver().notifyChange(DatabaseContentProviders.ConversationList.CONTENT_URI, null);
|
||||
}
|
||||
|
||||
@@ -64,26 +72,32 @@ public abstract class Database {
|
||||
context.getContentResolver().notifyChange(DatabaseContentProviders.StickerPack.CONTENT_URI, null);
|
||||
}
|
||||
|
||||
@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 setNotifyConversationListListeners(Cursor cursor) {
|
||||
cursor.setNotificationUri(context.getContentResolver(), DatabaseContentProviders.ConversationList.CONTENT_URI);
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
@@ -101,5 +115,4 @@ public abstract class Database {
|
||||
public void reset(SQLCipherOpenHelper databaseHelper) {
|
||||
this.databaseHelper = databaseHelper;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
package org.thoughtcrime.securesms.database;
|
||||
|
||||
import android.app.Application;
|
||||
import android.database.ContentObserver;
|
||||
import android.database.Cursor;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.signal.core.util.concurrent.SignalExecutors;
|
||||
import org.thoughtcrime.securesms.util.concurrent.SerialExecutor;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
/**
|
||||
* Allows listening to database changes to varying degrees of specificity.
|
||||
*
|
||||
* A replacement for the observer system in {@link Database}. We should move to this over time.
|
||||
*/
|
||||
public final class DatabaseObserver {
|
||||
|
||||
private final Application application;
|
||||
private final Executor executor;
|
||||
|
||||
private final Set<Observer> conversationListObservers;
|
||||
private final Map<Long, Set<Observer>> conversationObservers;
|
||||
private final Map<Long, Set<Observer>> verboseConversationObservers;
|
||||
|
||||
public DatabaseObserver(Application application) {
|
||||
this.application = application;
|
||||
this.executor = new SerialExecutor(SignalExecutors.BOUNDED);
|
||||
this.conversationListObservers = new HashSet<>();
|
||||
this.conversationObservers = new HashMap<>();
|
||||
this.verboseConversationObservers = new HashMap<>();
|
||||
}
|
||||
|
||||
public void registerConversationListObserver(@NonNull Observer listener) {
|
||||
executor.execute(() -> {
|
||||
conversationListObservers.add(listener);
|
||||
});
|
||||
}
|
||||
|
||||
public void registerConversationObserver(long threadId, @NonNull Observer listener) {
|
||||
executor.execute(() -> {
|
||||
registerMapped(conversationObservers, threadId, listener);
|
||||
});
|
||||
}
|
||||
|
||||
public void registerVerboseConversationObserver(long threadId, @NonNull Observer listener) {
|
||||
executor.execute(() -> {
|
||||
registerMapped(verboseConversationObservers, threadId, listener);
|
||||
});
|
||||
}
|
||||
|
||||
public void unregisterObserver(@NonNull Observer listener) {
|
||||
executor.execute(() -> {
|
||||
conversationListObservers.remove(listener);
|
||||
unregisterMapped(conversationObservers, listener);
|
||||
unregisterMapped(verboseConversationObservers, listener);
|
||||
});
|
||||
}
|
||||
|
||||
public void notifyConversationListeners(Set<Long> threadIds) {
|
||||
executor.execute(() -> {
|
||||
for (long threadId : threadIds) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
public void notifyConversationListeners(long threadId) {
|
||||
executor.execute(() -> {
|
||||
notifyMapped(conversationObservers, threadId);
|
||||
notifyMapped(verboseConversationObservers, threadId);
|
||||
});
|
||||
|
||||
application.getContentResolver().notifyChange(DatabaseContentProviders.Conversation.getUriForThread(threadId), null);
|
||||
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);
|
||||
}
|
||||
|
||||
public void notifyConversationListListeners() {
|
||||
executor.execute(() -> {
|
||||
for (Observer listener : conversationListObservers) {
|
||||
listener.onChanged();
|
||||
}
|
||||
});
|
||||
|
||||
application.getContentResolver().notifyChange(DatabaseContentProviders.ConversationList.CONTENT_URI, null);
|
||||
}
|
||||
|
||||
private <K> void registerMapped(@NonNull Map<K, Set<Observer>> map, @NonNull K key, @NonNull Observer listener) {
|
||||
Set<Observer> listeners = map.get(key);
|
||||
|
||||
if (listeners == null) {
|
||||
listeners = new HashSet<>();
|
||||
}
|
||||
|
||||
listeners.add(listener);
|
||||
map.put(key, listeners);
|
||||
}
|
||||
|
||||
private <K> void unregisterMapped(@NonNull Map<K, Set<Observer>> map, @NonNull Observer listener) {
|
||||
for (Map.Entry<K, Set<Observer>> entry : map.entrySet()) {
|
||||
entry.getValue().remove(listener);
|
||||
}
|
||||
}
|
||||
|
||||
private static <K> void notifyMapped(@NonNull Map<K, Set<Observer>> map, @NonNull K key) {
|
||||
Set<Observer> listeners = map.get(key);
|
||||
|
||||
if (listeners != null) {
|
||||
for (Observer listener : listeners) {
|
||||
listener.onChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface Observer {
|
||||
/**
|
||||
* Called when the relevant data changes. Executed on a serial executor, so don't do any
|
||||
* long-running tasks!
|
||||
*/
|
||||
void onChanged();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user