diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 5951f44968..a4e6bf6d61 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -332,11 +332,6 @@ android:theme="@style/Signal.DayNight.NoActionBar" android:windowSoftInputMode="adjustResize"/> - - - { initializeLogging(); diff --git a/app/src/main/java/org/thoughtcrime/securesms/DatabaseMigrationActivity.java b/app/src/main/java/org/thoughtcrime/securesms/DatabaseMigrationActivity.java deleted file mode 100644 index 06cd92f665..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/DatabaseMigrationActivity.java +++ /dev/null @@ -1,201 +0,0 @@ -package org.thoughtcrime.securesms; - -import android.content.BroadcastReceiver; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.ServiceConnection; -import android.os.Bundle; -import android.os.Handler; -import android.os.IBinder; -import android.os.Looper; -import android.os.Message; -import android.os.Parcelable; -import android.view.View; -import android.widget.Button; -import android.widget.LinearLayout; -import android.widget.ProgressBar; -import android.widget.TextView; - -import org.thoughtcrime.securesms.database.SmsMigrator.ProgressDescription; -import org.thoughtcrime.securesms.service.ApplicationMigrationService; -import org.thoughtcrime.securesms.service.ApplicationMigrationService.ImportState; - -public class DatabaseMigrationActivity extends PassphraseRequiredActivity { - - private final ImportServiceConnection serviceConnection = new ImportServiceConnection(); - private final ImportStateHandler importStateHandler = new ImportStateHandler(); - private final BroadcastReceiver completedReceiver = new NullReceiver(); - - private LinearLayout promptLayout; - private LinearLayout progressLayout; - private Button skipButton; - private Button importButton; - private ProgressBar progress; - private TextView progressLabel; - - private ApplicationMigrationService importService; - private boolean isVisible = false; - - @Override - protected void onCreate(Bundle bundle, boolean ready) { - setContentView(R.layout.database_migration_activity); - - initializeResources(); - initializeServiceBinding(); - } - - @Override - public void onResume() { - super.onResume(); - isVisible = true; - registerForCompletedNotification(); - } - - @Override - public void onPause() { - super.onPause(); - isVisible = false; - unregisterForCompletedNotification(); - } - - @Override - public void onDestroy() { - super.onDestroy(); - shutdownServiceBinding(); - } - - @Override - public void onBackPressed() { - - } - - private void initializeServiceBinding() { - Intent intent = new Intent(this, ApplicationMigrationService.class); - bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE); - } - - private void initializeResources() { - this.promptLayout = (LinearLayout)findViewById(R.id.prompt_layout); - this.progressLayout = (LinearLayout)findViewById(R.id.progress_layout); - this.skipButton = (Button) findViewById(R.id.skip_button); - this.importButton = (Button) findViewById(R.id.import_button); - this.progress = (ProgressBar) findViewById(R.id.import_progress); - this.progressLabel = (TextView) findViewById(R.id.import_status); - - this.progressLayout.setVisibility(View.GONE); - this.promptLayout.setVisibility(View.GONE); - - this.importButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - Intent intent = new Intent(DatabaseMigrationActivity.this, ApplicationMigrationService.class); - intent.setAction(ApplicationMigrationService.MIGRATE_DATABASE); - intent.putExtra("master_secret", (Parcelable)getIntent().getParcelableExtra("master_secret")); - startService(intent); - - promptLayout.setVisibility(View.GONE); - progressLayout.setVisibility(View.VISIBLE); - } - }); - - this.skipButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - ApplicationMigrationService.setDatabaseImported(DatabaseMigrationActivity.this); - handleImportComplete(); - } - }); - } - - private void registerForCompletedNotification() { - IntentFilter filter = new IntentFilter(); - filter.addAction(ApplicationMigrationService.COMPLETED_ACTION); - filter.setPriority(1000); - - registerReceiver(completedReceiver, filter); - } - - private void unregisterForCompletedNotification() { - unregisterReceiver(completedReceiver); - } - - private void shutdownServiceBinding() { - unbindService(serviceConnection); - } - - private void handleStateIdle() { - this.promptLayout.setVisibility(View.VISIBLE); - this.progressLayout.setVisibility(View.GONE); - } - - private void handleStateProgress(ProgressDescription update) { - this.promptLayout.setVisibility(View.GONE); - this.progressLayout.setVisibility(View.VISIBLE); - this.progressLabel.setText(update.primaryComplete + "/" + update.primaryTotal); - - double max = this.progress.getMax(); - double primaryTotal = update.primaryTotal; - double primaryComplete = update.primaryComplete; - double secondaryTotal = update.secondaryTotal; - double secondaryComplete = update.secondaryComplete; - - this.progress.setProgress((int)Math.round((primaryComplete / primaryTotal) * max)); - this.progress.setSecondaryProgress((int)Math.round((secondaryComplete / secondaryTotal) * max)); - } - - private void handleImportComplete() { - if (isVisible) { - if (getIntent().hasExtra("next_intent")) { - startActivity((Intent)getIntent().getParcelableExtra("next_intent")); - } else { - // TODO [greyson] Navigation - startActivity(MainActivity.clearTop(this)); - } - } - - finish(); - } - - private class ImportStateHandler extends Handler { - - public ImportStateHandler() { - super(Looper.getMainLooper()); - } - - @Override - public void handleMessage(Message message) { - switch (message.what) { - case ImportState.STATE_IDLE: handleStateIdle(); break; - case ImportState.STATE_MIGRATING_IN_PROGRESS: handleStateProgress((ProgressDescription)message.obj); break; - case ImportState.STATE_MIGRATING_COMPLETE: handleImportComplete(); break; - } - } - } - - private class ImportServiceConnection implements ServiceConnection { - @Override - public void onServiceConnected(ComponentName className, IBinder service) { - importService = ((ApplicationMigrationService.ApplicationMigrationBinder)service).getService(); - importService.setImportStateHandler(importStateHandler); - - ImportState state = importService.getState(); - importStateHandler.obtainMessage(state.state, state.progress).sendToTarget(); - } - - @Override - public void onServiceDisconnected(ComponentName name) { - importService.setImportStateHandler(null); - } - } - - private static class NullReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - abortBroadcast(); - } - } - - -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/reminder/SystemSmsImportReminder.java b/app/src/main/java/org/thoughtcrime/securesms/components/reminder/SystemSmsImportReminder.java deleted file mode 100644 index c99bf05b28..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/components/reminder/SystemSmsImportReminder.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.thoughtcrime.securesms.components.reminder; - -import android.content.Context; -import android.content.Intent; -import android.view.View; -import android.view.View.OnClickListener; - -import org.thoughtcrime.securesms.DatabaseMigrationActivity; -import org.thoughtcrime.securesms.MainActivity; -import org.thoughtcrime.securesms.R; -import org.thoughtcrime.securesms.service.ApplicationMigrationService; - -public class SystemSmsImportReminder extends Reminder { - - public SystemSmsImportReminder(final Context context) { - super(context.getString(R.string.reminder_header_sms_import_title), - context.getString(R.string.reminder_header_sms_import_text)); - - final OnClickListener okListener = v -> { - Intent intent = new Intent(context, ApplicationMigrationService.class); - intent.setAction(ApplicationMigrationService.MIGRATE_DATABASE); - context.startService(intent); - - // TODO [greyson] Navigation - Intent nextIntent = MainActivity.clearTop(context); - Intent activityIntent = new Intent(context, DatabaseMigrationActivity.class); - activityIntent.putExtra("next_intent", nextIntent); - context.startActivity(activityIntent); - }; - final OnClickListener cancelListener = new OnClickListener() { - @Override - public void onClick(View v) { - ApplicationMigrationService.setDatabaseImported(context); - } - }; - setOkListener(okListener); - setDismissListener(cancelListener); - } - - public static boolean isEligible(Context context) { - return !ApplicationMigrationService.isDatabaseImported(context); - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/GroupTable.java b/app/src/main/java/org/thoughtcrime/securesms/database/GroupTable.java index 78c162718b..5be2b06403 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/GroupTable.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/GroupTable.java @@ -137,7 +137,7 @@ public class GroupTable extends DatabaseTable implements RecipientIdDatabaseRefe TIMESTAMP, ACTIVE, MMS, V2_MASTER_KEY, V2_REVISION, V2_DECRYPTED_GROUP, LAST_FORCE_UPDATE_TIMESTAMP }; - static final List TYPED_GROUP_PROJECTION = Stream.of(GROUP_PROJECTION).map(columnName -> TABLE_NAME + "." + columnName).toList(); + static final List TYPED_GROUP_PROJECTION = Stream.of(GROUP_PROJECTION).filterNot(it -> it.equals(RECIPIENT_ID)).map(columnName -> TABLE_NAME + "." + columnName).toList(); public GroupTable(Context context, SignalDatabase databaseHelper) { super(context, databaseHelper); diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MediaTable.java b/app/src/main/java/org/thoughtcrime/securesms/database/MediaTable.java index 23502f8aad..e5323428ba 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MediaTable.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MediaTable.java @@ -48,7 +48,7 @@ public class MediaTable extends DatabaseTable { + AttachmentTable.TABLE_NAME + "." + AttachmentTable.CAPTION + ", " + AttachmentTable.TABLE_NAME + "." + AttachmentTable.NAME + ", " + AttachmentTable.TABLE_NAME + "." + AttachmentTable.UPLOAD_TIMESTAMP + ", " - + MmsTable.TABLE_NAME + "." + MmsTable.MESSAGE_BOX + ", " + + MmsTable.TABLE_NAME + "." + MmsTable.TYPE + ", " + MmsTable.TABLE_NAME + "." + MmsTable.DATE_SENT + ", " + MmsTable.TABLE_NAME + "." + MmsTable.DATE_RECEIVED + ", " + MmsTable.TABLE_NAME + "." + MmsTable.DATE_SERVER + ", " @@ -67,7 +67,7 @@ public class MediaTable extends DatabaseTable { + AttachmentTable.DATA + " IS NOT NULL AND " + "(" + AttachmentTable.QUOTE + " = 0 OR (" + AttachmentTable.QUOTE + " = 1 AND " + AttachmentTable.DATA_HASH + " IS NULL)) AND " + AttachmentTable.STICKER_PACK_ID + " IS NULL AND " - + MmsTable.RECIPIENT_ID + " > 0 AND " + + MmsTable.TABLE_NAME + "." + MmsTable.RECIPIENT_ID + " > 0 AND " + THREAD_RECIPIENT_ID + " > 0"; private static final String UNIQUE_MEDIA_QUERY = "SELECT " @@ -194,11 +194,11 @@ public class MediaTable extends DatabaseTable { List attachments = attachmentDatabase.getAttachments(cursor); RecipientId recipientId = RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.RECIPIENT_ID))); long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.THREAD_ID)); - boolean outgoing = MessageTable.Types.isOutgoingMessageType(cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.MESSAGE_BOX))); + boolean outgoing = MessageTable.Types.isOutgoingMessageType(cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.TYPE))); long date; - if (MmsTable.Types.isPushType(cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.MESSAGE_BOX)))) { + if (MmsTable.Types.isPushType(cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.TYPE)))) { date = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.DATE_SENT)); } else { date = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.DATE_RECEIVED)); diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MessageTable.java b/app/src/main/java/org/thoughtcrime/securesms/database/MessageTable.java index 1088305ba2..46310a1a01 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MessageTable.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MessageTable.java @@ -197,7 +197,6 @@ public abstract class MessageTable extends DatabaseTable implements MmsSmsColumn public abstract void endTransaction(SQLiteDatabase database); public abstract void setTransactionSuccessful(); public abstract void endTransaction(); - public abstract SQLiteStatement createInsertStatement(SQLiteDatabase database); public abstract void ensureMigration(); @@ -233,7 +232,7 @@ public abstract class MessageTable extends DatabaseTable implements MmsSmsColumn final @NonNull String getOutgoingTypeClause() { List segments = new ArrayList<>(Types.OUTGOING_MESSAGE_TYPES.length); for (long outgoingMessageType : Types.OUTGOING_MESSAGE_TYPES) { - segments.add("(" + getTypeField() + " & " + Types.BASE_TYPE_MASK + " = " + outgoingMessageType + ")"); + segments.add("(" + getTableName() + "." + getTypeField() + " & " + Types.BASE_TYPE_MASK + " = " + outgoingMessageType + ")"); } return Util.join(segments, " OR "); diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsColumns.java b/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsColumns.java index a80fd6ee6f..5dbd4d0a5c 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsColumns.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsColumns.java @@ -4,21 +4,21 @@ package org.thoughtcrime.securesms.database; public interface MmsSmsColumns { public static final String ID = "_id"; - public static final String NORMALIZED_DATE_SENT = "date_sent"; - public static final String NORMALIZED_DATE_RECEIVED = "date_received"; - public static final String NORMALIZED_TYPE = "type"; + public static final String DATE_SENT = "date_sent"; + public static final String DATE_RECEIVED = "date_received"; + public static final String TYPE = "type"; public static final String DATE_SERVER = "date_server"; public static final String THREAD_ID = "thread_id"; public static final String READ = "read"; public static final String BODY = "body"; - public static final String RECIPIENT_ID = "address"; - public static final String ADDRESS_DEVICE_ID = "address_device_id"; + public static final String RECIPIENT_ID = "recipient_id"; + public static final String RECIPIENT_DEVICE_ID = "recipient_device_id"; public static final String DELIVERY_RECEIPT_COUNT = "delivery_receipt_count"; public static final String READ_RECEIPT_COUNT = "read_receipt_count"; public static final String VIEWED_RECEIPT_COUNT = "viewed_receipt_count"; public static final String MISMATCHED_IDENTITIES = "mismatched_identities"; public static final String UNIQUE_ROW_ID = "unique_row_id"; - public static final String SUBSCRIPTION_ID = "subscription_id"; + public static final String SMS_SUBSCRIPTION_ID = "subscription_id"; public static final String EXPIRES_IN = "expires_in"; public static final String EXPIRE_STARTED = "expire_started"; public static final String NOTIFIED = "notified"; diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsTable.java b/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsTable.java index 6b92fec9bf..0551909f20 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsTable.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MmsSmsTable.java @@ -70,30 +70,27 @@ public class MmsSmsTable extends DatabaseTable { private static final String[] PROJECTION = { MmsSmsColumns.ID, MmsSmsColumns.UNIQUE_ROW_ID, - SmsTable.BODY, - SmsTable.TYPE, + MmsSmsColumns.BODY, + MmsSmsColumns.TYPE, MmsSmsColumns.THREAD_ID, SmsTable.RECIPIENT_ID, - SmsTable.ADDRESS_DEVICE_ID, - SmsTable.SUBJECT, - MmsSmsColumns.NORMALIZED_DATE_SENT, - MmsSmsColumns.NORMALIZED_DATE_RECEIVED, + SmsTable.RECIPIENT_DEVICE_ID, + MmsSmsColumns.DATE_SENT, + MmsSmsColumns.DATE_RECEIVED, MmsSmsColumns.DATE_SERVER, - MmsTable.MESSAGE_TYPE, - MmsTable.MESSAGE_BOX, - SmsTable.STATUS, + MmsTable.MMS_MESSAGE_TYPE, + SmsTable.SMS_STATUS, MmsSmsColumns.UNIDENTIFIED, - MmsTable.PART_COUNT, - MmsTable.CONTENT_LOCATION, - MmsTable.TRANSACTION_ID, - MmsTable.MESSAGE_SIZE, - MmsTable.EXPIRY, - MmsTable.STATUS, + MmsTable.MMS_CONTENT_LOCATION, + MmsTable.MMS_TRANSACTION_ID, + MmsTable.MMS_MESSAGE_SIZE, + MmsTable.MMS_EXPIRY, + MmsTable.MMS_STATUS, MmsSmsColumns.DELIVERY_RECEIPT_COUNT, MmsSmsColumns.READ_RECEIPT_COUNT, MmsSmsColumns.MISMATCHED_IDENTITIES, - MmsTable.NETWORK_FAILURE, - MmsSmsColumns.SUBSCRIPTION_ID, + MmsTable.NETWORK_FAILURES, + MmsSmsColumns.SMS_SUBSCRIPTION_ID, MmsSmsColumns.EXPIRES_IN, MmsSmsColumns.EXPIRE_STARTED, MmsSmsColumns.NOTIFIED, @@ -103,7 +100,6 @@ public class MmsSmsTable extends DatabaseTable { MmsTable.QUOTE_AUTHOR, MmsTable.QUOTE_BODY, MmsTable.QUOTE_MISSING, - MmsTable.QUOTE_ATTACHMENT, MmsTable.QUOTE_TYPE, MmsTable.QUOTE_MENTIONS, MmsTable.SHARED_CONTACTS, @@ -121,12 +117,12 @@ public class MmsSmsTable extends DatabaseTable { MmsTable.STORY_TYPE, MmsTable.PARENT_STORY_ID}; - private static final String SNIPPET_QUERY = "SELECT " + MmsSmsColumns.ID + ", 0 AS " + TRANSPORT + ", " + SmsTable.TYPE + " AS " + MmsSmsColumns.NORMALIZED_TYPE + ", " + SmsTable.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " FROM " + SmsTable.TABLE_NAME + " " + - "WHERE " + MmsSmsColumns.THREAD_ID + " = ? AND " + SmsTable.TYPE + " NOT IN (" + SmsTable.Types.PROFILE_CHANGE_TYPE + ", " + SmsTable.Types.GV1_MIGRATION_TYPE + ", " + SmsTable.Types.CHANGE_NUMBER_TYPE + ", " + SmsTable.Types.BOOST_REQUEST_TYPE + ", " + SmsTable.Types.SMS_EXPORT_TYPE + ") AND " + SmsTable.TYPE + " & " + GROUP_V2_LEAVE_BITS + " != " + GROUP_V2_LEAVE_BITS + " " + + private static final String SNIPPET_QUERY = "SELECT " + MmsSmsColumns.ID + ", 0 AS " + TRANSPORT + ", " + MmsSmsColumns.TYPE + ", " + MmsSmsColumns.DATE_RECEIVED + " FROM " + SmsTable.TABLE_NAME + " " + + "WHERE " + MmsSmsColumns.THREAD_ID + " = ? AND " + MmsSmsColumns.TYPE + " NOT IN (" + SmsTable.Types.PROFILE_CHANGE_TYPE + ", " + SmsTable.Types.GV1_MIGRATION_TYPE + ", " + SmsTable.Types.CHANGE_NUMBER_TYPE + ", " + SmsTable.Types.BOOST_REQUEST_TYPE + ", " + SmsTable.Types.SMS_EXPORT_TYPE + ") AND " + SmsTable.TYPE + " & " + GROUP_V2_LEAVE_BITS + " != " + GROUP_V2_LEAVE_BITS + " " + "UNION ALL " + - "SELECT " + MmsSmsColumns.ID + ", 1 AS " + TRANSPORT + ", " + MmsTable.MESSAGE_BOX + " AS " + MmsSmsColumns.NORMALIZED_TYPE + ", " + MmsTable.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " FROM " + MmsTable.TABLE_NAME + " " + - "WHERE " + MmsSmsColumns.THREAD_ID + " = ? AND " + MmsTable.MESSAGE_BOX + " & " + GROUP_V2_LEAVE_BITS + " != " + GROUP_V2_LEAVE_BITS + " AND " + MmsTable.STORY_TYPE + " = 0 AND " + MmsTable.PARENT_STORY_ID + " <= 0 " + - "ORDER BY " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC " + + "SELECT " + MmsSmsColumns.ID + ", 1 AS " + TRANSPORT + ", " + MmsSmsColumns.TYPE + ", " + MmsTable.DATE_RECEIVED + " FROM " + MmsTable.TABLE_NAME + " " + + "WHERE " + MmsSmsColumns.THREAD_ID + " = ? AND " + MmsTable.TYPE + " & " + GROUP_V2_LEAVE_BITS + " != " + GROUP_V2_LEAVE_BITS + " AND " + MmsTable.STORY_TYPE + " = 0 AND " + MmsTable.PARENT_STORY_ID + " <= 0 " + + "ORDER BY " + MmsSmsColumns.DATE_RECEIVED + " DESC " + "LIMIT 1"; public MmsSmsTable(Context context, SignalDatabase databaseHelper) { @@ -165,7 +161,7 @@ public class MmsSmsTable extends DatabaseTable { public int getMessagePositionOnOrAfterTimestamp(long threadId, long timestamp) { String[] projection = new String[] { "COUNT(*)" }; String selection = MmsSmsColumns.THREAD_ID + " = " + threadId + " AND " + - MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " >= " + timestamp + " AND " + + MmsSmsColumns.DATE_RECEIVED + " >= " + timestamp + " AND " + MmsTable.STORY_TYPE + " = 0 AND " + MmsTable.PARENT_STORY_ID + " <= 0"; try (Cursor cursor = queryTables(projection, selection, null, null, false)) { @@ -179,7 +175,7 @@ public class MmsSmsTable extends DatabaseTable { public @Nullable MessageRecord getMessageFor(long timestamp, RecipientId authorId) { Recipient author = Recipient.resolved(authorId); - try (Cursor cursor = queryTables(PROJECTION, MmsSmsColumns.NORMALIZED_DATE_SENT + " = " + timestamp, null, null, true)) { + try (Cursor cursor = queryTables(PROJECTION, MmsSmsColumns.DATE_SENT + " = " + timestamp, null, null, true)) { MmsSmsTable.Reader reader = readerFor(cursor); MessageRecord messageRecord; @@ -210,7 +206,7 @@ public class MmsSmsTable extends DatabaseTable { public Cursor getConversation(long threadId, long offset, long limit) { SQLiteDatabase db = databaseHelper.getSignalReadableDatabase(); - String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC"; + String order = MmsSmsColumns.DATE_RECEIVED + " DESC"; String selection = MmsSmsColumns.THREAD_ID + " = " + threadId + " AND " + MmsTable.STORY_TYPE + " = 0 AND " + MmsTable.PARENT_STORY_ID + " <= 0"; String limitStr = limit > 0 || offset > 0 ? offset + ", " + limit : null; String query = buildQuery(PROJECTION, selection, order, limitStr, false); @@ -249,7 +245,7 @@ public class MmsSmsTable extends DatabaseTable { SQLiteDatabase db = databaseHelper.getSignalReadableDatabase(); try (Cursor cursor = db.rawQuery(SNIPPET_QUERY, SqlUtil.buildArgs(threadId, threadId))) { if (cursor.moveToFirst()) { - return CursorUtil.requireLong(cursor, MmsSmsColumns.NORMALIZED_TYPE); + return CursorUtil.requireLong(cursor, MmsSmsColumns.TYPE); } else { throw new NoSuchMessageException("no message"); } @@ -266,14 +262,14 @@ public class MmsSmsTable extends DatabaseTable { .append(MmsSmsColumns.THREAD_ID + " = ") .append(stickyThread.getConversationId().getThreadId()) .append(" AND ") - .append(MmsSmsColumns.NORMALIZED_DATE_RECEIVED) + .append(MmsSmsColumns.DATE_RECEIVED) .append(" >= ") .append(stickyThread.getEarliestTimestamp()) .append(getStickyWherePartForParentStoryId(stickyThread.getConversationId().getGroupStoryId())) .append(")"); } - String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " ASC"; + String order = MmsSmsColumns.DATE_RECEIVED + " ASC"; String selection = MmsSmsColumns.NOTIFIED + " = 0 AND " + MmsTable.STORY_TYPE + " = 0 AND (" + MmsSmsColumns.READ + " = 0 OR " + MmsSmsColumns.REACTIONS_UNREAD + " = 1" + (stickyQuery.length() > 0 ? " OR (" + stickyQuery + ")" : "") + ")"; return queryTables(PROJECTION, selection, order, null, true); @@ -304,7 +300,7 @@ public class MmsSmsTable extends DatabaseTable { RecipientId author = targetMessage.isOutgoing() ? Recipient.self().getId() : targetMessage.getRecipient().getId(); String query = MmsTable.QUOTE_ID + " = " + targetMessage.getDateSent() + " AND " + MmsTable.QUOTE_AUTHOR + " = " + author.serialize(); - String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC"; + String order = MmsSmsColumns.DATE_RECEIVED + " DESC"; List records = new ArrayList<>(); @@ -421,7 +417,7 @@ public class MmsSmsTable extends DatabaseTable { } public int getMessageCountBeforeDate(long date) { - String selection = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " < " + date; + String selection = MmsSmsColumns.DATE_RECEIVED + " < " + date; try (Cursor cursor = queryTables(new String[] { "COUNT(*)" }, selection, null, null, false)) { if (cursor != null && cursor.moveToFirst()) { @@ -761,10 +757,10 @@ public class MmsSmsTable extends DatabaseTable { } public int getQuotedMessagePosition(long threadId, long quoteId, @NonNull RecipientId recipientId) { - String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC"; + String order = MmsSmsColumns.DATE_RECEIVED + " DESC"; String selection = MmsSmsColumns.THREAD_ID + " = " + threadId + " AND " + MmsTable.STORY_TYPE + " = 0" + " AND " + MmsTable.PARENT_STORY_ID + " <= 0"; - try (Cursor cursor = queryTables(new String[]{ MmsSmsColumns.NORMALIZED_DATE_SENT, MmsSmsColumns.RECIPIENT_ID, MmsSmsColumns.REMOTE_DELETED}, selection, order, null, false)) { + try (Cursor cursor = queryTables(new String[]{ MmsSmsColumns.DATE_SENT, MmsSmsColumns.RECIPIENT_ID, MmsSmsColumns.REMOTE_DELETED}, selection, order, null, false)) { boolean isOwnNumber = Recipient.resolved(recipientId).isSelf(); while (cursor != null && cursor.moveToNext()) { @@ -784,10 +780,10 @@ public class MmsSmsTable extends DatabaseTable { } public int getMessagePositionInConversation(long threadId, long receivedTimestamp, @NonNull RecipientId recipientId) { - String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC"; + String order = MmsSmsColumns.DATE_RECEIVED + " DESC"; String selection = MmsSmsColumns.THREAD_ID + " = " + threadId + " AND " + MmsTable.STORY_TYPE + " = 0" + " AND " + MmsTable.PARENT_STORY_ID + " <= 0"; - try (Cursor cursor = queryTables(new String[]{ MmsSmsColumns.NORMALIZED_DATE_RECEIVED, MmsSmsColumns.RECIPIENT_ID, MmsSmsColumns.REMOTE_DELETED}, selection, order, null, false)) { + try (Cursor cursor = queryTables(new String[]{ MmsSmsColumns.DATE_RECEIVED, MmsSmsColumns.RECIPIENT_ID, MmsSmsColumns.REMOTE_DELETED}, selection, order, null, false)) { boolean isOwnNumber = Recipient.resolved(recipientId).isSelf(); while (cursor != null && cursor.moveToNext()) { @@ -831,14 +827,14 @@ public class MmsSmsTable extends DatabaseTable { final String selection; if (groupStoryId > 0) { - order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " ASC"; + order = MmsSmsColumns.DATE_RECEIVED + " ASC"; selection = MmsSmsColumns.THREAD_ID + " = " + threadId + " AND " + - MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " < " + receivedTimestamp + " AND " + + MmsSmsColumns.DATE_RECEIVED + " < " + receivedTimestamp + " AND " + MmsTable.STORY_TYPE + " = 0 AND " + MmsTable.PARENT_STORY_ID + " = " + groupStoryId; } else { - order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC"; + order = MmsSmsColumns.DATE_RECEIVED + " DESC"; selection = MmsSmsColumns.THREAD_ID + " = " + threadId + " AND " + - MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " > " + receivedTimestamp + " AND " + + MmsSmsColumns.DATE_RECEIVED + " > " + receivedTimestamp + " AND " + MmsTable.STORY_TYPE + " = 0 AND " + MmsTable.PARENT_STORY_ID + " <= 0"; } @@ -851,10 +847,10 @@ public class MmsSmsTable extends DatabaseTable { } public long getTimestampForFirstMessageAfterDate(long date) { - String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " ASC"; - String selection = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " > " + date; + String order = MmsSmsColumns.DATE_RECEIVED + " ASC"; + String selection = MmsSmsColumns.DATE_RECEIVED + " > " + date; - try (Cursor cursor = queryTables(new String[] { MmsSmsColumns.NORMALIZED_DATE_RECEIVED }, selection, order, "1", false)) { + try (Cursor cursor = queryTables(new String[] { MmsSmsColumns.DATE_RECEIVED }, selection, order, "1", false)) { if (cursor != null && cursor.moveToFirst()) { return cursor.getLong(0); } @@ -926,41 +922,37 @@ public class MmsSmsTable extends DatabaseTable { attachmentJsonJoin = "NULL"; } - String[] mmsProjection = { MmsTable.DATE_SENT + " AS " + MmsSmsColumns.NORMALIZED_DATE_SENT, - MmsTable.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED, + String[] mmsProjection = { MmsSmsColumns.DATE_SENT, + MmsSmsColumns.DATE_RECEIVED, MmsTable.TABLE_NAME + "." + MmsTable.ID + " AS " + MmsSmsColumns.ID, "'MMS::' || " + MmsTable.TABLE_NAME + "." + MmsTable.ID + " || '::' || " + MmsTable.DATE_SENT + " AS " + MmsSmsColumns.UNIQUE_ROW_ID, - attachmentJsonJoin + " AS " + AttachmentTable.ATTACHMENT_JSON_ALIAS, + attachmentJsonJoin + " AS " + AttachmentTable.ATTACHMENT_JSON_ALIAS, SmsTable.BODY, MmsSmsColumns.READ, MmsSmsColumns.THREAD_ID, - SmsTable.TYPE, - SmsTable.RECIPIENT_ID, - SmsTable.ADDRESS_DEVICE_ID, - SmsTable.SUBJECT, - MmsTable.MESSAGE_TYPE, - MmsTable.MESSAGE_BOX, - SmsTable.STATUS, - MmsTable.PART_COUNT, - MmsTable.CONTENT_LOCATION, - MmsTable.TRANSACTION_ID, - MmsTable.MESSAGE_SIZE, - MmsTable.EXPIRY, - MmsTable.STATUS, + MmsSmsColumns.TYPE, + MmsSmsColumns.RECIPIENT_ID, + MmsSmsColumns.RECIPIENT_DEVICE_ID, + MmsTable.MMS_MESSAGE_TYPE, + SmsTable.SMS_STATUS, + MmsTable.MMS_CONTENT_LOCATION, + MmsTable.MMS_TRANSACTION_ID, + MmsTable.MMS_MESSAGE_SIZE, + MmsTable.MMS_EXPIRY, + MmsTable.MMS_STATUS, MmsTable.UNIDENTIFIED, MmsSmsColumns.DELIVERY_RECEIPT_COUNT, MmsSmsColumns.READ_RECEIPT_COUNT, MmsSmsColumns.MISMATCHED_IDENTITIES, - MmsSmsColumns.SUBSCRIPTION_ID, + MmsSmsColumns.SMS_SUBSCRIPTION_ID, MmsSmsColumns.EXPIRES_IN, MmsSmsColumns.EXPIRE_STARTED, MmsSmsColumns.NOTIFIED, - MmsTable.NETWORK_FAILURE, TRANSPORT, + MmsTable.NETWORK_FAILURES, TRANSPORT, MmsTable.QUOTE_ID, MmsTable.QUOTE_AUTHOR, MmsTable.QUOTE_BODY, MmsTable.QUOTE_MISSING, - MmsTable.QUOTE_ATTACHMENT, MmsTable.QUOTE_TYPE, MmsTable.QUOTE_MENTIONS, MmsTable.SHARED_CONTACTS, @@ -978,26 +970,36 @@ public class MmsSmsTable extends DatabaseTable { MmsTable.STORY_TYPE, MmsTable.PARENT_STORY_ID}; - String[] smsProjection = { SmsTable.DATE_SENT + " AS " + MmsSmsColumns.NORMALIZED_DATE_SENT, - SmsTable.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED, + String[] smsProjection = { MmsSmsColumns.DATE_SENT, + MmsSmsColumns.DATE_RECEIVED, MmsSmsColumns.ID, "'SMS::' || " + MmsSmsColumns.ID + " || '::' || " + SmsTable.DATE_SENT + " AS " + MmsSmsColumns.UNIQUE_ROW_ID, - "NULL AS " + AttachmentTable.ATTACHMENT_JSON_ALIAS, - SmsTable.BODY, MmsSmsColumns.READ, MmsSmsColumns.THREAD_ID, - SmsTable.TYPE, SmsTable.RECIPIENT_ID, SmsTable.ADDRESS_DEVICE_ID, SmsTable.SUBJECT, MmsTable.MESSAGE_TYPE, - MmsTable.MESSAGE_BOX, SmsTable.STATUS, MmsTable.PART_COUNT, - MmsTable.CONTENT_LOCATION, MmsTable.TRANSACTION_ID, - MmsTable.MESSAGE_SIZE, MmsTable.EXPIRY, MmsTable.STATUS, + "NULL AS " + AttachmentTable.ATTACHMENT_JSON_ALIAS, + SmsTable.BODY, + MmsSmsColumns.READ, + MmsSmsColumns.THREAD_ID, + MmsSmsColumns.TYPE, + SmsTable.RECIPIENT_ID, + SmsTable.RECIPIENT_DEVICE_ID, + MmsTable.MMS_MESSAGE_TYPE, + SmsTable.SMS_STATUS, + MmsTable.MMS_CONTENT_LOCATION, + MmsTable.MMS_TRANSACTION_ID, + MmsTable.MMS_MESSAGE_SIZE, + MmsTable.MMS_EXPIRY, + MmsTable.MMS_STATUS, MmsTable.UNIDENTIFIED, - MmsSmsColumns.DELIVERY_RECEIPT_COUNT, MmsSmsColumns.READ_RECEIPT_COUNT, + MmsSmsColumns.DELIVERY_RECEIPT_COUNT, + MmsSmsColumns.READ_RECEIPT_COUNT, MmsSmsColumns.MISMATCHED_IDENTITIES, - MmsSmsColumns.SUBSCRIPTION_ID, MmsSmsColumns.EXPIRES_IN, MmsSmsColumns.EXPIRE_STARTED, + MmsSmsColumns.SMS_SUBSCRIPTION_ID, + MmsSmsColumns.EXPIRES_IN, + MmsSmsColumns.EXPIRE_STARTED, MmsSmsColumns.NOTIFIED, - MmsTable.NETWORK_FAILURE, TRANSPORT, + MmsTable.NETWORK_FAILURES, TRANSPORT, MmsTable.QUOTE_ID, MmsTable.QUOTE_AUTHOR, MmsTable.QUOTE_BODY, MmsTable.QUOTE_MISSING, - MmsTable.QUOTE_ATTACHMENT, MmsTable.QUOTE_TYPE, MmsTable.QUOTE_MENTIONS, MmsTable.SHARED_CONTACTS, @@ -1038,32 +1040,30 @@ public class MmsSmsTable extends DatabaseTable { mmsColumnsPresent.add(MmsSmsColumns.THREAD_ID); mmsColumnsPresent.add(MmsSmsColumns.BODY); mmsColumnsPresent.add(MmsSmsColumns.RECIPIENT_ID); - mmsColumnsPresent.add(MmsSmsColumns.ADDRESS_DEVICE_ID); + mmsColumnsPresent.add(MmsSmsColumns.RECIPIENT_DEVICE_ID); mmsColumnsPresent.add(MmsSmsColumns.DELIVERY_RECEIPT_COUNT); mmsColumnsPresent.add(MmsSmsColumns.READ_RECEIPT_COUNT); mmsColumnsPresent.add(MmsSmsColumns.MISMATCHED_IDENTITIES); - mmsColumnsPresent.add(MmsSmsColumns.SUBSCRIPTION_ID); + mmsColumnsPresent.add(MmsSmsColumns.SMS_SUBSCRIPTION_ID); mmsColumnsPresent.add(MmsSmsColumns.EXPIRES_IN); mmsColumnsPresent.add(MmsSmsColumns.EXPIRE_STARTED); - mmsColumnsPresent.add(MmsTable.MESSAGE_TYPE); - mmsColumnsPresent.add(MmsTable.MESSAGE_BOX); + mmsColumnsPresent.add(MmsTable.MMS_MESSAGE_TYPE); + mmsColumnsPresent.add(MmsTable.TYPE); mmsColumnsPresent.add(MmsTable.DATE_SENT); mmsColumnsPresent.add(MmsTable.DATE_RECEIVED); mmsColumnsPresent.add(MmsTable.DATE_SERVER); - mmsColumnsPresent.add(MmsTable.PART_COUNT); - mmsColumnsPresent.add(MmsTable.CONTENT_LOCATION); - mmsColumnsPresent.add(MmsTable.TRANSACTION_ID); - mmsColumnsPresent.add(MmsTable.MESSAGE_SIZE); - mmsColumnsPresent.add(MmsTable.EXPIRY); + mmsColumnsPresent.add(MmsTable.MMS_CONTENT_LOCATION); + mmsColumnsPresent.add(MmsTable.MMS_TRANSACTION_ID); + mmsColumnsPresent.add(MmsTable.MMS_MESSAGE_SIZE); + mmsColumnsPresent.add(MmsTable.MMS_EXPIRY); mmsColumnsPresent.add(MmsTable.NOTIFIED); - mmsColumnsPresent.add(MmsTable.STATUS); + mmsColumnsPresent.add(MmsTable.MMS_STATUS); mmsColumnsPresent.add(MmsTable.UNIDENTIFIED); - mmsColumnsPresent.add(MmsTable.NETWORK_FAILURE); + mmsColumnsPresent.add(MmsTable.NETWORK_FAILURES); mmsColumnsPresent.add(MmsTable.QUOTE_ID); mmsColumnsPresent.add(MmsTable.QUOTE_AUTHOR); mmsColumnsPresent.add(MmsTable.QUOTE_BODY); mmsColumnsPresent.add(MmsTable.QUOTE_MISSING); - mmsColumnsPresent.add(MmsTable.QUOTE_ATTACHMENT); mmsColumnsPresent.add(MmsTable.QUOTE_TYPE); mmsColumnsPresent.add(MmsTable.QUOTE_MENTIONS); mmsColumnsPresent.add(MmsTable.SHARED_CONTACTS); @@ -1084,22 +1084,21 @@ public class MmsSmsTable extends DatabaseTable { smsColumnsPresent.add(MmsSmsColumns.ID); smsColumnsPresent.add(MmsSmsColumns.BODY); smsColumnsPresent.add(MmsSmsColumns.RECIPIENT_ID); - smsColumnsPresent.add(MmsSmsColumns.ADDRESS_DEVICE_ID); + smsColumnsPresent.add(MmsSmsColumns.RECIPIENT_DEVICE_ID); smsColumnsPresent.add(MmsSmsColumns.READ); smsColumnsPresent.add(MmsSmsColumns.THREAD_ID); smsColumnsPresent.add(MmsSmsColumns.DELIVERY_RECEIPT_COUNT); smsColumnsPresent.add(MmsSmsColumns.READ_RECEIPT_COUNT); smsColumnsPresent.add(MmsSmsColumns.MISMATCHED_IDENTITIES); - smsColumnsPresent.add(MmsSmsColumns.SUBSCRIPTION_ID); + smsColumnsPresent.add(MmsSmsColumns.SMS_SUBSCRIPTION_ID); smsColumnsPresent.add(MmsSmsColumns.EXPIRES_IN); smsColumnsPresent.add(MmsSmsColumns.EXPIRE_STARTED); smsColumnsPresent.add(MmsSmsColumns.NOTIFIED); smsColumnsPresent.add(SmsTable.TYPE); - smsColumnsPresent.add(SmsTable.SUBJECT); smsColumnsPresent.add(SmsTable.DATE_SENT); smsColumnsPresent.add(SmsTable.DATE_RECEIVED); smsColumnsPresent.add(SmsTable.DATE_SERVER); - smsColumnsPresent.add(SmsTable.STATUS); + smsColumnsPresent.add(SmsTable.SMS_STATUS); smsColumnsPresent.add(SmsTable.UNIDENTIFIED); smsColumnsPresent.add(SmsTable.REACTIONS_UNREAD); smsColumnsPresent.add(SmsTable.REACTIONS_LAST_SEEN); diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/MmsTable.java b/app/src/main/java/org/thoughtcrime/securesms/database/MmsTable.java index 6afa3d7af7..09e6794662 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/MmsTable.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/MmsTable.java @@ -31,8 +31,6 @@ import com.google.android.mms.pdu_alt.NotificationInd; import com.google.android.mms.pdu_alt.PduHeaders; import com.google.protobuf.InvalidProtocolBufferException; -import net.zetetic.database.sqlcipher.SQLiteStatement; - import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -121,80 +119,73 @@ public class MmsTable extends MessageTable { private static final String TAG = Log.tag(MmsTable.class); - public static final String TABLE_NAME = "mms"; - static final String DATE_SENT = "date"; - static final String DATE_RECEIVED = "date_received"; - public static final String MESSAGE_BOX = "msg_box"; - static final String CONTENT_LOCATION = "ct_l"; - static final String EXPIRY = "exp"; - public static final String MESSAGE_TYPE = "m_type"; - static final String MESSAGE_SIZE = "m_size"; - static final String STATUS = "st"; - static final String TRANSACTION_ID = "tr_id"; - static final String PART_COUNT = "part_count"; - static final String NETWORK_FAILURE = "network_failures"; + public static final String TABLE_NAME = "mms"; + static final String MMS_CONTENT_LOCATION = "ct_l"; + static final String MMS_EXPIRY = "exp"; + public static final String MMS_MESSAGE_TYPE = "m_type"; + static final String MMS_MESSAGE_SIZE = "m_size"; + static final String MMS_STATUS = "st"; + static final String MMS_TRANSACTION_ID = "tr_id"; + static final String NETWORK_FAILURES = "network_failures"; static final String QUOTE_ID = "quote_id"; static final String QUOTE_AUTHOR = "quote_author"; static final String QUOTE_BODY = "quote_body"; - static final String QUOTE_ATTACHMENT = "quote_attachment"; static final String QUOTE_MISSING = "quote_missing"; static final String QUOTE_MENTIONS = "quote_mentions"; static final String QUOTE_TYPE = "quote_type"; static final String SHARED_CONTACTS = "shared_contacts"; - static final String LINK_PREVIEWS = "previews"; + static final String LINK_PREVIEWS = "link_previews"; static final String MENTIONS_SELF = "mentions_self"; - static final String MESSAGE_RANGES = "ranges"; + static final String MESSAGE_RANGES = "message_ranges"; - public static final String VIEW_ONCE = "reveal_duration"; - public static final String STORY_TYPE = "is_story"; + public static final String VIEW_ONCE = "view_once"; + public static final String STORY_TYPE = "story_type"; static final String PARENT_STORY_ID = "parent_story_id"; public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" + ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + - THREAD_ID + " INTEGER, " + - DATE_SENT + " INTEGER, " + - DATE_RECEIVED + " INTEGER, " + + DATE_SENT + " INTEGER NOT NULL, " + + DATE_RECEIVED + " INTEGER NOT NULL, " + DATE_SERVER + " INTEGER DEFAULT -1, " + - MESSAGE_BOX + " INTEGER, " + - READ + " INTEGER DEFAULT 0, " + + THREAD_ID + " INTEGER NOT NULL REFERENCES " + ThreadTable.TABLE_NAME + " (" + ThreadTable.ID + ") ON DELETE CASCADE, " + + RECIPIENT_ID + " INTEGER NOT NULL REFERENCES " + RecipientTable.TABLE_NAME + " (" + RecipientTable.ID + ") ON DELETE CASCADE, " + + RECIPIENT_DEVICE_ID + " INTEGER, " + + TYPE + " INTEGER NOT NULL, " + BODY + " TEXT, " + - PART_COUNT + " INTEGER, " + - CONTENT_LOCATION + " TEXT, " + - RECIPIENT_ID + " INTEGER, " + - ADDRESS_DEVICE_ID + " INTEGER, " + - EXPIRY + " INTEGER, " + - MESSAGE_TYPE + " INTEGER, " + - MESSAGE_SIZE + " INTEGER, " + - STATUS + " INTEGER, " + - TRANSACTION_ID + " TEXT, " + + READ + " INTEGER DEFAULT 0, " + + MMS_CONTENT_LOCATION + " TEXT, " + + MMS_EXPIRY + " INTEGER, " + + MMS_MESSAGE_TYPE + " INTEGER, " + + MMS_MESSAGE_SIZE + " INTEGER, " + + MMS_STATUS + " INTEGER, " + + MMS_TRANSACTION_ID + " TEXT, " + + SMS_SUBSCRIPTION_ID + " INTEGER DEFAULT -1, " + + RECEIPT_TIMESTAMP + " INTEGER DEFAULT -1, " + DELIVERY_RECEIPT_COUNT + " INTEGER DEFAULT 0, " + + READ_RECEIPT_COUNT + " INTEGER DEFAULT 0, " + + VIEWED_RECEIPT_COUNT + " INTEGER DEFAULT 0, " + MISMATCHED_IDENTITIES + " TEXT DEFAULT NULL, " + - NETWORK_FAILURE + " TEXT DEFAULT NULL," + - SUBSCRIPTION_ID + " INTEGER DEFAULT -1, " + + NETWORK_FAILURES + " TEXT DEFAULT NULL," + EXPIRES_IN + " INTEGER DEFAULT 0, " + EXPIRE_STARTED + " INTEGER DEFAULT 0, " + NOTIFIED + " INTEGER DEFAULT 0, " + - READ_RECEIPT_COUNT + " INTEGER DEFAULT 0, " + QUOTE_ID + " INTEGER DEFAULT 0, " + - QUOTE_AUTHOR + " TEXT, " + - QUOTE_BODY + " TEXT, " + - QUOTE_ATTACHMENT + " INTEGER DEFAULT -1, " + + QUOTE_AUTHOR + " INTEGER DEFAULT 0, " + + QUOTE_BODY + " TEXT DEFAULT NULL, " + QUOTE_MISSING + " INTEGER DEFAULT 0, " + QUOTE_MENTIONS + " BLOB DEFAULT NULL," + QUOTE_TYPE + " INTEGER DEFAULT 0," + - SHARED_CONTACTS + " TEXT, " + + SHARED_CONTACTS + " TEXT DEFAULT NULL, " + UNIDENTIFIED + " INTEGER DEFAULT 0, " + - LINK_PREVIEWS + " TEXT, " + + LINK_PREVIEWS + " TEXT DEFAULT NULL, " + VIEW_ONCE + " INTEGER DEFAULT 0, " + REACTIONS_UNREAD + " INTEGER DEFAULT 0, " + REACTIONS_LAST_SEEN + " INTEGER DEFAULT -1, " + REMOTE_DELETED + " INTEGER DEFAULT 0, " + MENTIONS_SELF + " INTEGER DEFAULT 0, " + NOTIFIED_TIMESTAMP + " INTEGER DEFAULT 0, " + - VIEWED_RECEIPT_COUNT + " INTEGER DEFAULT 0, " + SERVER_GUID + " TEXT DEFAULT NULL, " + - RECEIPT_TIMESTAMP + " INTEGER DEFAULT -1, " + MESSAGE_RANGES + " BLOB DEFAULT NULL, " + STORY_TYPE + " INTEGER DEFAULT 0, " + PARENT_STORY_ID + " INTEGER DEFAULT 0, " + @@ -203,33 +194,64 @@ public class MmsTable extends MessageTable { public static final String[] CREATE_INDEXS = { "CREATE INDEX IF NOT EXISTS mms_read_and_notified_and_thread_id_index ON " + TABLE_NAME + "(" + READ + "," + NOTIFIED + "," + THREAD_ID + ");", - "CREATE INDEX IF NOT EXISTS mms_message_box_index ON " + TABLE_NAME + " (" + MESSAGE_BOX + ");", + "CREATE INDEX IF NOT EXISTS mms_type_index ON " + TABLE_NAME + " (" + TYPE + ");", "CREATE INDEX IF NOT EXISTS mms_date_sent_index ON " + TABLE_NAME + " (" + DATE_SENT + ", " + RECIPIENT_ID + ", " + THREAD_ID + ");", "CREATE INDEX IF NOT EXISTS mms_date_server_index ON " + TABLE_NAME + " (" + DATE_SERVER + ");", "CREATE INDEX IF NOT EXISTS mms_thread_date_index ON " + TABLE_NAME + " (" + THREAD_ID + ", " + DATE_RECEIVED + ");", "CREATE INDEX IF NOT EXISTS mms_reactions_unread_index ON " + TABLE_NAME + " (" + REACTIONS_UNREAD + ");", - "CREATE INDEX IF NOT EXISTS mms_is_story_index ON " + TABLE_NAME + " (" + STORY_TYPE + ");", + "CREATE INDEX IF NOT EXISTS mms_story_type_index ON " + TABLE_NAME + " (" + STORY_TYPE + ");", "CREATE INDEX IF NOT EXISTS mms_parent_story_id_index ON " + TABLE_NAME + " (" + PARENT_STORY_ID + ");", "CREATE INDEX IF NOT EXISTS mms_thread_story_parent_story_index ON " + TABLE_NAME + " (" + THREAD_ID + ", " + DATE_RECEIVED + "," + STORY_TYPE + "," + PARENT_STORY_ID + ");", "CREATE INDEX IF NOT EXISTS mms_quote_id_quote_author_index ON " + TABLE_NAME + "(" + QUOTE_ID + ", " + QUOTE_AUTHOR + ");", "CREATE INDEX IF NOT EXISTS mms_exported_index ON " + TABLE_NAME + " (" + EXPORTED + ");", - "CREATE INDEX IF NOT EXISTS mms_id_msg_box_payment_transactions_index ON " + TABLE_NAME + " (" + ID + "," + MESSAGE_BOX + ") WHERE " + MESSAGE_BOX + " & " + Types.SPECIAL_TYPE_PAYMENTS_NOTIFICATION + " != 0;" + "CREATE INDEX IF NOT EXISTS mms_id_type_payment_transactions_index ON " + TABLE_NAME + " (" + ID + "," + TYPE + ") WHERE " + TYPE + " & " + Types.SPECIAL_TYPE_PAYMENTS_NOTIFICATION + " != 0;" }; private static final String[] MMS_PROJECTION = new String[] { MmsTable.TABLE_NAME + "." + ID + " AS " + ID, - THREAD_ID, DATE_SENT + " AS " + NORMALIZED_DATE_SENT, - DATE_RECEIVED + " AS " + NORMALIZED_DATE_RECEIVED, + THREAD_ID, + DATE_SENT, + DATE_RECEIVED, DATE_SERVER, - MESSAGE_BOX, READ, - CONTENT_LOCATION, EXPIRY, MESSAGE_TYPE, - MESSAGE_SIZE, STATUS, TRANSACTION_ID, - BODY, PART_COUNT, RECIPIENT_ID, ADDRESS_DEVICE_ID, - DELIVERY_RECEIPT_COUNT, READ_RECEIPT_COUNT, MISMATCHED_IDENTITIES, NETWORK_FAILURE, SUBSCRIPTION_ID, - EXPIRES_IN, EXPIRE_STARTED, NOTIFIED, QUOTE_ID, QUOTE_AUTHOR, QUOTE_BODY, QUOTE_ATTACHMENT, QUOTE_TYPE, QUOTE_MISSING, QUOTE_MENTIONS, - SHARED_CONTACTS, LINK_PREVIEWS, UNIDENTIFIED, VIEW_ONCE, REACTIONS_UNREAD, REACTIONS_LAST_SEEN, - REMOTE_DELETED, MENTIONS_SELF, NOTIFIED_TIMESTAMP, VIEWED_RECEIPT_COUNT, RECEIPT_TIMESTAMP, MESSAGE_RANGES, - STORY_TYPE, PARENT_STORY_ID, + TYPE, + READ, + MMS_CONTENT_LOCATION, + MMS_EXPIRY, + MMS_MESSAGE_TYPE, + MMS_MESSAGE_SIZE, + MMS_STATUS, + MMS_TRANSACTION_ID, + BODY, + RECIPIENT_ID, + RECIPIENT_DEVICE_ID, + DELIVERY_RECEIPT_COUNT, + READ_RECEIPT_COUNT, + MISMATCHED_IDENTITIES, + NETWORK_FAILURES, + SMS_SUBSCRIPTION_ID, + EXPIRES_IN, + EXPIRE_STARTED, + NOTIFIED, + QUOTE_ID, + QUOTE_AUTHOR, + QUOTE_BODY, + QUOTE_TYPE, + QUOTE_MISSING, + QUOTE_MENTIONS, + SHARED_CONTACTS, + LINK_PREVIEWS, + UNIDENTIFIED, + VIEW_ONCE, + REACTIONS_UNREAD, + REACTIONS_LAST_SEEN, + REMOTE_DELETED, + MENTIONS_SELF, + NOTIFIED_TIMESTAMP, + VIEWED_RECEIPT_COUNT, + RECEIPT_TIMESTAMP, + MESSAGE_RANGES, + STORY_TYPE, + PARENT_STORY_ID, "json_group_array(json_object(" + "'" + AttachmentTable.ROW_ID + "', " + AttachmentTable.TABLE_NAME + "." + AttachmentTable.ROW_ID + ", " + "'" + AttachmentTable.UNIQUE_ID + "', " + AttachmentTable.TABLE_NAME + "." + AttachmentTable.UNIQUE_ID + ", " + @@ -266,9 +288,6 @@ public class MmsTable extends MessageTable { private static final String RAW_ID_WHERE = TABLE_NAME + "._id = ?"; - private static final String OUTGOING_INSECURE_MESSAGES_CLAUSE = "(" + MESSAGE_BOX + " & " + Types.BASE_TYPE_MASK + ") = " + Types.BASE_SENT_TYPE + " AND NOT (" + MESSAGE_BOX + " & " + Types.SECURE_MESSAGE_BIT + ")"; - private static final String OUTGOING_SECURE_MESSAGES_CLAUSE = "(" + MESSAGE_BOX + " & " + Types.BASE_TYPE_MASK + ") = " + Types.BASE_SENT_TYPE + " AND (" + MESSAGE_BOX + " & " + (Types.SECURE_MESSAGE_BIT | Types.PUSH_MESSAGE_BIT) + ")"; - private final EarlyReceiptCache earlyDeliveryReceiptCache = new EarlyReceiptCache("MmsDelivery"); public MmsTable(Context context, SignalDatabase databaseHelper) { @@ -292,7 +311,7 @@ public class MmsTable extends MessageTable { @Override protected String getTypeField() { - return MESSAGE_BOX; + return TYPE; } @Override @@ -384,8 +403,8 @@ public class MmsTable extends MessageTable { @Override public @NonNull List getViewedIncomingMessages(long threadId) { SQLiteDatabase db = databaseHelper.getSignalReadableDatabase(); - String[] columns = new String[]{ID, RECIPIENT_ID, DATE_SENT, MESSAGE_BOX, THREAD_ID, STORY_TYPE}; - String where = THREAD_ID + " = ? AND " + VIEWED_RECEIPT_COUNT + " > 0 AND " + MESSAGE_BOX + " & " + Types.BASE_INBOX_TYPE + " = " + Types.BASE_INBOX_TYPE; + String[] columns = new String[]{ ID, RECIPIENT_ID, DATE_SENT, TYPE, THREAD_ID, STORY_TYPE}; + String where = THREAD_ID + " = ? AND " + VIEWED_RECEIPT_COUNT + " > 0 AND " + TYPE + " & " + Types.BASE_INBOX_TYPE + " = " + Types.BASE_INBOX_TYPE; String[] args = SqlUtil.buildArgs(threadId); @@ -427,21 +446,20 @@ public class MmsTable extends MessageTable { } SQLiteDatabase database = databaseHelper.getSignalWritableDatabase(); - String[] columns = new String[]{ID, RECIPIENT_ID, DATE_SENT, MESSAGE_BOX, THREAD_ID, STORY_TYPE}; + String[] columns = new String[]{ ID, RECIPIENT_ID, DATE_SENT, TYPE, THREAD_ID, STORY_TYPE}; String where = ID + " IN (" + Util.join(messageIds, ",") + ") AND " + VIEWED_RECEIPT_COUNT + " = 0"; List results = new LinkedList<>(); database.beginTransaction(); try (Cursor cursor = database.query(TABLE_NAME, columns, where, null, null, null, null)) { while (cursor != null && cursor.moveToNext()) { - long type = CursorUtil.requireLong(cursor, MESSAGE_BOX); + long type = CursorUtil.requireLong(cursor, TYPE); if (Types.isSecureType(type) && Types.isInboxType(type)) { long messageId = CursorUtil.requireLong(cursor, ID); long threadId = CursorUtil.requireLong(cursor, THREAD_ID); RecipientId recipientId = RecipientId.from(CursorUtil.requireLong(cursor, RECIPIENT_ID)); long dateSent = CursorUtil.requireLong(cursor, DATE_SENT); SyncMessageId syncMessageId = new SyncMessageId(recipientId, dateSent); - StoryType storyType = StoryType.fromCode(CursorUtil.requireInt(cursor, STORY_TYPE)); results.add(new MarkedMessageInfo(threadId, syncMessageId, new MessageId(messageId, true), null)); @@ -599,11 +617,6 @@ public class MmsTable extends MessageTable { database.endTransaction(); } - @Override - public SQLiteStatement createInsertStatement(SQLiteDatabase database) { - throw new UnsupportedOperationException(); - } - @Override public void ensureMigration() { databaseHelper.getSignalWritableDatabase(); @@ -827,7 +840,7 @@ public class MmsTable extends MessageTable { @Override public @NonNull List getUnreadStoryThreadRecipientIds() { SQLiteDatabase db = getReadableDatabase(); - String query = "SELECT DISTINCT " + ThreadTable.RECIPIENT_ID + "\n" + String query = "SELECT DISTINCT " + ThreadTable.TABLE_NAME + "." + ThreadTable.RECIPIENT_ID + "\n" + "FROM " + TABLE_NAME + "\n" + "JOIN " + ThreadTable.TABLE_NAME + "\n" + "ON " + TABLE_NAME + "." + THREAD_ID + " = " + ThreadTable.TABLE_NAME + "." + ThreadTable.ID + "\n" @@ -849,27 +862,27 @@ public class MmsTable extends MessageTable { @Override public @NonNull List getOrderedStoryRecipientsAndIds(boolean isOutgoingOnly) { - String where = "WHERE is_story > 0 AND remote_deleted = 0" + (isOutgoingOnly ? " AND is_outgoing != 0" : "") + "\n"; + String where = "WHERE " + STORY_TYPE + " > 0 AND " + REMOTE_DELETED + " = 0" + (isOutgoingOnly ? " AND is_outgoing != 0" : "") + "\n"; SQLiteDatabase db = getReadableDatabase(); String query = "SELECT\n" - + " mms.date AS sent_timestamp,\n" - + " mms._id AS mms_id,\n" - + " thread_recipient_id,\n" + + " " + TABLE_NAME + "." + DATE_SENT + " AS sent_timestamp,\n" + + " " + TABLE_NAME + "." + ID + " AS mms_id,\n" + + " " + ThreadTable.TABLE_NAME + "." + ThreadTable.RECIPIENT_ID + ",\n" + " (" + getOutgoingTypeClause() + ") AS is_outgoing,\n" - + " viewed_receipt_count,\n" - + " mms.date,\n" - + " receipt_timestamp,\n" - + " (" + getOutgoingTypeClause() + ") = 0 AND viewed_receipt_count = 0 AS is_unread\n" - + "FROM mms\n" - + "JOIN thread\n" - + "ON mms.thread_id = thread._id\n" + + " " + VIEWED_RECEIPT_COUNT + ",\n" + + " " + TABLE_NAME + "." + DATE_SENT + ",\n" + + " " + RECEIPT_TIMESTAMP + ",\n" + + " (" + getOutgoingTypeClause() + ") = 0 AND " + VIEWED_RECEIPT_COUNT + " = 0 AS is_unread\n" + + "FROM " + TABLE_NAME + "\n" + + "JOIN " + ThreadTable.TABLE_NAME + "\n" + + "ON " + TABLE_NAME + "." + THREAD_ID + " = " + ThreadTable.TABLE_NAME + "." + ThreadTable.ID + "\n" + where + "ORDER BY\n" + "is_unread DESC,\n" + "CASE\n" - + "WHEN is_outgoing = 0 AND viewed_receipt_count = 0 THEN mms.date\n" - + "WHEN is_outgoing = 0 AND viewed_receipt_count > 0 THEN receipt_timestamp\n" - + "WHEN is_outgoing = 1 THEN mms.date\n" + + "WHEN is_outgoing = 0 AND " + VIEWED_RECEIPT_COUNT + " = 0 THEN " + MmsTable.TABLE_NAME + "." + MmsTable.DATE_SENT + "\n" + + "WHEN is_outgoing = 0 AND viewed_receipt_count > 0 THEN " + MmsTable.RECEIPT_TIMESTAMP + "\n" + + "WHEN is_outgoing = 1 THEN " + MmsTable.TABLE_NAME + "." + MmsTable.DATE_SENT + "\n" + "END DESC"; List results; @@ -1047,7 +1060,7 @@ public class MmsTable extends MessageTable { String[] columns = new String[]{ID}; long type = Types.getOutgoingEncryptedMessageType() | Types.GROUP_LEAVE_BIT; - String query = ID + " = ? AND " + MESSAGE_BOX + " & " + type + " = " + type + " AND " + MESSAGE_BOX + " & " + Types.GROUP_V2_BIT + " = 0"; + String query = ID + " = ? AND " + TYPE + " & " + type + " = " + type + " AND " + TYPE + " & " + Types.GROUP_V2_BIT + " = 0"; String[] args = SqlUtil.buildArgs(messageId); try (Cursor cursor = db.query(TABLE_NAME, columns, query, args, null, null, null, null)) { @@ -1065,7 +1078,7 @@ public class MmsTable extends MessageTable { String[] columns = new String[]{DATE_SENT}; long type = Types.getOutgoingEncryptedMessageType() | Types.GROUP_LEAVE_BIT; - String query = THREAD_ID + " = ? AND " + MESSAGE_BOX + " & " + type + " = " + type + " AND " + MESSAGE_BOX + " & " + Types.GROUP_V2_BIT + " = 0 AND " + DATE_SENT + " < ?"; + String query = THREAD_ID + " = ? AND " + TYPE + " & " + type + " = " + type + " AND " + TYPE + " & " + Types.GROUP_V2_BIT + " = 0 AND " + DATE_SENT + " < ?"; String[] args = new String[]{String.valueOf(threadId), String.valueOf(quitTimeBarrier)}; String orderBy = DATE_SENT + " DESC"; String limit = "1"; @@ -1139,7 +1152,7 @@ public class MmsTable extends MessageTable { @Override public void addFailures(long messageId, List failure) { try { - addToDocument(messageId, NETWORK_FAILURE, failure, NetworkFailureSet.class); + addToDocument(messageId, NETWORK_FAILURES, failure, NetworkFailureSet.class); } catch (IOException e) { Log.w(TAG, e); } @@ -1148,7 +1161,7 @@ public class MmsTable extends MessageTable { @Override public void setNetworkFailures(long messageId, Set failures) { try { - setDocument(databaseHelper.getSignalWritableDatabase(), messageId, NETWORK_FAILURE, new NetworkFailureSet(failures)); + setDocument(databaseHelper.getSignalWritableDatabase(), messageId, NETWORK_FAILURES, new NetworkFailureSet(failures)); } catch (IOException e) { Log.w(TAG, e); } @@ -1174,13 +1187,13 @@ public class MmsTable extends MessageTable { throw new IllegalArgumentException("Unsupported qualifier: " + messageQualifier); } - try (Cursor cursor = SQLiteDatabaseExtensionsKt.select(database, ID, THREAD_ID, MESSAGE_BOX, RECIPIENT_ID, receiptType.getColumnName(), RECEIPT_TIMESTAMP) + try (Cursor cursor = SQLiteDatabaseExtensionsKt.select(database, ID, THREAD_ID, TYPE, RECIPIENT_ID, receiptType.getColumnName(), RECEIPT_TIMESTAMP) .from(TABLE_NAME) .where(DATE_SENT + " = ?" + qualifierWhere, messageId.getTimetamp()) .run()) { while (cursor.moveToNext()) { - if (Types.isOutgoingMessageType(CursorUtil.requireLong(cursor, MESSAGE_BOX))) { + if (Types.isOutgoingMessageType(CursorUtil.requireLong(cursor, TYPE))) { RecipientId theirRecipientId = RecipientId.from(CursorUtil.requireLong(cursor, RECIPIENT_ID)); RecipientId ourRecipientId = messageId.getRecipientId(); String columnName = receiptType.getColumnName(); @@ -1340,7 +1353,7 @@ public class MmsTable extends MessageTable { db.beginTransaction(); try { db.execSQL("UPDATE " + TABLE_NAME + - " SET " + MESSAGE_BOX + " = (" + MESSAGE_BOX + " & " + (Types.TOTAL_MASK - maskOff) + " | " + maskOn + " )" + + " SET " + TYPE + " = (" + TYPE + " & " + (Types.TOTAL_MASK - maskOff) + " | " + maskOn + " )" + " WHERE " + ID + " = ?", new String[] { id + "" }); if (threadId.isPresent()) { @@ -1435,7 +1448,6 @@ public class MmsTable extends MessageTable { values.putNull(BODY); values.putNull(QUOTE_BODY); values.putNull(QUOTE_AUTHOR); - values.putNull(QUOTE_ATTACHMENT); values.putNull(QUOTE_TYPE); values.putNull(QUOTE_ID); values.putNull(LINK_PREVIEWS); @@ -1469,7 +1481,7 @@ public class MmsTable extends MessageTable { public void markDownloadState(long messageId, long state) { SQLiteDatabase database = databaseHelper.getSignalWritableDatabase(); ContentValues contentValues = new ContentValues(); - contentValues.put(STATUS, state); + contentValues.put(MMS_STATUS, state); database.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {messageId + ""}); ApplicationDependencies.getDatabaseObserver().notifyMessageUpdateObservers(new MessageId(messageId, true)); @@ -1608,10 +1620,10 @@ public class MmsTable extends MessageTable { database.beginTransaction(); try { - cursor = database.query(TABLE_NAME, new String[] {ID, RECIPIENT_ID, DATE_SENT, MESSAGE_BOX, EXPIRES_IN, EXPIRE_STARTED, THREAD_ID, STORY_TYPE }, where, arguments, null, null, null); + cursor = database.query(TABLE_NAME, new String[] { ID, RECIPIENT_ID, DATE_SENT, TYPE, EXPIRES_IN, EXPIRE_STARTED, THREAD_ID, STORY_TYPE }, where, arguments, null, null, null); while(cursor != null && cursor.moveToNext()) { - if (Types.isSecureType(CursorUtil.requireLong(cursor, MESSAGE_BOX))) { + if (Types.isSecureType(CursorUtil.requireLong(cursor, TYPE))) { long threadId = CursorUtil.requireLong(cursor, THREAD_ID); RecipientId recipientId = RecipientId.from(CursorUtil.requireLong(cursor, RECIPIENT_ID)); long dateSent = CursorUtil.requireLong(cursor, DATE_SENT); @@ -1712,9 +1724,9 @@ public class MmsTable extends MessageTable { if (cursor != null && cursor.moveToNext()) { return Optional.of(new MmsNotificationInfo(RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(RECIPIENT_ID))), - cursor.getString(cursor.getColumnIndexOrThrow(CONTENT_LOCATION)), - cursor.getString(cursor.getColumnIndexOrThrow(TRANSACTION_ID)), - cursor.getInt(cursor.getColumnIndexOrThrow(SUBSCRIPTION_ID)))); + cursor.getString(cursor.getColumnIndexOrThrow(MMS_CONTENT_LOCATION)), + cursor.getString(cursor.getColumnIndexOrThrow(MMS_TRANSACTION_ID)), + cursor.getInt(cursor.getColumnIndexOrThrow(SMS_SUBSCRIPTION_ID)))); } else { return Optional.empty(); } @@ -1739,17 +1751,17 @@ public class MmsTable extends MessageTable { List associatedAttachments = attachmentDatabase.getAttachmentsForMessage(messageId); List mentions = mentionDatabase.getMentionsForMessage(messageId); - long outboxType = cursor.getLong(cursor.getColumnIndexOrThrow(MESSAGE_BOX)); + long outboxType = cursor.getLong(cursor.getColumnIndexOrThrow(TYPE)); String body = cursor.getString(cursor.getColumnIndexOrThrow(BODY)); - long timestamp = cursor.getLong(cursor.getColumnIndexOrThrow(NORMALIZED_DATE_SENT)); - int subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(SUBSCRIPTION_ID)); + long timestamp = cursor.getLong(cursor.getColumnIndexOrThrow(DATE_SENT)); + int subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(SMS_SUBSCRIPTION_ID)); long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRES_IN)); boolean viewOnce = cursor.getLong(cursor.getColumnIndexOrThrow(VIEW_ONCE)) == 1; long recipientId = cursor.getLong(cursor.getColumnIndexOrThrow(RECIPIENT_ID)); long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID)); int distributionType = SignalDatabase.threads().getDistributionType(threadId); String mismatchDocument = cursor.getString(cursor.getColumnIndexOrThrow(MmsTable.MISMATCHED_IDENTITIES)); - String networkDocument = cursor.getString(cursor.getColumnIndexOrThrow(MmsTable.NETWORK_FAILURE)); + String networkDocument = cursor.getString(cursor.getColumnIndexOrThrow(MmsTable.NETWORK_FAILURES)); StoryType storyType = StoryType.fromCode(CursorUtil.requireInt(cursor, STORY_TYPE)); ParentStoryId parentStoryId = ParentStoryId.deserialize(CursorUtil.requireLong(cursor, PARENT_STORY_ID)); @@ -1942,14 +1954,13 @@ public class MmsTable extends MessageTable { contentValues.put(DATE_SERVER, retrieved.getServerTimeMillis()); contentValues.put(RECIPIENT_ID, retrieved.getFrom().serialize()); - contentValues.put(MESSAGE_BOX, mailbox); - contentValues.put(MESSAGE_TYPE, PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF); + contentValues.put(TYPE, mailbox); + contentValues.put(MMS_MESSAGE_TYPE, PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF); contentValues.put(THREAD_ID, threadId); - contentValues.put(CONTENT_LOCATION, contentLocation); - contentValues.put(STATUS, Status.DOWNLOAD_INITIALIZED); + contentValues.put(MMS_CONTENT_LOCATION, contentLocation); + contentValues.put(MMS_STATUS, Status.DOWNLOAD_INITIALIZED); contentValues.put(DATE_RECEIVED, retrieved.isPushMessage() ? retrieved.getReceivedTimeMillis() : generatePduCompatTimestamp(retrieved.getReceivedTimeMillis())); - contentValues.put(PART_COUNT, retrieved.getAttachments().size()); - contentValues.put(SUBSCRIPTION_ID, retrieved.getSubscriptionId()); + contentValues.put(SMS_SUBSCRIPTION_ID, retrieved.getSubscriptionId()); contentValues.put(EXPIRES_IN, retrieved.getExpiresIn()); contentValues.put(VIEW_ONCE, retrieved.isViewOnce() ? 1 : 0); contentValues.put(STORY_TYPE, retrieved.getStoryType().getCode()); @@ -2101,12 +2112,12 @@ public class MmsTable extends MessageTable { Log.i(TAG, "Message received type: " + notification.getMessageType()); - contentBuilder.add(CONTENT_LOCATION, notification.getContentLocation()); + contentBuilder.add(MMS_CONTENT_LOCATION, notification.getContentLocation()); contentBuilder.add(DATE_SENT, System.currentTimeMillis()); - contentBuilder.add(EXPIRY, notification.getExpiry()); - contentBuilder.add(MESSAGE_SIZE, notification.getMessageSize()); - contentBuilder.add(TRANSACTION_ID, notification.getTransactionId()); - contentBuilder.add(MESSAGE_TYPE, notification.getMessageType()); + contentBuilder.add(MMS_EXPIRY, notification.getExpiry()); + contentBuilder.add(MMS_MESSAGE_SIZE, notification.getMessageSize()); + contentBuilder.add(MMS_TRANSACTION_ID, notification.getTransactionId()); + contentBuilder.add(MMS_MESSAGE_TYPE, notification.getMessageType()); if (notification.getFrom() != null) { Recipient recipient = Recipient.external(context, Util.toIsoString(notification.getFrom().getTextString())); @@ -2115,12 +2126,12 @@ public class MmsTable extends MessageTable { contentValues.put(RECIPIENT_ID, RecipientId.UNKNOWN.serialize()); } - contentValues.put(MESSAGE_BOX, Types.BASE_INBOX_TYPE); + contentValues.put(TYPE, Types.BASE_INBOX_TYPE); contentValues.put(THREAD_ID, threadId); - contentValues.put(STATUS, Status.DOWNLOAD_INITIALIZED); + contentValues.put(MMS_STATUS, Status.DOWNLOAD_INITIALIZED); contentValues.put(DATE_RECEIVED, generatePduCompatTimestamp(System.currentTimeMillis())); contentValues.put(READ, Util.isDefaultSmsProvider(context) ? 0 : 1); - contentValues.put(SUBSCRIPTION_ID, subscriptionId); + contentValues.put(SMS_SUBSCRIPTION_ID, subscriptionId); if (!contentValues.containsKey(DATE_SENT)) contentValues.put(DATE_SENT, contentValues.getAsLong(DATE_RECEIVED)); @@ -2170,7 +2181,7 @@ public class MmsTable extends MessageTable { private void markGiftRedemptionState(long messageId, @NonNull GiftBadge.RedemptionState redemptionState) { String[] projection = SqlUtil.buildArgs(BODY, THREAD_ID); - String where = "(" + MESSAGE_BOX + " & " + Types.SPECIAL_TYPES_MASK + " = " + Types.SPECIAL_TYPE_GIFT_BADGE + ") AND " + + String where = "(" + TYPE + " & " + Types.SPECIAL_TYPES_MASK + " = " + Types.SPECIAL_TYPE_GIFT_BADGE + ") AND " + ID + " = ?"; String[] args = SqlUtil.buildArgs(messageId); boolean updated = false; @@ -2282,13 +2293,13 @@ public class MmsTable extends MessageTable { ContentValues contentValues = new ContentValues(); contentValues.put(DATE_SENT, message.getSentTimeMillis()); - contentValues.put(MESSAGE_TYPE, PduHeaders.MESSAGE_TYPE_SEND_REQ); + contentValues.put(MMS_MESSAGE_TYPE, PduHeaders.MESSAGE_TYPE_SEND_REQ); - contentValues.put(MESSAGE_BOX, type); + contentValues.put(TYPE, type); contentValues.put(THREAD_ID, threadId); contentValues.put(READ, 1); contentValues.put(DATE_RECEIVED, System.currentTimeMillis()); - contentValues.put(SUBSCRIPTION_ID, message.getSubscriptionId()); + contentValues.put(SMS_SUBSCRIPTION_ID, message.getSubscriptionId()); contentValues.put(EXPIRES_IN, message.getExpiresIn()); contentValues.put(VIEW_ONCE, message.isViewOnce()); contentValues.put(RECIPIENT_ID, message.getRecipient().getId().serialize()); @@ -2415,7 +2426,6 @@ public class MmsTable extends MessageTable { allAttachments.addAll(previewAttachments); contentValues.put(BODY, body); - contentValues.put(PART_COUNT, allAttachments.size()); contentValues.put(MENTIONS_SELF, mentionsSelf ? 1 : 0); if (messageRanges != null) { @@ -2568,9 +2578,9 @@ public class MmsTable extends MessageTable { @Override public boolean isSent(long messageId) { SQLiteDatabase database = databaseHelper.getSignalReadableDatabase(); - try (Cursor cursor = database.query(TABLE_NAME, new String[] { MESSAGE_BOX }, ID + " = ?", new String[] { String.valueOf(messageId)}, null, null, null)) { + try (Cursor cursor = database.query(TABLE_NAME, new String[] { TYPE }, ID + " = ?", new String[] { String.valueOf(messageId)}, null, null, null)) { if (cursor != null && cursor.moveToNext()) { - long type = cursor.getLong(cursor.getColumnIndexOrThrow(MESSAGE_BOX)); + long type = cursor.getLong(cursor.getColumnIndexOrThrow(TYPE)); return Types.isSentType(type); } } @@ -2585,7 +2595,7 @@ public class MmsTable extends MessageTable { @Override public Set getAllRateLimitedMessageIds() { SQLiteDatabase db = databaseHelper.getSignalReadableDatabase(); - String where = "(" + MESSAGE_BOX + " & " + Types.TOTAL_MASK + " & " + Types.MESSAGE_RATE_LIMITED_BIT + ") > 0"; + String where = "(" + TYPE + " & " + Types.TOTAL_MASK + " & " + Types.MESSAGE_RATE_LIMITED_BIT + ") > 0"; Set ids = new HashSet<>(); @@ -2851,7 +2861,6 @@ public class MmsTable extends MessageTable { 0, threadId, message.getBody(), slideDeck, - slideDeck.getSlides().size(), message.isSecure() ? MmsSmsColumns.Types.getOutgoingEncryptedMessageType() : MmsSmsColumns.Types.getOutgoingSmsMessageType(), Collections.emptySet(), Collections.emptySet(), @@ -2915,7 +2924,7 @@ public class MmsTable extends MessageTable { @Override public MessageRecord getCurrent() { - long mmsType = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.MESSAGE_TYPE)); + long mmsType = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.MMS_MESSAGE_TYPE)); if (mmsType == PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND) { return getNotificationMmsMessageRecord(cursor); @@ -2945,22 +2954,22 @@ public class MmsTable extends MessageTable { private NotificationMmsMessageRecord getNotificationMmsMessageRecord(Cursor cursor) { long id = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.ID)); - long dateSent = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.NORMALIZED_DATE_SENT)); - long dateReceived = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.NORMALIZED_DATE_RECEIVED)); + long dateSent = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.DATE_SENT)); + long dateReceived = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.DATE_RECEIVED)); long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.THREAD_ID)); - long mailbox = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.MESSAGE_BOX)); + long mailbox = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.TYPE)); long recipientId = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.RECIPIENT_ID)); - int addressDeviceId = cursor.getInt(cursor.getColumnIndexOrThrow(MmsTable.ADDRESS_DEVICE_ID)); + int addressDeviceId = cursor.getInt(cursor.getColumnIndexOrThrow(MmsTable.RECIPIENT_DEVICE_ID)); Recipient recipient = Recipient.live(RecipientId.from(recipientId)).get(); - String contentLocation = cursor.getString(cursor.getColumnIndexOrThrow(MmsTable.CONTENT_LOCATION)); - String transactionId = cursor.getString(cursor.getColumnIndexOrThrow(MmsTable.TRANSACTION_ID)); - long messageSize = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.MESSAGE_SIZE)); - long expiry = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.EXPIRY)); - int status = cursor.getInt(cursor.getColumnIndexOrThrow(MmsTable.STATUS)); + String contentLocation = cursor.getString(cursor.getColumnIndexOrThrow(MmsTable.MMS_CONTENT_LOCATION)); + String transactionId = cursor.getString(cursor.getColumnIndexOrThrow(MmsTable.MMS_TRANSACTION_ID)); + long messageSize = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.MMS_MESSAGE_SIZE)); + long expiry = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.MMS_EXPIRY)); + int status = cursor.getInt(cursor.getColumnIndexOrThrow(MmsTable.MMS_STATUS)); int deliveryReceiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(MmsTable.DELIVERY_RECEIPT_COUNT)); int readReceiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(MmsTable.READ_RECEIPT_COUNT)); - int subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(MmsTable.SUBSCRIPTION_ID)); + int subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(MmsTable.SMS_SUBSCRIPTION_ID)); int viewedReceiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(MmsSmsColumns.VIEWED_RECEIPT_COUNT)); long receiptTimestamp = CursorUtil.requireLong(cursor, MmsSmsColumns.RECEIPT_TIMESTAMP); StoryType storyType = StoryType.fromCode(CursorUtil.requireInt(cursor, STORY_TYPE)); @@ -3001,20 +3010,19 @@ public class MmsTable extends MessageTable { private MediaMmsMessageRecord getMediaMmsMessageRecord(Cursor cursor) { long id = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.ID)); - long dateSent = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.NORMALIZED_DATE_SENT)); - long dateReceived = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.NORMALIZED_DATE_RECEIVED)); + long dateSent = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.DATE_SENT)); + long dateReceived = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.DATE_RECEIVED)); long dateServer = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.DATE_SERVER)); - long box = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.MESSAGE_BOX)); + long box = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.TYPE)); long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.THREAD_ID)); long recipientId = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.RECIPIENT_ID)); - int addressDeviceId = cursor.getInt(cursor.getColumnIndexOrThrow(MmsTable.ADDRESS_DEVICE_ID)); + int addressDeviceId = cursor.getInt(cursor.getColumnIndexOrThrow(MmsTable.RECIPIENT_DEVICE_ID)); int deliveryReceiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(MmsTable.DELIVERY_RECEIPT_COUNT)); int readReceiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(MmsTable.READ_RECEIPT_COUNT)); String body = cursor.getString(cursor.getColumnIndexOrThrow(MmsTable.BODY)); - int partCount = cursor.getInt(cursor.getColumnIndexOrThrow(MmsTable.PART_COUNT)); String mismatchDocument = cursor.getString(cursor.getColumnIndexOrThrow(MmsTable.MISMATCHED_IDENTITIES)); - String networkDocument = cursor.getString(cursor.getColumnIndexOrThrow(MmsTable.NETWORK_FAILURE)); - int subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(MmsTable.SUBSCRIPTION_ID)); + String networkDocument = cursor.getString(cursor.getColumnIndexOrThrow(MmsTable.NETWORK_FAILURES)); + int subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(MmsTable.SMS_SUBSCRIPTION_ID)); long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.EXPIRES_IN)); long expireStarted = cursor.getLong(cursor.getColumnIndexOrThrow(MmsTable.EXPIRE_STARTED)); boolean unidentified = cursor.getInt(cursor.getColumnIndexOrThrow(MmsTable.UNIDENTIFIED)) == 1; @@ -3067,7 +3075,7 @@ public class MmsTable extends MessageTable { return new MediaMmsMessageRecord(id, recipient, recipient, addressDeviceId, dateSent, dateReceived, dateServer, deliveryReceiptCount, - threadId, body, slideDeck, partCount, box, mismatches, + threadId, body, slideDeck, box, mismatches, networkFailures, subscriptionId, expiresIn, expireStarted, isViewOnce, readReceiptCount, quote, contacts, previews, unidentified, Collections.emptyList(), remoteDelete, mentionsSelf, notifiedTimestamp, viewedReceiptCount, receiptTimestamp, messageRanges, diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/SearchTable.java b/app/src/main/java/org/thoughtcrime/securesms/database/SearchTable.java index 38ddf18123..b7a935f1e1 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/SearchTable.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/SearchTable.java @@ -61,9 +61,9 @@ public class SearchTable extends DatabaseTable { private static final String MESSAGES_QUERY = "SELECT " + ThreadTable.TABLE_NAME + "." + ThreadTable.RECIPIENT_ID + " AS " + CONVERSATION_RECIPIENT + ", " + - MmsSmsColumns.RECIPIENT_ID + " AS " + MESSAGE_RECIPIENT + ", " + + SmsTable.TABLE_NAME + "." + MmsSmsColumns.RECIPIENT_ID + " AS " + MESSAGE_RECIPIENT + ", " + "snippet(" + SMS_FTS_TABLE_NAME + ", -1, '', '', '" + SNIPPET_WRAP + "', 7) AS " + SNIPPET + ", " + - SmsTable.TABLE_NAME + "." + SmsTable.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED + ", " + + SmsTable.TABLE_NAME + "." + MmsSmsColumns.DATE_RECEIVED + ", " + SMS_FTS_TABLE_NAME + "." + THREAD_ID + ", " + SMS_FTS_TABLE_NAME + "." + BODY + ", " + SMS_FTS_TABLE_NAME + "." + ID + " AS " + MESSAGE_ID + ", " + @@ -78,9 +78,9 @@ public class SearchTable extends DatabaseTable { "UNION ALL " + "SELECT " + ThreadTable.TABLE_NAME + "." + ThreadTable.RECIPIENT_ID + " AS " + CONVERSATION_RECIPIENT + ", " + - MmsSmsColumns.RECIPIENT_ID + " AS " + MESSAGE_RECIPIENT + ", " + + MmsTable.TABLE_NAME + "." + MmsSmsColumns.RECIPIENT_ID + " AS " + MESSAGE_RECIPIENT + ", " + "snippet(" + MMS_FTS_TABLE_NAME + ", -1, '', '', '" + SNIPPET_WRAP + "', 7) AS " + SNIPPET + ", " + - MmsTable.TABLE_NAME + "." + MmsTable.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED + ", " + + MmsTable.TABLE_NAME + "." + MmsSmsColumns.DATE_RECEIVED + ", " + MMS_FTS_TABLE_NAME + "." + THREAD_ID + ", " + MMS_FTS_TABLE_NAME + "." + BODY + ", " + MMS_FTS_TABLE_NAME + "." + ID + " AS " + MESSAGE_ID + ", " + @@ -89,17 +89,17 @@ public class SearchTable extends DatabaseTable { "INNER JOIN " + MMS_FTS_TABLE_NAME + " ON " + MMS_FTS_TABLE_NAME + "." + ID + " = " + MmsTable.TABLE_NAME + "." + MmsTable.ID + " " + "INNER JOIN " + ThreadTable.TABLE_NAME + " ON " + MMS_FTS_TABLE_NAME + "." + THREAD_ID + " = " + ThreadTable.TABLE_NAME + "." + ThreadTable.ID + " " + "WHERE " + MMS_FTS_TABLE_NAME + " MATCH ? " + - "AND " + MmsTable.TABLE_NAME + "." + MmsTable.MESSAGE_BOX + " & " + MmsSmsColumns.Types.GROUP_V2_BIT + " = 0 " + - "AND " + MmsTable.TABLE_NAME + "." + MmsTable.MESSAGE_BOX + " & " + MmsSmsColumns.Types.SPECIAL_TYPE_PAYMENTS_NOTIFICATION + " = 0 " + - "ORDER BY " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC " + + "AND " + MmsTable.TABLE_NAME + "." + MmsTable.TYPE + " & " + MmsSmsColumns.Types.GROUP_V2_BIT + " = 0 " + + "AND " + MmsTable.TABLE_NAME + "." + MmsTable.TYPE + " & " + MmsSmsColumns.Types.SPECIAL_TYPE_PAYMENTS_NOTIFICATION + " = 0 " + + "ORDER BY " + MmsSmsColumns.DATE_RECEIVED + " DESC " + "LIMIT 500"; private static final String MESSAGES_FOR_THREAD_QUERY = "SELECT " + ThreadTable.TABLE_NAME + "." + ThreadTable.RECIPIENT_ID + " AS " + CONVERSATION_RECIPIENT + ", " + - MmsSmsColumns.RECIPIENT_ID + " AS " + MESSAGE_RECIPIENT + ", " + + SmsTable.TABLE_NAME + "." + MmsSmsColumns.RECIPIENT_ID + " AS " + MESSAGE_RECIPIENT + ", " + "snippet(" + SMS_FTS_TABLE_NAME + ", -1, '', '', '" + SNIPPET_WRAP + "', 7) AS " + SNIPPET + ", " + - SmsTable.TABLE_NAME + "." + SmsTable.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED + ", " + + SmsTable.TABLE_NAME + "." + MmsSmsColumns.DATE_RECEIVED + ", " + SMS_FTS_TABLE_NAME + "." + THREAD_ID + ", " + SMS_FTS_TABLE_NAME + "." + BODY + ", " + SMS_FTS_TABLE_NAME + "." + ID + " AS " + MESSAGE_ID + ", " + @@ -111,9 +111,9 @@ public class SearchTable extends DatabaseTable { "UNION ALL " + "SELECT " + ThreadTable.TABLE_NAME + "." + ThreadTable.RECIPIENT_ID + " AS " + CONVERSATION_RECIPIENT + ", " + - MmsSmsColumns.RECIPIENT_ID + " AS " + MESSAGE_RECIPIENT + ", " + + MmsTable.TABLE_NAME + "." + MmsSmsColumns.RECIPIENT_ID + " AS " + MESSAGE_RECIPIENT + ", " + "snippet(" + MMS_FTS_TABLE_NAME + ", -1, '', '', '" + SNIPPET_WRAP + "', 7) AS " + SNIPPET + ", " + - MmsTable.TABLE_NAME + "." + MmsTable.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED + ", " + + MmsTable.TABLE_NAME + "." + MmsSmsColumns.DATE_RECEIVED + ", " + MMS_FTS_TABLE_NAME + "." + THREAD_ID + ", " + MMS_FTS_TABLE_NAME + "." + BODY + ", " + MMS_FTS_TABLE_NAME + "." + ID + " AS " + MESSAGE_ID + ", " + @@ -122,7 +122,7 @@ public class SearchTable extends DatabaseTable { "INNER JOIN " + MMS_FTS_TABLE_NAME + " ON " + MMS_FTS_TABLE_NAME + "." + ID + " = " + MmsTable.TABLE_NAME + "." + MmsTable.ID + " " + "INNER JOIN " + ThreadTable.TABLE_NAME + " ON " + MMS_FTS_TABLE_NAME + "." + THREAD_ID + " = " + ThreadTable.TABLE_NAME + "." + ThreadTable.ID + " " + "WHERE " + MMS_FTS_TABLE_NAME + " MATCH ? AND " + MmsTable.TABLE_NAME + "." + MmsSmsColumns.THREAD_ID + " = ? " + - "ORDER BY " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC " + + "ORDER BY " + MmsSmsColumns.DATE_RECEIVED + " DESC " + "LIMIT 500"; public SearchTable(@NonNull Context context, @NonNull SignalDatabase databaseHelper) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/SignalDatabase.kt b/app/src/main/java/org/thoughtcrime/securesms/database/SignalDatabase.kt index d492d57bb7..a62f0a4383 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/SignalDatabase.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/SignalDatabase.kt @@ -156,15 +156,25 @@ open class SignalDatabase(private val context: Application, databaseSecret: Data } override fun onUpgrade(db: net.zetetic.database.sqlcipher.SQLiteDatabase, oldVersion: Int, newVersion: Int) { + // The caller of onUpgrade starts a transaction, which prevents us from turning off foreign keys. + // At this point it hasn't done anything, so we can just end it and then start it again ourselves. + db.endTransaction() + Log.i(TAG, "Upgrading database: $oldVersion, $newVersion") val startTime = System.currentTimeMillis() + db.setForeignKeyConstraintsEnabled(false) db.beginTransaction() try { migrate(context, db, oldVersion, newVersion) db.setTransactionSuccessful() } finally { db.endTransaction() + db.setForeignKeyConstraintsEnabled(true) + + // We have to re-begin the transaction for the calling code (see comment at start of method) + db.beginTransaction() } + migratePostTransaction(context, oldVersion) Log.i(TAG, "Upgrade complete. Took " + (System.currentTimeMillis() - startTime) + " ms.") } diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/SmsMigrator.java b/app/src/main/java/org/thoughtcrime/securesms/database/SmsMigrator.java deleted file mode 100644 index 4f77ed2190..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/database/SmsMigrator.java +++ /dev/null @@ -1,288 +0,0 @@ -/* - * Copyright (C) 2011 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 . - */ -package org.thoughtcrime.securesms.database; - -import android.content.Context; -import android.database.Cursor; -import android.database.sqlite.SQLiteException; -import android.net.Uri; - -import androidx.annotation.Nullable; - -import com.annimon.stream.Stream; - -import net.zetetic.database.sqlcipher.SQLiteStatement; - -import org.signal.core.util.logging.Log; -import org.thoughtcrime.securesms.groups.GroupId; -import org.thoughtcrime.securesms.recipients.Recipient; -import org.thoughtcrime.securesms.recipients.RecipientId; - -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.StringTokenizer; - -public class SmsMigrator { - - private static final String TAG = Log.tag(SmsMigrator.class); - - private static class SystemColumns { - private static final String ADDRESS = "address"; - private static final String PERSON = "person"; - private static final String DATE_RECEIVED = "date"; - private static final String PROTOCOL = "protocol"; - private static final String READ = "read"; - private static final String STATUS = "status"; - private static final String TYPE = "type"; - private static final String SUBJECT = "subject"; - private static final String REPLY_PATH_PRESENT = "reply_path_present"; - private static final String BODY = "body"; - private static final String SERVICE_CENTER = "service_center"; - } - - private static void addStringToStatement(SQLiteStatement statement, Cursor cursor, - int index, String key) - { - int columnIndex = cursor.getColumnIndexOrThrow(key); - - if (cursor.isNull(columnIndex)) { - statement.bindNull(index); - } else { - statement.bindString(index, cursor.getString(columnIndex)); - } - } - - private static void addIntToStatement(SQLiteStatement statement, Cursor cursor, - int index, String key) - { - int columnIndex = cursor.getColumnIndexOrThrow(key); - - if (cursor.isNull(columnIndex)) { - statement.bindNull(index); - } else { - statement.bindLong(index, cursor.getLong(columnIndex)); - } - } - - @SuppressWarnings("SameParameterValue") - private static void addTranslatedTypeToStatement(SQLiteStatement statement, Cursor cursor, int index, String key) - { - int columnIndex = cursor.getColumnIndexOrThrow(key); - - if (cursor.isNull(columnIndex)) { - statement.bindLong(index, SmsTable.Types.BASE_INBOX_TYPE); - } else { - long theirType = cursor.getLong(columnIndex); - statement.bindLong(index, SmsTable.Types.translateFromSystemBaseType(theirType)); - } - } - - private static boolean isAppropriateTypeForMigration(Cursor cursor, int columnIndex) { - long systemType = cursor.getLong(columnIndex); - long ourType = SmsTable.Types.translateFromSystemBaseType(systemType); - - return ourType == MmsSmsColumns.Types.BASE_INBOX_TYPE || - ourType == MmsSmsColumns.Types.BASE_SENT_TYPE || - ourType == MmsSmsColumns.Types.BASE_SENT_FAILED_TYPE; - } - - private static void getContentValuesForRow(Context context, Cursor cursor, long threadId, SQLiteStatement statement) { - String address = cursor.getString(cursor.getColumnIndexOrThrow(SystemColumns.ADDRESS)); - RecipientId id = Recipient.external(context, address).getId(); - - statement.bindString(1, id.serialize()); - addIntToStatement(statement, cursor, 2, SystemColumns.PERSON); - addIntToStatement(statement, cursor, 3, SystemColumns.DATE_RECEIVED); - addIntToStatement(statement, cursor, 4, SystemColumns.DATE_RECEIVED); - addIntToStatement(statement, cursor, 5, SystemColumns.PROTOCOL); - addIntToStatement(statement, cursor, 6, SystemColumns.READ); - addIntToStatement(statement, cursor, 7, SystemColumns.STATUS); - addTranslatedTypeToStatement(statement, cursor, 8, SystemColumns.TYPE); - addIntToStatement(statement, cursor, 9, SystemColumns.REPLY_PATH_PRESENT); - addStringToStatement(statement, cursor, 10, SystemColumns.SUBJECT); - addStringToStatement(statement, cursor, 11, SystemColumns.BODY); - addStringToStatement(statement, cursor, 12, SystemColumns.SERVICE_CENTER); - - statement.bindLong(13, threadId); - } - - private static String getTheirCanonicalAddress(Context context, String theirRecipientId) { - Uri uri = Uri.parse("content://mms-sms/canonical-address/" + theirRecipientId); - Cursor cursor = null; - - try { - cursor = context.getContentResolver().query(uri, null, null, null, null); - - if (cursor != null && cursor.moveToFirst()) { - return cursor.getString(0); - } else { - return null; - } - } catch (IllegalStateException iae) { - Log.w(TAG, iae); - return null; - } finally { - if (cursor != null) - cursor.close(); - } - } - - private static @Nullable Set getOurRecipients(Context context, String theirRecipients) { - StringTokenizer tokenizer = new StringTokenizer(theirRecipients.trim(), " "); - Set recipientList = new HashSet<>(); - - while (tokenizer.hasMoreTokens()) { - String theirRecipientId = tokenizer.nextToken(); - String address = getTheirCanonicalAddress(context, theirRecipientId); - - if (address != null) { - recipientList.add(Recipient.external(context, address)); - } - } - - if (recipientList.isEmpty()) return null; - else return recipientList; - } - - private static void migrateConversation(Context context, SmsMigrationProgressListener listener, - ProgressDescription progress, - long theirThreadId, long ourThreadId) - { - MessageTable ourSmsDatabase = SignalDatabase.sms(); - Cursor cursor = null; - SQLiteStatement statement = null; - - try { - Uri uri = Uri.parse("content://sms/conversations/" + theirThreadId); - - try { - cursor = context.getContentResolver().query(uri, null, null, null, null); - } catch (SQLiteException e) { - /// Work around for weird sony-specific (?) bug: #4309 - Log.w(TAG, e); - return; - } - - SQLiteDatabase transaction = ourSmsDatabase.beginTransaction(); - statement = ourSmsDatabase.createInsertStatement(transaction); - - while (cursor != null && cursor.moveToNext()) { - int addressColumn = cursor.getColumnIndexOrThrow(SystemColumns.ADDRESS); - int typeColumn = cursor.getColumnIndex(SmsTable.TYPE); - - if (!cursor.isNull(addressColumn) && (cursor.isNull(typeColumn) || isAppropriateTypeForMigration(cursor, typeColumn))) { - getContentValuesForRow(context, cursor, ourThreadId, statement); - statement.execute(); - } - - listener.progressUpdate(new ProgressDescription(progress, cursor.getCount(), cursor.getPosition())); - } - - ourSmsDatabase.endTransaction(transaction); - SignalDatabase.threads().update(ourThreadId, true); - SignalDatabase.threads().setLastScrolled(ourThreadId, 0); - SignalDatabase.threads().notifyConversationListeners(ourThreadId); - - } finally { - if (statement != null) - statement.close(); - if (cursor != null) - cursor.close(); - } - } - - public static void migrateDatabase(Context context, SmsMigrationProgressListener listener) - { -// if (context.getSharedPreferences("SecureSMS", Context.MODE_PRIVATE).getBoolean("migrated", false)) -// return; - - ThreadTable threadTable = SignalDatabase.threads(); - Cursor cursor = null; - - try { - Uri threadListUri = Uri.parse("content://mms-sms/conversations?simple=true"); - cursor = context.getContentResolver().query(threadListUri, null, null, null, "date ASC"); - - while (cursor != null && cursor.moveToNext()) { - long theirThreadId = cursor.getLong(cursor.getColumnIndexOrThrow("_id")); - String theirRecipients = cursor.getString(cursor.getColumnIndexOrThrow("recipient_ids")); - Set ourRecipients = getOurRecipients(context, theirRecipients); - ProgressDescription progress = new ProgressDescription(cursor.getCount(), cursor.getPosition(), 100, 0); - - if (ourRecipients != null) { - if (ourRecipients.size() == 1) { - long ourThreadId = threadTable.getOrCreateThreadIdFor(ourRecipients.iterator().next()); - migrateConversation(context, listener, progress, theirThreadId, ourThreadId); - } else if (ourRecipients.size() > 1) { - ourRecipients.add(Recipient.self()); - - List recipientIds = Stream.of(ourRecipients).map(Recipient::getId).toList(); - - GroupId.Mms ourGroupId = SignalDatabase.groups().getOrCreateMmsGroupForMembers(recipientIds); - RecipientId ourGroupRecipientId = SignalDatabase.recipients().getOrInsertFromGroupId(ourGroupId); - Recipient ourGroupRecipient = Recipient.resolved(ourGroupRecipientId); - long ourThreadId = threadTable.getOrCreateThreadIdFor(ourGroupRecipient, ThreadTable.DistributionTypes.CONVERSATION); - - migrateConversation(context, listener, progress, theirThreadId, ourThreadId); - } - } - - progress.incrementPrimaryComplete(); - listener.progressUpdate(progress); - } - } finally { - if (cursor != null) - cursor.close(); - } - - context.getSharedPreferences("SecureSMS", Context.MODE_PRIVATE).edit() - .putBoolean("migrated", true).apply(); - } - - public interface SmsMigrationProgressListener { - void progressUpdate(ProgressDescription description); - } - - public static class ProgressDescription { - public final int primaryTotal; - public int primaryComplete; - public final int secondaryTotal; - public final int secondaryComplete; - - ProgressDescription(int primaryTotal, int primaryComplete, - int secondaryTotal, int secondaryComplete) - { - this.primaryTotal = primaryTotal; - this.primaryComplete = primaryComplete; - this.secondaryTotal = secondaryTotal; - this.secondaryComplete = secondaryComplete; - } - - ProgressDescription(ProgressDescription that, int secondaryTotal, int secondaryComplete) { - this.primaryComplete = that.primaryComplete; - this.primaryTotal = that.primaryTotal; - this.secondaryComplete = secondaryComplete; - this.secondaryTotal = secondaryTotal; - } - - void incrementPrimaryComplete() { - primaryComplete += 1; - } - } - -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/SmsTable.java b/app/src/main/java/org/thoughtcrime/securesms/database/SmsTable.java index 3b01621970..42dc2fd039 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/SmsTable.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/SmsTable.java @@ -31,8 +31,6 @@ import com.google.android.mms.pdu_alt.NotificationInd; import com.google.protobuf.ByteString; import com.google.protobuf.InvalidProtocolBufferException; -import net.zetetic.database.sqlcipher.SQLiteStatement; - import org.signal.core.util.CursorExtensionsKt; import org.signal.core.util.CursorUtil; import org.signal.core.util.SQLiteDatabaseExtensionsKt; @@ -100,36 +98,23 @@ public class SmsTable extends MessageTable { private static final String TAG = Log.tag(SmsTable.class); - public static final String TABLE_NAME = "sms"; - public static final String PERSON = "person"; - static final String DATE_RECEIVED = "date"; - static final String DATE_SENT = "date_sent"; - public static final String PROTOCOL = "protocol"; - public static final String STATUS = "status"; - public static final String TYPE = "type"; - public static final String REPLY_PATH_PRESENT = "reply_path_present"; - public static final String SUBJECT = "subject"; - public static final String SERVICE_CENTER = "service_center"; + public static final String TABLE_NAME = "sms"; + public static final String SMS_STATUS = "status"; public static final String CREATE_TABLE = "CREATE TABLE " + TABLE_NAME + " (" + ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " + - THREAD_ID + " INTEGER, " + - RECIPIENT_ID + " INTEGER, " + - ADDRESS_DEVICE_ID + " INTEGER DEFAULT 1, " + - PERSON + " INTEGER, " + - DATE_RECEIVED + " INTEGER, " + - DATE_SENT + " INTEGER, " + + DATE_SENT + " INTEGER NOT NULL, " + + DATE_RECEIVED + " INTEGER NOT NULL, " + DATE_SERVER + " INTEGER DEFAULT -1, " + - PROTOCOL + " INTEGER, " + - READ + " INTEGER DEFAULT 0, " + - STATUS + " INTEGER DEFAULT -1," + + THREAD_ID + " INTEGER NOT NULL REFERENCES " + ThreadTable.TABLE_NAME + " (" + ThreadTable.ID + ") ON DELETE CASCADE, " + + RECIPIENT_ID + " INTEGER NOT NULL REFERENCES " + RecipientTable.TABLE_NAME + " (" + RecipientTable.ID + ") ON DELETE CASCADE, " + + RECIPIENT_DEVICE_ID + " INTEGER DEFAULT 1, " + TYPE + " INTEGER, " + - REPLY_PATH_PRESENT + " INTEGER, " + - DELIVERY_RECEIPT_COUNT + " INTEGER DEFAULT 0," + - SUBJECT + " TEXT, " + BODY + " TEXT, " + + READ + " INTEGER DEFAULT 0, " + + SMS_STATUS + " INTEGER DEFAULT -1," + + DELIVERY_RECEIPT_COUNT + " INTEGER DEFAULT 0," + MISMATCHED_IDENTITIES + " TEXT DEFAULT NULL, " + - SERVICE_CENTER + " TEXT, " + - SUBSCRIPTION_ID + " INTEGER DEFAULT -1, " + + SMS_SUBSCRIPTION_ID + " INTEGER DEFAULT -1, " + EXPIRES_IN + " INTEGER DEFAULT 0, " + EXPIRE_STARTED + " INTEGER DEFAULT 0, " + NOTIFIED + " DEFAULT 0, " + @@ -155,15 +140,30 @@ public class SmsTable extends MessageTable { }; private static final String[] MESSAGE_PROJECTION = new String[] { - ID, THREAD_ID, RECIPIENT_ID, ADDRESS_DEVICE_ID, PERSON, - DATE_RECEIVED + " AS " + NORMALIZED_DATE_RECEIVED, - DATE_SENT + " AS " + NORMALIZED_DATE_SENT, + ID, + THREAD_ID, + RECIPIENT_ID, + RECIPIENT_DEVICE_ID, + DATE_RECEIVED, + DATE_SENT, DATE_SERVER, - PROTOCOL, READ, STATUS, TYPE, - REPLY_PATH_PRESENT, SUBJECT, BODY, SERVICE_CENTER, DELIVERY_RECEIPT_COUNT, - MISMATCHED_IDENTITIES, SUBSCRIPTION_ID, EXPIRES_IN, EXPIRE_STARTED, - NOTIFIED, READ_RECEIPT_COUNT, UNIDENTIFIED, REACTIONS_UNREAD, REACTIONS_LAST_SEEN, - REMOTE_DELETED, NOTIFIED_TIMESTAMP, RECEIPT_TIMESTAMP + READ, + SMS_STATUS, + TYPE, + BODY, + DELIVERY_RECEIPT_COUNT, + MISMATCHED_IDENTITIES, + SMS_SUBSCRIPTION_ID, + EXPIRES_IN, + EXPIRE_STARTED, + NOTIFIED, + READ_RECEIPT_COUNT, + UNIDENTIFIED, + REACTIONS_UNREAD, + REACTIONS_LAST_SEEN, + REMOTE_DELETED, + NOTIFIED_TIMESTAMP, + RECEIPT_TIMESTAMP }; @VisibleForTesting @@ -489,7 +489,7 @@ public class SmsTable extends MessageTable { public void markSmsStatus(long id, int status) { Log.i(TAG, "Updating ID: " + id + " to status: " + status); ContentValues contentValues = new ContentValues(); - contentValues.put(STATUS, status); + contentValues.put(SMS_STATUS, status); SQLiteDatabase db = databaseHelper.getSignalWritableDatabase(); db.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {id+""}); @@ -731,7 +731,7 @@ public class SmsTable extends MessageTable { ContentValues values = new ContentValues(); values.put(RECIPIENT_ID, sender.serialize()); - values.put(ADDRESS_DEVICE_ID, 1); + values.put(RECIPIENT_DEVICE_ID, 1); values.put(DATE_RECEIVED, timestamp); values.put(DATE_SENT, timestamp); values.put(READ, markRead ? 1 : 0); @@ -808,7 +808,7 @@ public class SmsTable extends MessageTable { ContentValues values = new ContentValues(); values.put(RECIPIENT_ID, sender.serialize()); - values.put(ADDRESS_DEVICE_ID, 1); + values.put(RECIPIENT_DEVICE_ID, 1); values.put(DATE_RECEIVED, timestamp); values.put(DATE_SENT, timestamp); values.put(READ, 0); @@ -880,7 +880,7 @@ public class SmsTable extends MessageTable { ContentValues values = new ContentValues(6); values.put(RECIPIENT_ID, recipientId.serialize()); - values.put(ADDRESS_DEVICE_ID, 1); + values.put(RECIPIENT_DEVICE_ID, 1); values.put(DATE_RECEIVED, System.currentTimeMillis()); values.put(DATE_SENT, timestamp); values.put(READ, unread ? 0 : 1); @@ -1008,7 +1008,7 @@ public class SmsTable extends MessageTable { .forEach(threadId -> { ContentValues values = new ContentValues(); values.put(RECIPIENT_ID, recipient.getId().serialize()); - values.put(ADDRESS_DEVICE_ID, 1); + values.put(RECIPIENT_DEVICE_ID, 1); values.put(DATE_RECEIVED, System.currentTimeMillis()); values.put(DATE_SENT, System.currentTimeMillis()); values.put(READ, 1); @@ -1056,7 +1056,7 @@ public class SmsTable extends MessageTable { { ContentValues values = new ContentValues(); values.put(RECIPIENT_ID, recipientId.serialize()); - values.put(ADDRESS_DEVICE_ID, 1); + values.put(RECIPIENT_DEVICE_ID, 1); values.put(DATE_RECEIVED, System.currentTimeMillis()); values.put(DATE_SENT, System.currentTimeMillis()); values.put(READ, 1); @@ -1092,7 +1092,7 @@ public class SmsTable extends MessageTable { .forEach(threadId -> { ContentValues values = new ContentValues(); values.put(RECIPIENT_ID, recipientId.serialize()); - values.put(ADDRESS_DEVICE_ID, 1); + values.put(RECIPIENT_DEVICE_ID, 1); values.put(DATE_RECEIVED, System.currentTimeMillis()); values.put(DATE_SENT, System.currentTimeMillis()); values.put(READ, 1); @@ -1121,7 +1121,7 @@ public class SmsTable extends MessageTable { public void insertBoostRequestMessage(@NonNull RecipientId recipientId, long threadId) { ContentValues values = new ContentValues(); values.put(RECIPIENT_ID, recipientId.serialize()); - values.put(ADDRESS_DEVICE_ID, 1); + values.put(RECIPIENT_DEVICE_ID, 1); values.put(DATE_RECEIVED, System.currentTimeMillis()); values.put(DATE_SENT, System.currentTimeMillis()); values.put(READ, 1); @@ -1136,7 +1136,7 @@ public class SmsTable extends MessageTable { public void insertThreadMergeEvent(@NonNull RecipientId recipientId, long threadId, @NonNull ThreadMergeEvent event) { ContentValues values = new ContentValues(); values.put(RECIPIENT_ID, recipientId.serialize()); - values.put(ADDRESS_DEVICE_ID, 1); + values.put(RECIPIENT_DEVICE_ID, 1); values.put(DATE_RECEIVED, System.currentTimeMillis()); values.put(DATE_SENT, System.currentTimeMillis()); values.put(READ, 1); @@ -1153,7 +1153,7 @@ public class SmsTable extends MessageTable { public void insertSmsExportMessage(@NonNull RecipientId recipientId, long threadId) { ContentValues values = new ContentValues(); values.put(RECIPIENT_ID, recipientId.serialize()); - values.put(ADDRESS_DEVICE_ID, 1); + values.put(RECIPIENT_DEVICE_ID, 1); values.put(DATE_RECEIVED, System.currentTimeMillis()); values.put(DATE_SENT, System.currentTimeMillis()); values.put(READ, 1); @@ -1251,21 +1251,14 @@ public class SmsTable extends MessageTable { ContentValues values = new ContentValues(); values.put(RECIPIENT_ID, message.getSender().serialize()); - values.put(ADDRESS_DEVICE_ID, message.getSenderDeviceId()); + values.put(RECIPIENT_DEVICE_ID, message.getSenderDeviceId()); values.put(DATE_RECEIVED, message.getReceivedTimestampMillis()); values.put(DATE_SENT, message.getSentTimestampMillis()); values.put(DATE_SERVER, message.getServerTimestampMillis()); - values.put(PROTOCOL, message.getProtocol()); values.put(READ, unread ? 0 : 1); - values.put(SUBSCRIPTION_ID, message.getSubscriptionId()); + values.put(SMS_SUBSCRIPTION_ID, message.getSubscriptionId()); values.put(EXPIRES_IN, message.getExpiresIn()); values.put(UNIDENTIFIED, message.isUnidentified()); - - if (!TextUtils.isEmpty(message.getPseudoSubject())) - values.put(SUBJECT, message.getPseudoSubject()); - - values.put(REPLY_PATH_PRESENT, message.isReplyPathPresent()); - values.put(SERVICE_CENTER, message.getServiceCenterAddress()); values.put(BODY, message.getMessageBody()); values.put(TYPE, type); values.put(THREAD_ID, threadId); @@ -1316,7 +1309,7 @@ public class SmsTable extends MessageTable { ContentValues values = new ContentValues(); values.put(RECIPIENT_ID, recipientId.serialize()); - values.put(ADDRESS_DEVICE_ID, senderDeviceId); + values.put(RECIPIENT_DEVICE_ID, senderDeviceId); values.put(DATE_RECEIVED, System.currentTimeMillis()); values.put(DATE_SENT, sentTimestamp); values.put(DATE_SERVER, -1); @@ -1341,7 +1334,7 @@ public class SmsTable extends MessageTable { public void insertBadDecryptMessage(@NonNull RecipientId recipientId, int senderDevice, long sentTimestamp, long receivedTimestamp, long threadId) { ContentValues values = new ContentValues(); values.put(RECIPIENT_ID, recipientId.serialize()); - values.put(ADDRESS_DEVICE_ID, senderDevice); + values.put(RECIPIENT_DEVICE_ID, senderDevice); values.put(DATE_SENT, sentTimestamp); values.put(DATE_RECEIVED, receivedTimestamp); values.put(DATE_SERVER, -1); @@ -1387,7 +1380,7 @@ public class SmsTable extends MessageTable { contentValues.put(DATE_SENT, date); contentValues.put(READ, 1); contentValues.put(TYPE, type); - contentValues.put(SUBSCRIPTION_ID, message.getSubscriptionId()); + contentValues.put(SMS_SUBSCRIPTION_ID, message.getSubscriptionId()); contentValues.put(EXPIRES_IN, message.getExpiresIn()); contentValues.put(DELIVERY_RECEIPT_COUNT, Stream.of(earlyDeliveryReceipts.values()).mapToLong(EarlyReceiptCache.Receipt::getCount).sum()); contentValues.put(RECEIPT_TIMESTAMP, Stream.of(earlyDeliveryReceipts.values()).mapToLong(EarlyReceiptCache.Receipt::getTimestamp).max().orElse(-1)); @@ -1732,24 +1725,6 @@ public class SmsTable extends MessageTable { databaseHelper.getSignalWritableDatabase().endTransaction(); } - @Override - public SQLiteStatement createInsertStatement(SQLiteDatabase database) { - return database.compileStatement("INSERT INTO " + TABLE_NAME + " (" + RECIPIENT_ID + ", " + - PERSON + ", " + - DATE_SENT + ", " + - DATE_RECEIVED + ", " + - PROTOCOL + ", " + - READ + ", " + - STATUS + ", " + - TYPE + ", " + - REPLY_PATH_PRESENT + ", " + - SUBJECT + ", " + - BODY + ", " + - SERVICE_CENTER + - ", " + THREAD_ID + ") " + - " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); - } - @Override public @Nullable ViewOnceExpirationInfo getNearestExpiringViewOnceMessage() { throw new UnsupportedOperationException(); @@ -1948,17 +1923,17 @@ public class SmsTable extends MessageTable { public SmsMessageRecord getCurrent() { long messageId = cursor.getLong(cursor.getColumnIndexOrThrow(SmsTable.ID)); long recipientId = cursor.getLong(cursor.getColumnIndexOrThrow(SmsTable.RECIPIENT_ID)); - int addressDeviceId = cursor.getInt(cursor.getColumnIndexOrThrow(SmsTable.ADDRESS_DEVICE_ID)); + int addressDeviceId = cursor.getInt(cursor.getColumnIndexOrThrow(SmsTable.RECIPIENT_DEVICE_ID)); long type = cursor.getLong(cursor.getColumnIndexOrThrow(SmsTable.TYPE)); - long dateReceived = cursor.getLong(cursor.getColumnIndexOrThrow(SmsTable.NORMALIZED_DATE_RECEIVED)); - long dateSent = cursor.getLong(cursor.getColumnIndexOrThrow(SmsTable.NORMALIZED_DATE_SENT)); + long dateReceived = cursor.getLong(cursor.getColumnIndexOrThrow(SmsTable.DATE_RECEIVED)); + long dateSent = cursor.getLong(cursor.getColumnIndexOrThrow(SmsTable.DATE_SENT)); long dateServer = cursor.getLong(cursor.getColumnIndexOrThrow(SmsTable.DATE_SERVER)); long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(SmsTable.THREAD_ID)); - int status = cursor.getInt(cursor.getColumnIndexOrThrow(SmsTable.STATUS)); + int status = cursor.getInt(cursor.getColumnIndexOrThrow(SmsTable.SMS_STATUS)); int deliveryReceiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(SmsTable.DELIVERY_RECEIPT_COUNT)); int readReceiptCount = cursor.getInt(cursor.getColumnIndexOrThrow(SmsTable.READ_RECEIPT_COUNT)); String mismatchDocument = cursor.getString(cursor.getColumnIndexOrThrow(SmsTable.MISMATCHED_IDENTITIES)); - int subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(SmsTable.SUBSCRIPTION_ID)); + int subscriptionId = cursor.getInt(cursor.getColumnIndexOrThrow(SmsTable.SMS_SUBSCRIPTION_ID)); long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(SmsTable.EXPIRES_IN)); long expireStarted = cursor.getLong(cursor.getColumnIndexOrThrow(SmsTable.EXPIRE_STARTED)); String body = cursor.getString(cursor.getColumnIndexOrThrow(SmsTable.BODY)); diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/StorySendTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/StorySendTable.kt index f87bd4768e..9315a5e347 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/StorySendTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/StorySendTable.kt @@ -326,7 +326,7 @@ class StorySendTable(context: Context, databaseHelper: SignalDatabase) : Databas // language=sql """ SELECT - $RECIPIENT_ID, + $TABLE_NAME.$RECIPIENT_ID, $ALLOWS_REPLIES, $DISTRIBUTION_ID, ${MmsTable.REMOTE_DELETED} diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/ThreadTable.kt b/app/src/main/java/org/thoughtcrime/securesms/database/ThreadTable.kt index 155841f05e..866bbb8e38 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/ThreadTable.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/ThreadTable.kt @@ -76,14 +76,13 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa const val TABLE_NAME = "thread" const val ID = "_id" const val DATE = "date" - const val MEANINGFUL_MESSAGES = "message_count" - const val RECIPIENT_ID = "thread_recipient_id" - const val SNIPPET = "snippet" - const val SNIPPET_CHARSET = "snippet_charset" + const val MEANINGFUL_MESSAGES = "meaningful_messages" + const val RECIPIENT_ID = "recipient_id" const val READ = "read" const val UNREAD_COUNT = "unread_count" const val TYPE = "type" const val ERROR = "error" + const val SNIPPET = "snippet" const val SNIPPET_TYPE = "snippet_type" const val SNIPPET_URI = "snippet_uri" const val SNIPPET_CONTENT_TYPE = "snippet_content_type" @@ -106,11 +105,10 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa $DATE INTEGER DEFAULT 0, $MEANINGFUL_MESSAGES INTEGER DEFAULT 0, $RECIPIENT_ID INTEGER, - $SNIPPET TEXT, - $SNIPPET_CHARSET INTEGER DEFAULT 0, $READ INTEGER DEFAULT ${ReadStatus.READ.serialize()}, $TYPE INTEGER DEFAULT 0, $ERROR INTEGER DEFAULT 0, + $SNIPPET TEXT, $SNIPPET_TYPE INTEGER DEFAULT 0, $SNIPPET_URI TEXT DEFAULT NULL, $SNIPPET_CONTENT_TYPE TEXT DEFAULT NULL, @@ -143,7 +141,6 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa MEANINGFUL_MESSAGES, RECIPIENT_ID, SNIPPET, - SNIPPET_CHARSET, READ, UNREAD_COUNT, TYPE, @@ -343,7 +340,7 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa mmsSms.getConversation(threadId).use { cursor -> if (cursor.count > length) { cursor.moveToPosition(length - 1) - max(trimBeforeDate, cursor.requireLong(MmsSmsColumns.NORMALIZED_DATE_RECEIVED)) + max(trimBeforeDate, cursor.requireLong(MmsSmsColumns.DATE_RECEIVED)) } else { trimBeforeDate } @@ -702,14 +699,14 @@ class ThreadTable(context: Context, databaseHelper: SignalDatabase) : DatabaseTa } if (hideSelf) { - where += " AND $RECIPIENT_ID != ${Recipient.self().id.toLong()}" + where += " AND $TABLE_NAME.$RECIPIENT_ID != ${Recipient.self().id.toLong()}" } where += " AND $ARCHIVED = 0" where += " AND ${RecipientTable.TABLE_NAME}.${RecipientTable.BLOCKED} = 0" if (SignalStore.releaseChannelValues().releaseChannelRecipientId != null) { - where += " AND $RECIPIENT_ID != ${SignalStore.releaseChannelValues().releaseChannelRecipientId!!.toLong()}" + where += " AND $TABLE_NAME.$RECIPIENT_ID != ${SignalStore.releaseChannelValues().releaseChannelRecipientId!!.toLong()}" } val query = createQuery( diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt index 3c52395e84..664850d107 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/SignalDatabaseMigrations.kt @@ -21,6 +21,7 @@ import org.thoughtcrime.securesms.database.helpers.migration.V162_ThreadUnreadSe import org.thoughtcrime.securesms.database.helpers.migration.V163_RemoteMegaphoneSnoozeSupportMigration import org.thoughtcrime.securesms.database.helpers.migration.V164_ThreadDatabaseReadIndexMigration import org.thoughtcrime.securesms.database.helpers.migration.V165_MmsMessageBoxPaymentTransactionIndexMigration +import org.thoughtcrime.securesms.database.helpers.migration.V166_ThreadAndMessageForeignKeys /** * Contains all of the database migrations for [SignalDatabase]. Broken into a separate file for cleanliness. @@ -29,7 +30,7 @@ object SignalDatabaseMigrations { val TAG: String = Log.tag(SignalDatabaseMigrations.javaClass) - const val DATABASE_VERSION = 165 + const val DATABASE_VERSION = 166 @JvmStatic fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { @@ -100,6 +101,10 @@ object SignalDatabaseMigrations { if (oldVersion < 165) { V165_MmsMessageBoxPaymentTransactionIndexMigration.migrate(context, db, oldVersion, newVersion) } + + if (oldVersion < 166) { + V166_ThreadAndMessageForeignKeys.migrate(context, db, oldVersion, newVersion) + } } @JvmStatic diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V166_ThreadAndMessageForeignKeys.kt b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V166_ThreadAndMessageForeignKeys.kt new file mode 100644 index 0000000000..f4782ae7c4 --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/database/helpers/migration/V166_ThreadAndMessageForeignKeys.kt @@ -0,0 +1,424 @@ +package org.thoughtcrime.securesms.database.helpers.migration + +import android.app.Application +import net.zetetic.database.sqlcipher.SQLiteDatabase +import org.signal.core.util.Stopwatch +import org.signal.core.util.delete +import org.signal.core.util.logging.Log +import org.signal.core.util.readToList +import org.signal.core.util.requireLong +import org.signal.core.util.update + +/** + * This one's a doozy. We want to add additional foreign key constraints between the thread, recipient, and message tables. This will let us know for sure + * that there aren't threads with invalid recipients, or messages with invalid threads, or multiple threads for the same recipient. + */ +object V166_ThreadAndMessageForeignKeys : SignalDatabaseMigration { + + private val TAG = Log.tag(V166_ThreadAndMessageForeignKeys::class.java) + + override fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { + val stopwatch = Stopwatch("migration") + + removeDuplicateThreadEntries(db) + stopwatch.split("thread-dupes") + + updateThreadTableSchema(db) + stopwatch.split("thread-schema") + + fixDanglingSmsMessages(db) + stopwatch.split("sms-dangling") + + fixDanglingMmsMessages(db) + stopwatch.split("mms-dangling") + + updateSmsTableSchema(db) + stopwatch.split("sms-schema") + + updateMmsTableSchema(db) + stopwatch.split("mms-schema") + + stopwatch.stop(TAG) + } + + private fun removeDuplicateThreadEntries(db: SQLiteDatabase) { + db.rawQuery( + """ + SELECT + thread_recipient_id, + COUNT(*) AS thread_count + FROM thread + GROUP BY thread_recipient_id HAVING thread_count > 1 + """.trimMargin() + ).use { cursor -> + while (cursor.moveToNext()) { + val recipientId = cursor.requireLong("thread_recipient_id") + val count = cursor.requireLong("thread_count") + Log.w(TAG, "There were $count threads for RecipientId::$recipientId. Merging.") + + val threads: List = getThreadsByRecipientId(db, cursor.requireLong("thread_recipient_id")) + mergeThreads(db, threads) + } + } + } + + private fun getThreadsByRecipientId(db: SQLiteDatabase, recipientId: Long): List { + return db.rawQuery("SELECT _id, date FROM thread WHERE thread_recipient_id = ?".trimIndent(), recipientId).readToList { cursor -> + ThreadInfo(cursor.requireLong("_id"), cursor.requireLong("date")) + } + } + + private fun mergeThreads(db: SQLiteDatabase, threads: List) { + val primaryThread: ThreadInfo = threads.maxByOrNull { it.date }!! + val secondaryThreads: List = threads.filterNot { it.id == primaryThread.id } + + secondaryThreads.forEach { secondaryThread -> + remapThread(db, primaryThread.id, secondaryThread.id) + } + } + + private fun remapThread(db: SQLiteDatabase, primaryId: Long, secondaryId: Long) { + db.update("drafts") + .values("thread_id" to primaryId) + .where("thread_id = ?", secondaryId) + .run() + + db.update("mention") + .values("thread_id" to primaryId) + .where("thread_id = ?", secondaryId) + .run() + + db.update("mms") + .values("thread_id" to primaryId) + .where("thread_id = ?", secondaryId) + .run() + + db.update("sms") + .values("thread_id" to primaryId) + .where("thread_id = ?", secondaryId) + .run() + + db.update("pending_retry_receipts") + .values("thread_id" to primaryId) + .where("thread_id = ?", secondaryId) + .run() + + db.delete("thread") + .where("_id = ?", secondaryId) + .run() + } + + private fun updateThreadTableSchema(db: SQLiteDatabase) { + db.execSQL( + """ + CREATE TABLE thread_tmp ( + _id INTEGER PRIMARY KEY AUTOINCREMENT, + date INTEGER DEFAULT 0, + meaningful_messages INTEGER DEFAULT 0, + recipient_id INTEGER NOT NULL UNIQUE REFERENCES recipient (_id) ON DELETE CASCADE, + read INTEGER DEFAULT 1, + type INTEGER DEFAULT 0, + error INTEGER DEFAULT 0, + snippet TEXT, + snippet_type INTEGER DEFAULT 0, + snippet_uri TEXT DEFAULT NULL, + snippet_content_type TEXT DEFAULT NULL, + snippet_extras TEXT DEFAULT NULL, + unread_count INTEGER DEFAULT 0, + archived INTEGER DEFAULT 0, + status INTEGER DEFAULT 0, + delivery_receipt_count INTEGER DEFAULT 0, + read_receipt_count INTEGER DEFAULT 0, + expires_in INTEGER DEFAULT 0, + last_seen INTEGER DEFAULT 0, + has_sent INTEGER DEFAULT 0, + last_scrolled INTEGER DEFAULT 0, + pinned INTEGER DEFAULT 0, + unread_self_mention_count INTEGER DEFAULT 0 + ) + """.trimIndent() + ) + + db.execSQL( + """ + INSERT INTO thread_tmp + SELECT + _id, + date, + message_count, + thread_recipient_id, + read, + type, + error, + snippet, + snippet_type, + snippet_uri, + snippet_content_type, + snippet_extras, + unread_count, + archived, + status, + delivery_receipt_count, + read_receipt_count, + expires_in, + last_seen, + has_sent, + last_scrolled, + pinned, + unread_self_mention_count + FROM thread + """.trimMargin() + ) + + db.execSQL("DROP TABLE thread") + db.execSQL("ALTER TABLE thread_tmp RENAME TO thread") + + db.execSQL("CREATE INDEX thread_recipient_id_index ON thread (recipient_id)") + db.execSQL("CREATE INDEX archived_count_index ON thread (archived, meaningful_messages)") + db.execSQL("CREATE INDEX thread_pinned_index ON thread (pinned)") + db.execSQL("CREATE INDEX thread_read ON thread (read)") + } + + private fun fixDanglingSmsMessages(db: SQLiteDatabase) { + db.delete("sms") + .where("address NOT IN (SELECT _id FROM recipient)") + .run() + + // Can't even attempt to "fix" these because without the threadId we don't know if it's a 1:1 or group message + db.delete("sms") + .where("thread_id NOT IN (SELECT _id FROM thread)") + .run() + } + + private fun fixDanglingMmsMessages(db: SQLiteDatabase) { + db.delete("mms") + .where("address NOT IN (SELECT _id FROM recipient)") + .run() + + // Can't even attempt to "fix" these because without the threadId we don't know if it's a 1:1 or group message + db.delete("mms") + .where("thread_id NOT IN (SELECT _id FROM thread)") + .run() + } + + private fun updateSmsTableSchema(db: SQLiteDatabase) { + db.execSQL( + """ + CREATE TABLE sms_tmp ( + _id INTEGER PRIMARY KEY AUTOINCREMENT, + date_sent INTEGER NOT NULL, + date_received INTEGER NOT NULL, + date_server INTEGER DEFAULT -1, + thread_id INTEGER NOT NULL REFERENCES thread (_id) ON DELETE CASCADE, + recipient_id NOT NULL REFERENCES recipient (_id) ON DELETE CASCADE, + recipient_device_id INTEGER DEFAULT 1, + type INTEGER, + body TEXT, + read INTEGER DEFAULT 0, + status INTEGER DEFAULT -1, + delivery_receipt_count INTEGER DEFAULT 0, + mismatched_identities TEXT DEFAULT NULL, + subscription_id INTEGER DEFAULT -1, + expires_in INTEGER DEFAULT 0, + expire_started INTEGER DEFAULT 0, + notified INTEGER DEFAULT 0, + read_receipt_count INTEGER DEFAULT 0, + unidentified INTEGER DEFAULT 0, + reactions_unread INTEGER DEFAULT 0, + reactions_last_seen INTEGER DEFAULT -1, + remote_deleted INTEGER DEFAULT 0, + notified_timestamp INTEGER DEFAULT 0, + server_guid TEXT DEFAULT NULL, + receipt_timestamp INTEGER DEFAULT -1, + export_state BLOB DEFAULT NULL, + exported INTEGER DEFAULT 0 + ) + """.trimIndent() + ) + + db.execSQL( + """ + INSERT INTO sms_tmp + SELECT + _id, + date_sent, + date, + date_server, + thread_id, + address, + address_device_id, + type, + body, + read, + status, + delivery_receipt_count, + mismatched_identities, + subscription_id, + expires_in, + expire_started, + notified, + read_receipt_count, + unidentified, + reactions_unread, + reactions_last_seen, + remote_deleted, + notified_timestamp, + server_guid, + receipt_timestamp, + export_state, + exported + FROM sms + """.trimIndent() + ) + + db.execSQL("DROP TABLE sms") + db.execSQL("ALTER TABLE sms_tmp RENAME TO sms") + + db.execSQL("CREATE INDEX sms_read_and_notified_and_thread_id_index ON sms(read, notified, thread_id)") + db.execSQL("CREATE INDEX sms_type_index ON sms (type)") + db.execSQL("CREATE INDEX sms_date_sent_index ON sms (date_sent, recipient_id, thread_id)") + db.execSQL("CREATE INDEX sms_date_server_index ON sms (date_server)") + db.execSQL("CREATE INDEX sms_thread_date_index ON sms (thread_id, date_received)") + db.execSQL("CREATE INDEX sms_reactions_unread_index ON sms (reactions_unread)") + db.execSQL("CREATE INDEX sms_exported_index ON sms (exported)") + + db.execSQL("CREATE TRIGGER sms_ai AFTER INSERT ON sms BEGIN INSERT INTO sms_fts(rowid, body, thread_id) VALUES (new._id, new.body, new.thread_id); END;") + db.execSQL("CREATE TRIGGER sms_ad AFTER DELETE ON sms BEGIN INSERT INTO sms_fts(sms_fts, rowid, body, thread_id) VALUES('delete', old._id, old.body, old.thread_id); END;") + db.execSQL("CREATE TRIGGER sms_au AFTER UPDATE ON sms BEGIN INSERT INTO sms_fts(sms_fts, rowid, body, thread_id) VALUES('delete', old._id, old.body, old.thread_id); INSERT INTO sms_fts(rowid, body, thread_id) VALUES(new._id, new.body, new.thread_id); END;") + db.execSQL("CREATE TRIGGER msl_sms_delete AFTER DELETE ON sms BEGIN DELETE FROM msl_payload WHERE _id IN (SELECT payload_id FROM msl_message WHERE message_id = old._id AND is_mms = 0); END") + } + + private fun updateMmsTableSchema(db: SQLiteDatabase) { + db.execSQL( + """ + CREATE TABLE mms_tmp ( + _id INTEGER PRIMARY KEY AUTOINCREMENT, + date_sent INTEGER NOT NULL, + date_received INTEGER NOT NULL, + date_server INTEGER DEFAULT -1, + thread_id INTEGER NOT NULL REFERENCES thread (_id) ON DELETE CASCADE, + recipient_id INTEGER NOT NULL REFERENCES recipient (_id) ON DELETE CASCADE, + recipient_device_id INTEGER, + type INTEGER NOT NULL, + body TEXT, + read INTEGER DEFAULT 0, + ct_l TEXT, + exp INTEGER, + m_type INTEGER, + m_size INTEGER, + st INTEGER, + tr_id TEXT, + subscription_id INTEGER DEFAULT -1, + receipt_timestamp INTEGER DEFAULT -1, + delivery_receipt_count INTEGER DEFAULT 0, + read_receipt_count INTEGER DEFAULT 0, + viewed_receipt_count INTEGER DEFAULT 0, + mismatched_identities TEXT DEFAULT NULL, + network_failures TEXT DEFAULT NULL, + expires_in INTEGER DEFAULT 0, + expire_started INTEGER DEFAULT 0, + notified INTEGER DEFAULT 0, + quote_id INTEGER DEFAULT 0, + quote_author INTEGER DEFAULT 0, + quote_body TEXT DEFAULT NULL, + quote_missing INTEGER DEFAULT 0, + quote_mentions BLOB DEFAULT NULL, + quote_type INTEGER DEFAULT 0, + shared_contacts TEXT DEFAULT NULL, + unidentified INTEGER DEFAULT 0, + link_previews TEXT DEFAULT NULL, + view_once INTEGER DEFAULT 0, + reactions_unread INTEGER DEFAULT 0, + reactions_last_seen INTEGER DEFAULT -1, + remote_deleted INTEGER DEFAULT 0, + mentions_self INTEGER DEFAULT 0, + notified_timestamp INTEGER DEFAULT 0, + server_guid TEXT DEFAULT NULL, + message_ranges BLOB DEFAULT NULL, + story_type INTEGER DEFAULT 0, + parent_story_id INTEGER DEFAULT 0, + export_state BLOB DEFAULT NULL, + exported INTEGER DEFAULT 0 + ) + """.trimIndent() + ) + + db.execSQL( + """ + INSERT INTO mms_tmp + SELECT + _id, + date, + date_received, + date_server, + thread_id, + address, + address_device_id, + msg_box, + body, + read, + ct_l, + exp, + m_type, + m_size, + st, + tr_id, + subscription_id, + receipt_timestamp, + delivery_receipt_count, + read_receipt_count, + viewed_receipt_count, + mismatched_identities, + network_failures, + expires_in, + expire_started, + notified, + quote_id, + quote_author, + quote_body, + quote_missing, + quote_mentions, + quote_type, + shared_contacts, + unidentified, + previews, + reveal_duration, + reactions_unread, + reactions_last_seen, + remote_deleted, + mentions_self, + notified_timestamp, + server_guid, + ranges, + is_story, + parent_story_id, + export_state, + exported + FROM mms + """.trimIndent() + ) + + db.execSQL("DROP TABLE mms") + db.execSQL("ALTER TABLE mms_tmp RENAME TO mms") + + db.execSQL("CREATE INDEX mms_read_and_notified_and_thread_id_index ON mms(read, notified, thread_id)") + db.execSQL("CREATE INDEX mms_type_index ON mms (type)") + db.execSQL("CREATE INDEX mms_date_sent_index ON mms (date_sent, recipient_id, thread_id)") + db.execSQL("CREATE INDEX mms_date_server_index ON mms (date_server)") + db.execSQL("CREATE INDEX mms_thread_date_index ON mms (thread_id, date_received)") + db.execSQL("CREATE INDEX mms_reactions_unread_index ON mms (reactions_unread)") + db.execSQL("CREATE INDEX IF NOT EXISTS mms_story_type_index ON mms (story_type)") + db.execSQL("CREATE INDEX IF NOT EXISTS mms_parent_story_id_index ON mms (parent_story_id)") + db.execSQL("CREATE INDEX IF NOT EXISTS mms_thread_story_parent_story_index ON mms (thread_id, date_received, story_type, parent_story_id)") + db.execSQL("CREATE INDEX IF NOT EXISTS mms_quote_id_quote_author_index ON mms (quote_id, quote_author)") + db.execSQL("CREATE INDEX IF NOT EXISTS mms_exported_index ON mms (exported)") + db.execSQL("CREATE INDEX IF NOT EXISTS mms_id_type_payment_transactions_index ON mms (_id, type) WHERE type & ${0x300000000L} != 0") + + db.execSQL("CREATE TRIGGER mms_ai AFTER INSERT ON mms BEGIN INSERT INTO mms_fts(rowid, body, thread_id) VALUES (new._id, new.body, new.thread_id); END") + db.execSQL("CREATE TRIGGER mms_ad AFTER DELETE ON mms BEGIN INSERT INTO mms_fts(mms_fts, rowid, body, thread_id) VALUES('delete', old._id, old.body, old.thread_id); END") + db.execSQL("CREATE TRIGGER mms_au AFTER UPDATE ON mms BEGIN INSERT INTO mms_fts(mms_fts, rowid, body, thread_id) VALUES('delete', old._id, old.body, old.thread_id); INSERT INTO mms_fts(rowid, body, thread_id) VALUES (new._id, new.body, new.thread_id); END") + db.execSQL("CREATE TRIGGER msl_mms_delete AFTER DELETE ON mms BEGIN DELETE FROM msl_payload WHERE _id IN (SELECT payload_id FROM msl_message WHERE message_id = old._id AND is_mms = 1); END") + } + + data class ThreadInfo(val id: Long, val date: Long) +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/database/model/MediaMmsMessageRecord.java b/app/src/main/java/org/thoughtcrime/securesms/database/model/MediaMmsMessageRecord.java index 7bc00039f2..4d49357963 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/database/model/MediaMmsMessageRecord.java +++ b/app/src/main/java/org/thoughtcrime/securesms/database/model/MediaMmsMessageRecord.java @@ -60,7 +60,6 @@ import java.util.stream.Collectors; public class MediaMmsMessageRecord extends MmsMessageRecord { private final static String TAG = Log.tag(MediaMmsMessageRecord.class); - private final int partCount; private final boolean mentionsSelf; private final BodyRangeList messageRanges; private final Payment payment; @@ -76,7 +75,6 @@ public class MediaMmsMessageRecord extends MmsMessageRecord { long threadId, String body, @NonNull SlideDeck slideDeck, - int partCount, long mailbox, Set mismatches, Set failures, @@ -106,7 +104,6 @@ public class MediaMmsMessageRecord extends MmsMessageRecord { subscriptionId, expiresIn, expireStarted, viewOnce, slideDeck, readReceiptCount, quote, contacts, linkPreviews, unidentified, reactions, remoteDelete, notifiedTimestamp, viewedReceiptCount, receiptTimestamp, storyType, parentStoryId, giftBadge); - this.partCount = partCount; this.mentionsSelf = mentionsSelf; this.messageRanges = messageRanges; this.payment = payment; @@ -140,10 +137,6 @@ public class MediaMmsMessageRecord extends MmsMessageRecord { return super.getDisplayBody(context); } - public int getPartCount() { - return partCount; - } - public @Nullable BodyRangeList getMessageRanges() { return messageRanges; } @@ -164,14 +157,14 @@ public class MediaMmsMessageRecord extends MmsMessageRecord { public @NonNull MediaMmsMessageRecord withReactions(@NonNull List reactions) { return new MediaMmsMessageRecord(getId(), getRecipient(), getIndividualRecipient(), getRecipientDeviceId(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), getThreadId(), getBody(), getSlideDeck(), - getPartCount(), getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(), + getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(), getReadReceiptCount(), getQuote(), getSharedContacts(), getLinkPreviews(), isUnidentified(), reactions, isRemoteDelete(), mentionsSelf, getNotifiedTimestamp(), getViewedReceiptCount(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), getPayment()); } public @NonNull MediaMmsMessageRecord withoutQuote() { return new MediaMmsMessageRecord(getId(), getRecipient(), getIndividualRecipient(), getRecipientDeviceId(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), getThreadId(), getBody(), getSlideDeck(), - getPartCount(), getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(), + getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(), getReadReceiptCount(), null, getSharedContacts(), getLinkPreviews(), isUnidentified(), getReactions(), isRemoteDelete(), mentionsSelf, getNotifiedTimestamp(), getViewedReceiptCount(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), getPayment()); } @@ -192,14 +185,14 @@ public class MediaMmsMessageRecord extends MmsMessageRecord { SlideDeck slideDeck = MmsTable.Reader.buildSlideDeck(context, slideAttachments); return new MediaMmsMessageRecord(getId(), getRecipient(), getIndividualRecipient(), getRecipientDeviceId(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), getThreadId(), getBody(), slideDeck, - getPartCount(), getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(), + getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(), getReadReceiptCount(), quote, contacts, linkPreviews, isUnidentified(), getReactions(), isRemoteDelete(), mentionsSelf, getNotifiedTimestamp(), getViewedReceiptCount(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), getPayment()); } public @NonNull MediaMmsMessageRecord withPayment(@NonNull Payment payment) { return new MediaMmsMessageRecord(getId(), getRecipient(), getIndividualRecipient(), getRecipientDeviceId(), getDateSent(), getDateReceived(), getServerTimestamp(), getDeliveryReceiptCount(), getThreadId(), getBody(), getSlideDeck(), - getPartCount(), getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(), + getType(), getIdentityKeyMismatches(), getNetworkFailures(), getSubscriptionId(), getExpiresIn(), getExpireStarted(), isViewOnce(), getReadReceiptCount(), getQuote(), getSharedContacts(), getLinkPreviews(), isUnidentified(), getReactions(), isRemoteDelete(), mentionsSelf, getNotifiedTimestamp(), getViewedReceiptCount(), getReceiptTimestamp(), getMessageRanges(), getStoryType(), getParentStoryId(), getGiftBadge(), payment); } diff --git a/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplicationMigrations.java b/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplicationMigrations.java index 3c9bff36e3..db03de0ea8 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplicationMigrations.java +++ b/app/src/main/java/org/thoughtcrime/securesms/migrations/ApplicationMigrations.java @@ -111,9 +111,10 @@ public class ApplicationMigrations { static final int SYSTEM_NAME_SYNC = 67; static final int STORY_VIEWED_STATE = 68; static final int STORY_READ_STATE = 69; + static final int THREAD_MESSAGE_SCHEMA_CHANGE = 70; } - public static final int CURRENT_VERSION = 69; + public static final int CURRENT_VERSION = 70; /** * This *must* be called after the {@link JobManager} has been instantiated, but *before* the call @@ -491,6 +492,10 @@ public class ApplicationMigrations { jobs.put(Version.STORY_READ_STATE, new StoryReadStateMigrationJob()); } + if (lastSeenVersion < Version.THREAD_MESSAGE_SCHEMA_CHANGE) { + jobs.put(Version.THREAD_MESSAGE_SCHEMA_CHANGE, new DatabaseMigrationJob()); + } + return jobs; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/search/SearchRepository.java b/app/src/main/java/org/thoughtcrime/securesms/search/SearchRepository.java index c39eeea6d7..8224cadd38 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/search/SearchRepository.java +++ b/app/src/main/java/org/thoughtcrime/securesms/search/SearchRepository.java @@ -451,7 +451,7 @@ public class SearchRepository { Recipient messageRecipient = Recipient.live(messageRecipientId).get(); String body = CursorUtil.requireString(cursor, SearchTable.BODY); String bodySnippet = CursorUtil.requireString(cursor, SearchTable.SNIPPET); - long receivedMs = CursorUtil.requireLong(cursor, MmsSmsColumns.NORMALIZED_DATE_RECEIVED); + long receivedMs = CursorUtil.requireLong(cursor, MmsSmsColumns.DATE_RECEIVED); long threadId = CursorUtil.requireLong(cursor, MmsSmsColumns.THREAD_ID); int messageId = CursorUtil.requireInt(cursor, SearchTable.MESSAGE_ID); boolean isMms = CursorUtil.requireInt(cursor, SearchTable.IS_MMS) == 1; diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/ApplicationMigrationService.java b/app/src/main/java/org/thoughtcrime/securesms/service/ApplicationMigrationService.java deleted file mode 100644 index 180382d630..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/service/ApplicationMigrationService.java +++ /dev/null @@ -1,226 +0,0 @@ -package org.thoughtcrime.securesms.service; - -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.app.Service; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.graphics.BitmapFactory; -import android.os.Binder; -import android.os.Handler; -import android.os.IBinder; -import android.os.PowerManager; -import android.os.PowerManager.WakeLock; - -import androidx.core.app.NotificationCompat; - -import org.signal.core.util.PendingIntentFlags; -import org.signal.core.util.logging.Log; -import org.thoughtcrime.securesms.MainActivity; -import org.thoughtcrime.securesms.R; -import org.thoughtcrime.securesms.database.SmsMigrator; -import org.thoughtcrime.securesms.database.SmsMigrator.ProgressDescription; -import org.thoughtcrime.securesms.notifications.NotificationChannels; -import org.thoughtcrime.securesms.notifications.NotificationIds; - -import java.lang.ref.WeakReference; -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; - -// FIXME: This class is nuts. -public class ApplicationMigrationService extends Service - implements SmsMigrator.SmsMigrationProgressListener -{ - private static final String TAG = Log.tag(ApplicationMigrationService.class); - public static final String MIGRATE_DATABASE = "org.thoughtcrime.securesms.ApplicationMigration.MIGRATE_DATABSE"; - public static final String COMPLETED_ACTION = "org.thoughtcrime.securesms.ApplicationMigrationService.COMPLETED"; - private static final String PREFERENCES_NAME = "SecureSMS"; - private static final String DATABASE_MIGRATED = "migrated"; - - private final BroadcastReceiver completedReceiver = new CompletedReceiver(); - private final Binder binder = new ApplicationMigrationBinder(); - private final Executor executor = Executors.newSingleThreadExecutor(); - - private WeakReference handler = null; - private NotificationCompat.Builder notification = null; - private ImportState state = new ImportState(ImportState.STATE_IDLE, null); - - @Override - public void onCreate() { - registerCompletedReceiver(); - } - - @Override - public int onStartCommand(Intent intent, int flags, int startId) { - if (intent == null) return START_NOT_STICKY; - - if (intent.getAction() != null && intent.getAction().equals(MIGRATE_DATABASE)) { - executor.execute(new ImportRunnable()); - } - - return START_NOT_STICKY; - } - - @Override - public void onDestroy() { - unregisterCompletedReceiver(); - } - - @Override - public IBinder onBind(Intent intent) { - return binder; - } - - public void setImportStateHandler(Handler handler) { - this.handler = new WeakReference<>(handler); - } - - private void registerCompletedReceiver() { - IntentFilter filter = new IntentFilter(); - filter.addAction(COMPLETED_ACTION); - - registerReceiver(completedReceiver, filter); - } - - private void unregisterCompletedReceiver() { - unregisterReceiver(completedReceiver); - } - - private void notifyImportComplete() { - Intent intent = new Intent(); - intent.setAction(COMPLETED_ACTION); - - sendOrderedBroadcast(intent, null); - } - - @Override - public void progressUpdate(ProgressDescription progress) { - setState(new ImportState(ImportState.STATE_MIGRATING_IN_PROGRESS, progress)); - } - - public ImportState getState() { - return state; - } - - private void setState(ImportState state) { - this.state = state; - - if (this.handler != null) { - Handler handler = this.handler.get(); - - if (handler != null) { - handler.obtainMessage(state.state, state.progress).sendToTarget(); - } - } - - if (state.progress != null && state.progress.secondaryComplete == 0) { - updateBackgroundNotification(state.progress.primaryTotal, state.progress.primaryComplete); - } - } - - private void updateBackgroundNotification(int total, int complete) { - notification.setProgress(total, complete, false); - - ((NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE)) - .notify(NotificationIds.APPLICATION_MIGRATION, notification.build()); - } - - private NotificationCompat.Builder initializeBackgroundNotification() { - NotificationCompat.Builder builder = new NotificationCompat.Builder(this, NotificationChannels.OTHER); - - builder.setSmallIcon(R.drawable.ic_notification); - builder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.ic_notification)); - builder.setContentTitle(getString(R.string.ApplicationMigrationService_importing_text_messages)); - builder.setContentText(getString(R.string.ApplicationMigrationService_import_in_progress)); - builder.setOngoing(true); - builder.setProgress(100, 0, false); - // TODO [greyson] Navigation - builder.setContentIntent(PendingIntent.getActivity(this, 0, MainActivity.clearTop(this), PendingIntentFlags.mutable())); - - stopForeground(true); - startForeground(NotificationIds.APPLICATION_MIGRATION, builder.build()); - - return builder; - } - - private class ImportRunnable implements Runnable { - - ImportRunnable() {} - - @Override - public void run() { - notification = initializeBackgroundNotification(); - PowerManager powerManager = (PowerManager)getSystemService(Context.POWER_SERVICE); - WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "signal:migration"); - - try { - wakeLock.acquire(); - - setState(new ImportState(ImportState.STATE_MIGRATING_BEGIN, null)); - - SmsMigrator.migrateDatabase(ApplicationMigrationService.this, - ApplicationMigrationService.this); - - setState(new ImportState(ImportState.STATE_MIGRATING_COMPLETE, null)); - - setDatabaseImported(ApplicationMigrationService.this); - stopForeground(true); - notifyImportComplete(); - stopSelf(); - } finally { - wakeLock.release(); - } - } - } - - public class ApplicationMigrationBinder extends Binder { - public ApplicationMigrationService getService() { - return ApplicationMigrationService.this; - } - } - - private static class CompletedReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - NotificationCompat.Builder builder = new NotificationCompat.Builder(context, NotificationChannels.OTHER); - builder.setSmallIcon(R.drawable.ic_notification); - builder.setContentTitle(context.getString(R.string.ApplicationMigrationService_import_complete)); - builder.setContentText(context.getString(R.string.ApplicationMigrationService_system_database_import_is_complete)); - // TODO [greyson] Navigation - builder.setContentIntent(PendingIntent.getActivity(context, 0, MainActivity.clearTop(context), PendingIntentFlags.mutable())); - builder.setWhen(System.currentTimeMillis()); - builder.setDefaults(Notification.DEFAULT_VIBRATE); - builder.setAutoCancel(true); - - Notification notification = builder.build(); - ((NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE)).notify(NotificationIds.SMS_IMPORT_COMPLETE, notification); - } - } - - public static class ImportState { - public static final int STATE_IDLE = 0; - public static final int STATE_MIGRATING_BEGIN = 1; - public static final int STATE_MIGRATING_IN_PROGRESS = 2; - public static final int STATE_MIGRATING_COMPLETE = 3; - - public int state; - public ProgressDescription progress; - - public ImportState(int state, ProgressDescription progress) { - this.state = state; - this.progress = progress; - } - } - - public static boolean isDatabaseImported(Context context) { - return context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE) - .getBoolean(DATABASE_MIGRATED, false); - } - - public static void setDatabaseImported(Context context) { - context.getSharedPreferences(PREFERENCES_NAME, 0).edit().putBoolean(DATABASE_MIGRATED, true).apply(); - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/MmsListener.java b/app/src/main/java/org/thoughtcrime/securesms/service/MmsListener.java index 3746233ae0..96d8f64ba7 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/MmsListener.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/MmsListener.java @@ -31,10 +31,6 @@ public class MmsListener extends BroadcastReceiver { private static final String TAG = Log.tag(MmsListener.class); private boolean isRelevant(Context context, Intent intent) { - if (!ApplicationMigrationService.isDatabaseImported(context)) { - return false; - } - if (Telephony.Sms.Intents.WAP_PUSH_RECEIVED_ACTION.equals(intent.getAction()) && Util.isDefaultSmsProvider(context)) { return false; } diff --git a/app/src/main/java/org/thoughtcrime/securesms/service/SmsListener.java b/app/src/main/java/org/thoughtcrime/securesms/service/SmsListener.java index 19b579287d..93ac1121ea 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/service/SmsListener.java +++ b/app/src/main/java/org/thoughtcrime/securesms/service/SmsListener.java @@ -86,9 +86,6 @@ public class SmsListener extends BroadcastReceiver { if (isExemption(message, messageBody)) return false; - if (!ApplicationMigrationService.isDatabaseImported(context)) - return false; - if (SMS_RECEIVED_ACTION.equals(intent.getAction()) && Util.isDefaultSmsProvider(context)) { return false; } diff --git a/app/src/spinner/java/org/thoughtcrime/securesms/database/GV2UpdateTransformer.kt b/app/src/spinner/java/org/thoughtcrime/securesms/database/GV2UpdateTransformer.kt index 9becc0e1fa..29d27a4333 100644 --- a/app/src/spinner/java/org/thoughtcrime/securesms/database/GV2UpdateTransformer.kt +++ b/app/src/spinner/java/org/thoughtcrime/securesms/database/GV2UpdateTransformer.kt @@ -39,8 +39,7 @@ object GV2UpdateTransformer : ColumnTransformer { private fun Cursor.getMessageType(): Long { return when { - getColumnIndex(SmsTable.TYPE) != -1 -> requireLong(SmsTable.TYPE) - getColumnIndex(MmsTable.MESSAGE_BOX) != -1 -> requireLong(MmsTable.MESSAGE_BOX) + getColumnIndex(MmsSmsColumns.TYPE) != -1 -> requireLong(MmsSmsColumns.TYPE) else -> -1 } } diff --git a/app/src/test/java/org/thoughtcrime/securesms/database/FakeMessageRecords.kt b/app/src/test/java/org/thoughtcrime/securesms/database/FakeMessageRecords.kt index fbf2deb202..73a5332171 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/database/FakeMessageRecords.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/database/FakeMessageRecords.kt @@ -151,7 +151,6 @@ object FakeMessageRecords { threadId, body, slideDeck, - partCount, mailbox, mismatches, failures, diff --git a/app/src/test/java/org/thoughtcrime/securesms/database/TestMms.kt b/app/src/test/java/org/thoughtcrime/securesms/database/TestMms.kt index 68d11c061f..ca34c31208 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/database/TestMms.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/database/TestMms.kt @@ -77,13 +77,13 @@ object TestMms { ): Long { val contentValues = ContentValues().apply { put(MmsTable.DATE_SENT, message.sentTimeMillis) - put(MmsTable.MESSAGE_TYPE, PduHeaders.MESSAGE_TYPE_SEND_REQ) + put(MmsTable.MMS_MESSAGE_TYPE, PduHeaders.MESSAGE_TYPE_SEND_REQ) - put(MmsTable.MESSAGE_BOX, type) + put(MmsTable.TYPE, type) put(MmsSmsColumns.THREAD_ID, threadId) put(MmsSmsColumns.READ, if (unread) 0 else 1) put(MmsTable.DATE_RECEIVED, receivedTimestampMillis) - put(MmsSmsColumns.SUBSCRIPTION_ID, message.subscriptionId) + put(MmsSmsColumns.SMS_SUBSCRIPTION_ID, message.subscriptionId) put(MmsSmsColumns.EXPIRES_IN, message.expiresIn) put(MmsTable.VIEW_ONCE, message.isViewOnce) put(MmsSmsColumns.RECIPIENT_ID, recipientId.serialize()) @@ -93,7 +93,6 @@ object TestMms { put(MmsTable.STORY_TYPE, message.storyType.code) put(MmsSmsColumns.BODY, body) - put(MmsTable.PART_COUNT, 0) put(MmsTable.MENTIONS_SELF, 0) } @@ -106,7 +105,6 @@ object TestMms { values.putNull(MmsSmsColumns.BODY) values.putNull(MmsTable.QUOTE_BODY) values.putNull(MmsTable.QUOTE_AUTHOR) - values.putNull(MmsTable.QUOTE_ATTACHMENT) values.put(MmsTable.QUOTE_TYPE, -1) values.putNull(MmsTable.QUOTE_ID) values.putNull(MmsTable.LINK_PREVIEWS) diff --git a/app/src/test/java/org/thoughtcrime/securesms/database/TestSms.kt b/app/src/test/java/org/thoughtcrime/securesms/database/TestSms.kt index fa0a470f8c..566d42befc 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/database/TestSms.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/database/TestSms.kt @@ -1,7 +1,6 @@ package org.thoughtcrime.securesms.database import android.content.ContentValues -import android.text.TextUtils import org.thoughtcrime.securesms.groups.GroupId import org.thoughtcrime.securesms.recipients.RecipientId import org.thoughtcrime.securesms.sms.IncomingTextMessage @@ -61,22 +60,14 @@ object TestSms { ): Long { val values = ContentValues().apply { put(MmsSmsColumns.RECIPIENT_ID, message.sender.serialize()) - put(MmsSmsColumns.ADDRESS_DEVICE_ID, message.senderDeviceId) + put(MmsSmsColumns.RECIPIENT_DEVICE_ID, message.senderDeviceId) put(SmsTable.DATE_RECEIVED, message.receivedTimestampMillis) put(SmsTable.DATE_SENT, message.sentTimestampMillis) put(MmsSmsColumns.DATE_SERVER, message.serverTimestampMillis) - put(SmsTable.PROTOCOL, message.protocol) put(MmsSmsColumns.READ, if (unread) 0 else 1) - put(MmsSmsColumns.SUBSCRIPTION_ID, message.subscriptionId) + put(MmsSmsColumns.SMS_SUBSCRIPTION_ID, message.subscriptionId) put(MmsSmsColumns.EXPIRES_IN, message.expiresIn) put(MmsSmsColumns.UNIDENTIFIED, message.isUnidentified) - - if (!TextUtils.isEmpty(message.pseudoSubject)) { - put(SmsTable.SUBJECT, message.pseudoSubject) - } - - put(SmsTable.REPLY_PATH_PRESENT, message.isReplyPathPresent) - put(SmsTable.SERVICE_CENTER, message.serviceCenterAddress) put(MmsSmsColumns.BODY, message.messageBody) put(SmsTable.TYPE, type) put(MmsSmsColumns.THREAD_ID, threadId) diff --git a/core-util/src/main/java/org/signal/core/util/SQLiteDatabaseExtensions.kt b/core-util/src/main/java/org/signal/core/util/SQLiteDatabaseExtensions.kt index b45e15751c..c7140e1b77 100644 --- a/core-util/src/main/java/org/signal/core/util/SQLiteDatabaseExtensions.kt +++ b/core-util/src/main/java/org/signal/core/util/SQLiteDatabaseExtensions.kt @@ -6,6 +6,7 @@ import android.database.sqlite.SQLiteDatabase import androidx.core.content.contentValuesOf import androidx.sqlite.db.SupportSQLiteDatabase import androidx.sqlite.db.SupportSQLiteQueryBuilder +import org.intellij.lang.annotations.Language /** * Begins a transaction on the `this` database, runs the provided [block] providing the `this` value as it's argument @@ -85,7 +86,7 @@ class SelectBuilderPart2( private val columns: Array, private val tableName: String ) { - fun where(where: String, vararg whereArgs: Any): SelectBuilderPart3 { + fun where(@Language("sql") where: String, vararg whereArgs: Any): SelectBuilderPart3 { return SelectBuilderPart3(db, columns, tableName, where, SqlUtil.buildArgs(*whereArgs)) } @@ -213,7 +214,7 @@ class UpdateBuilderPart2( private val tableName: String, private val values: ContentValues ) { - fun where(where: String, vararg whereArgs: Any): UpdateBuilderPart3 { + fun where(@Language("sql") where: String, vararg whereArgs: Any): UpdateBuilderPart3 { return UpdateBuilderPart3(db, tableName, values, where, SqlUtil.buildArgs(*whereArgs)) } @@ -239,7 +240,7 @@ class DeleteBuilderPart1( private val db: SupportSQLiteDatabase, private val tableName: String ) { - fun where(where: String, vararg whereArgs: Any): DeleteBuilderPart2 { + fun where(@Language("sql") where: String, vararg whereArgs: Any): DeleteBuilderPart2 { return DeleteBuilderPart2(db, tableName, where, SqlUtil.buildArgs(*whereArgs)) }