@ -26,14 +26,10 @@ import android.content.Context;
import android.database.Cursor ;
import android.database.MergeCursor ;
import android.net.Uri ;
import androidx.annotation.NonNull ;
import androidx.annotation.Nullable ;
import com.annimon.stream.Stream ;
import net.zetetic.database.sqlcipher.SQLiteDatabase ;
import org.jetbrains.annotations.NotNull ;
import org.session.libsession.snode.SnodeAPI ;
import org.session.libsession.utilities.Address ;
@ -61,7 +57,6 @@ import org.thoughtcrime.securesms.mms.Slide;
import org.thoughtcrime.securesms.mms.SlideDeck ;
import org.thoughtcrime.securesms.notifications.MarkReadReceiver ;
import org.thoughtcrime.securesms.util.SessionMetaProtocol ;
import java.io.Closeable ;
import java.util.Collections ;
import java.util.HashMap ;
@ -83,7 +78,7 @@ public class ThreadDatabase extends Database {
public static final String TABLE_NAME = "thread" ;
public static final String ID = "_id" ;
public static final String DATE = "date" ;
public static final String THREAD_CREATION_ DATE = "date" ;
public static final String MESSAGE_COUNT = "message_count" ;
public static final String ADDRESS = "recipient_ids" ;
public static final String SNIPPET = "snippet" ;
@ -91,7 +86,7 @@ public class ThreadDatabase extends Database {
public static final String READ = "read" ;
public static final String UNREAD_COUNT = "unread_count" ;
public static final String UNREAD_MENTION_COUNT = "unread_mention_count" ;
public static final String TYPE = "type" ;
public static final String DISTRIBUTION_ TYPE = "type" ; // See: DistributionTypes.kt
private static final String ERROR = "error" ;
public static final String SNIPPET_TYPE = "snippet_type" ;
public static final String SNIPPET_URI = "snippet_uri" ;
@ -101,27 +96,27 @@ public class ThreadDatabase extends Database {
public static final String READ_RECEIPT_COUNT = "read_receipt_count" ;
public static final String EXPIRES_IN = "expires_in" ;
public static final String LAST_SEEN = "last_seen" ;
public static final String HAS_SENT = "has_sent" ;
public static final String HAS_SENT = "has_sent" ;
public static final String IS_PINNED = "is_pinned" ;
public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" +
ID + " INTEGER PRIMARY KEY, " + DATE + " INTEGER DEFAULT 0, " +
ID + " INTEGER PRIMARY KEY, " + THREAD_CREATION_ DATE + " INTEGER DEFAULT 0, " +
MESSAGE_COUNT + " INTEGER DEFAULT 0, " + ADDRESS + " TEXT, " + SNIPPET + " TEXT, " +
SNIPPET_CHARSET + " INTEGER DEFAULT 0, " + READ + " INTEGER DEFAULT 1, " +
TYPE + " INTEGER DEFAULT 0, " + ERROR + " INTEGER DEFAULT 0, " +
DISTRIBUTION_ TYPE + " INTEGER DEFAULT 0, " + ERROR + " INTEGER DEFAULT 0, " +
SNIPPET_TYPE + " INTEGER DEFAULT 0, " + SNIPPET_URI + " TEXT DEFAULT NULL, " +
ARCHIVED + " INTEGER DEFAULT 0, " + STATUS + " INTEGER DEFAULT 0, " +
DELIVERY_RECEIPT_COUNT + " INTEGER DEFAULT 0, " + EXPIRES_IN + " INTEGER DEFAULT 0, " +
LAST_SEEN + " INTEGER DEFAULT 0, " + HAS_SENT + " INTEGER DEFAULT 0, " +
READ_RECEIPT_COUNT + " INTEGER DEFAULT 0, " + UNREAD_COUNT + " INTEGER DEFAULT 0);" ;
public static final String [ ] CREATE_INDEX S = {
public static final String [ ] CREATE_INDEX E S = {
"CREATE INDEX IF NOT EXISTS thread_recipient_ids_index ON " + TABLE_NAME + " (" + ADDRESS + ");" ,
"CREATE INDEX IF NOT EXISTS archived_count_index ON " + TABLE_NAME + " (" + ARCHIVED + ", " + MESSAGE_COUNT + ");" ,
} ;
private static final String [ ] THREAD_PROJECTION = {
ID , DATE, MESSAGE_COUNT , ADDRESS , SNIPPET , SNIPPET_CHARSET , READ , UNREAD_COUNT , UNREAD_MENTION_COUNT , TYPE, ERROR , SNIPPET_TYPE ,
ID , THREAD_CREATION_ DATE, MESSAGE_COUNT , ADDRESS , SNIPPET , SNIPPET_CHARSET , READ , UNREAD_COUNT , UNREAD_MENTION_COUNT , DISTRIBUTION_ TYPE, ERROR , SNIPPET_TYPE ,
SNIPPET_URI , ARCHIVED , STATUS , DELIVERY_RECEIPT_COUNT , EXPIRES_IN , LAST_SEEN , READ_RECEIPT_COUNT , IS_PINNED
} ;
@ -131,8 +126,8 @@ public class ThreadDatabase extends Database {
private static final List < String > COMBINED_THREAD_RECIPIENT_GROUP_PROJECTION = Stream . concat ( Stream . concat ( Stream . of ( TYPED_THREAD_PROJECTION ) ,
Stream . of ( RecipientDatabase . TYPED_RECIPIENT_PROJECTION ) ) ,
Stream . of ( GroupDatabase . TYPED_GROUP_PROJECTION ) )
. toList ( ) ;
Stream . of ( GroupDatabase . TYPED_GROUP_PROJECTION ) )
. toList ( ) ;
public static String getCreatePinnedCommand ( ) {
return "ALTER TABLE " + TABLE_NAME + " " +
@ -158,11 +153,10 @@ public class ThreadDatabase extends Database {
ContentValues contentValues = new ContentValues ( 4 ) ;
long date = SnodeAPI . getNowWithOffset ( ) ;
contentValues . put ( DATE, date - date % 1000 ) ;
contentValues . put ( THREAD_CREATION_ DATE, date - date % 1000 ) ;
contentValues . put ( ADDRESS , address . serialize ( ) ) ;
if ( group )
contentValues . put ( TYPE , distributionType ) ;
if ( group ) contentValues . put ( DISTRIBUTION_TYPE , distributionType ) ;
contentValues . put ( MESSAGE_COUNT , 0 ) ;
@ -175,7 +169,7 @@ public class ThreadDatabase extends Database {
long expiresIn , int readReceiptCount )
{
ContentValues contentValues = new ContentValues ( 7 ) ;
contentValues . put ( DATE, date - date % 1000 ) ;
contentValues . put ( THREAD_CREATION_ DATE, date - date % 1000 ) ;
contentValues . put ( MESSAGE_COUNT , count ) ;
if ( ! body . isEmpty ( ) ) {
contentValues . put ( SNIPPET , body ) ;
@ -187,9 +181,7 @@ public class ThreadDatabase extends Database {
contentValues . put ( READ_RECEIPT_COUNT , readReceiptCount ) ;
contentValues . put ( EXPIRES_IN , expiresIn ) ;
if ( unarchive ) {
contentValues . put ( ARCHIVED , 0 ) ;
}
if ( unarchive ) { contentValues . put ( ARCHIVED , 0 ) ; }
SQLiteDatabase db = databaseHelper . getWritableDatabase ( ) ;
db . update ( TABLE_NAME , contentValues , ID + " = ?" , new String [ ] { threadId + "" } ) ;
@ -199,7 +191,7 @@ public class ThreadDatabase extends Database {
public void updateSnippet ( long threadId , String snippet , @Nullable Uri attachment , long date , long type , boolean unarchive ) {
ContentValues contentValues = new ContentValues ( 4 ) ;
contentValues . put ( DATE, date - date % 1000 ) ;
contentValues . put ( THREAD_CREATION_ DATE, date - date % 1000 ) ;
if ( ! snippet . isEmpty ( ) ) {
contentValues . put ( SNIPPET , snippet ) ;
}
@ -230,9 +222,7 @@ public class ThreadDatabase extends Database {
SQLiteDatabase db = databaseHelper . getWritableDatabase ( ) ;
String where = "" ;
for ( long threadId : threadIds ) {
where + = ID + " = '" + threadId + "' OR " ;
}
for ( long threadId : threadIds ) { where + = ID + " = '" + threadId + "' OR " ; }
where = where . substring ( 0 , where . length ( ) - 4 ) ;
@ -358,7 +348,7 @@ public class ThreadDatabase extends Database {
public void setDistributionType ( long threadId , int distributionType ) {
ContentValues contentValues = new ContentValues ( 1 ) ;
contentValues . put ( TYPE, distributionType ) ;
contentValues . put ( DISTRIBUTION_ TYPE, distributionType ) ;
SQLiteDatabase db = databaseHelper . getWritableDatabase ( ) ;
db . update ( TABLE_NAME , contentValues , ID_WHERE , new String [ ] { threadId + "" } ) ;
@ -367,7 +357,7 @@ public class ThreadDatabase extends Database {
public void setDate ( long threadId , long date ) {
ContentValues contentValues = new ContentValues ( 1 ) ;
contentValues . put ( DATE, date ) ;
contentValues . put ( THREAD_CREATION_ DATE, date ) ;
SQLiteDatabase db = databaseHelper . getWritableDatabase ( ) ;
int updated = db . update ( TABLE_NAME , contentValues , ID_WHERE , new String [ ] { threadId + "" } ) ;
if ( updated > 0 ) notifyConversationListListeners ( ) ;
@ -375,11 +365,11 @@ public class ThreadDatabase extends Database {
public int getDistributionType ( long threadId ) {
SQLiteDatabase db = databaseHelper . getReadableDatabase ( ) ;
Cursor cursor = db . query ( TABLE_NAME , new String [ ] { TYPE} , ID_WHERE , new String [ ] { String . valueOf ( threadId ) } , null , null , null ) ;
Cursor cursor = db . query ( TABLE_NAME , new String [ ] { DISTRIBUTION_ TYPE} , ID_WHERE , new String [ ] { String . valueOf ( threadId ) } , null , null , null ) ;
try {
if ( cursor ! = null & & cursor . moveToNext ( ) ) {
return cursor . getInt ( cursor . getColumnIndexOrThrow ( TYPE) ) ;
return cursor . getInt ( cursor . getColumnIndexOrThrow ( DISTRIBUTION_ TYPE) ) ;
}
return DistributionTypes . DEFAULT ;
@ -469,7 +459,7 @@ public class ThreadDatabase extends Database {
Cursor cursor = null ;
try {
String where = "SELECT " + DATE + " FROM " + TABLE_NAME +
String where = "SELECT " + THREAD_CREATION_ DATE + " FROM " + TABLE_NAME +
" LEFT OUTER JOIN " + RecipientDatabase . TABLE_NAME +
" ON " + TABLE_NAME + "." + ADDRESS + " = " + RecipientDatabase . TABLE_NAME + "." + RecipientDatabase . ADDRESS +
" LEFT OUTER JOIN " + GroupDatabase . TABLE_NAME +
@ -477,7 +467,7 @@ public class ThreadDatabase extends Database {
" WHERE " + MESSAGE_COUNT + " != 0 AND " + ARCHIVED + " = 0 AND " + HAS_SENT + " = 0 AND " +
RecipientDatabase . TABLE_NAME + "." + RecipientDatabase . BLOCK + " = 0 AND " +
RecipientDatabase . TABLE_NAME + "." + RecipientDatabase . APPROVED + " = 0 AND " +
GroupDatabase . TABLE_NAME + "." + GROUP_ID + " IS NULL ORDER BY " + DATE + " DESC LIMIT 1" ;
GroupDatabase . TABLE_NAME + "." + GROUP_ID + " IS NULL ORDER BY " + THREAD_CREATION_ DATE + " DESC LIMIT 1" ;
cursor = db . rawQuery ( where , null ) ;
if ( cursor ! = null & & cursor . moveToFirst ( ) )
@ -595,7 +585,7 @@ public class ThreadDatabase extends Database {
public Long getLastUpdated ( long threadId ) {
SQLiteDatabase db = databaseHelper . getReadableDatabase ( ) ;
Cursor cursor = db . query ( TABLE_NAME , new String [ ] { DATE} , ID_WHERE , new String [ ] { String . valueOf ( threadId ) } , null , null , null ) ;
Cursor cursor = db . query ( TABLE_NAME , new String [ ] { THREAD_CREATION_ DATE} , ID_WHERE , new String [ ] { String . valueOf ( threadId ) } , null , null , null ) ;
try {
if ( cursor ! = null & & cursor . moveToFirst ( ) ) {
@ -736,7 +726,7 @@ public class ThreadDatabase extends Database {
MmsSmsDatabase mmsSmsDatabase = DatabaseComponent . get ( context ) . mmsSmsDatabase ( ) ;
long count = mmsSmsDatabase . getConversationCount ( threadId ) ;
boolean shouldDeleteEmptyThread = shouldDeleteOnEmpty & & d eleteThreadOnEmpty( threadId ) ;
boolean shouldDeleteEmptyThread = shouldDeleteOnEmpty & & possibleToD eleteThreadOnEmpty( threadId ) ;
if ( count = = 0 & & shouldDeleteEmptyThread ) {
deleteThread ( threadId ) ;
@ -810,7 +800,7 @@ public class ThreadDatabase extends Database {
return setLastSeen ( threadId , lastSeenTime ) ;
}
private boolean d eleteThreadOnEmpty( long threadId ) {
private boolean possibleToD eleteThreadOnEmpty( long threadId ) {
Recipient threadRecipient = getRecipientForThreadId ( threadId ) ;
return threadRecipient ! = null & & ! threadRecipient . isCommunityRecipient ( ) ;
}
@ -855,7 +845,7 @@ public class ThreadDatabase extends Database {
" LEFT OUTER JOIN " + GroupDatabase . TABLE_NAME +
" ON " + TABLE_NAME + "." + ADDRESS + " = " + GroupDatabase . TABLE_NAME + "." + GROUP_ID +
" WHERE " + where +
" ORDER BY " + TABLE_NAME + "." + IS_PINNED + " DESC, " + TABLE_NAME + "." + DATE + " DESC" ;
" ORDER BY " + TABLE_NAME + "." + IS_PINNED + " DESC, " + TABLE_NAME + "." + THREAD_CREATION_ DATE + " DESC" ;
if ( limit > 0 ) {
query + = " LIMIT " + limit ;
@ -900,7 +890,7 @@ public class ThreadDatabase extends Database {
public ThreadRecord getCurrent ( ) {
long threadId = cursor . getLong ( cursor . getColumnIndexOrThrow ( ThreadDatabase . ID ) ) ;
int distributionType = cursor . getInt ( cursor . getColumnIndexOrThrow ( ThreadDatabase . TYPE) ) ;
int distributionType = cursor . getInt ( cursor . getColumnIndexOrThrow ( ThreadDatabase . DISTRIBUTION_ TYPE) ) ;
Address address = Address . fromSerialized ( cursor . getString ( cursor . getColumnIndexOrThrow ( ThreadDatabase . ADDRESS ) ) ) ;
Optional < RecipientSettings > settings ;
@ -916,7 +906,7 @@ public class ThreadDatabase extends Database {
Recipient recipient = Recipient . from ( context , address , settings , groupRecord , true ) ;
String body = cursor . getString ( cursor . getColumnIndexOrThrow ( ThreadDatabase . SNIPPET ) ) ;
long date = cursor . getLong ( cursor . getColumnIndexOrThrow ( ThreadDatabase . DATE) ) ;
long date = cursor . getLong ( cursor . getColumnIndexOrThrow ( ThreadDatabase . THREAD_CREATION_ DATE) ) ;
long count = cursor . getLong ( cursor . getColumnIndexOrThrow ( ThreadDatabase . MESSAGE_COUNT ) ) ;
int unreadCount = cursor . getInt ( cursor . getColumnIndexOrThrow ( ThreadDatabase . UNREAD_COUNT ) ) ;
int unreadMentionCount = cursor . getInt ( cursor . getColumnIndexOrThrow ( ThreadDatabase . UNREAD_MENTION_COUNT ) ) ;
@ -934,7 +924,17 @@ public class ThreadDatabase extends Database {
readReceiptCount = 0 ;
}
return new ThreadRecord ( body , snippetUri , recipient , date , count ,
MessageRecord lastMessage = null ;
if ( count > 0 ) {
MmsSmsDatabase mmsSmsDatabase = DatabaseComponent . get ( context ) . mmsSmsDatabase ( ) ;
long messageTimestamp = mmsSmsDatabase . getLastMessageTimestamp ( threadId ) ;
if ( messageTimestamp > 0 ) {
lastMessage = mmsSmsDatabase . getMessageForTimestamp ( messageTimestamp ) ;
}
}
return new ThreadRecord ( body , snippetUri , lastMessage , recipient , date , count ,
unreadCount , unreadMentionCount , threadId , deliveryReceiptCount , status , type ,
distributionType , archived , expiresIn , lastSeen , readReceiptCount , pinned ) ;
}