mirror of
https://github.com/oxen-io/session-android.git
synced 2025-01-11 18:53:40 +00:00
clean up signal database
This commit is contained in:
parent
861b4bf9c9
commit
5db7f0ecb8
@ -375,9 +375,6 @@
|
||||
<action android:name="com.google.firebase.MESSAGING_EVENT" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
<service
|
||||
android:name="org.thoughtcrime.securesms.service.ApplicationMigrationService"
|
||||
android:enabled="true" />
|
||||
<service
|
||||
android:name="org.thoughtcrime.securesms.service.KeyCachingService"
|
||||
android:enabled="true"
|
||||
|
@ -66,14 +66,6 @@ public abstract class Database {
|
||||
cursor.setNotificationUri(context.getContentResolver(), DatabaseContentProviders.ConversationList.CONTENT_URI);
|
||||
}
|
||||
|
||||
protected void setNotifyStickerListeners(Cursor cursor) {
|
||||
cursor.setNotificationUri(context.getContentResolver(), DatabaseContentProviders.Sticker.CONTENT_URI);
|
||||
}
|
||||
|
||||
protected void setNotifyStickerPackListeners(Cursor cursor) {
|
||||
cursor.setNotificationUri(context.getContentResolver(), DatabaseContentProviders.StickerPack.CONTENT_URI);
|
||||
}
|
||||
|
||||
protected void registerAttachmentListeners(@NonNull ContentObserver observer) {
|
||||
context.getContentResolver().registerContentObserver(DatabaseContentProviders.Attachment.CONTENT_URI,
|
||||
true,
|
||||
|
@ -177,24 +177,6 @@ public class GroupDatabase extends Database implements LokiOpenGroupDatabaseProt
|
||||
return recipients;
|
||||
}
|
||||
|
||||
public boolean isClosedGroupMember(String hexEncodedPublicKey) {
|
||||
try {
|
||||
Address address = Address.fromSerialized(hexEncodedPublicKey);
|
||||
Reader reader = DatabaseFactory.getGroupDatabase(context).getGroups();
|
||||
|
||||
GroupRecord record;
|
||||
while ((record = reader.getNext()) != null) {
|
||||
if (record.isClosedGroup() && record.getMembers().contains(address)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public long create(@NonNull String groupId, @Nullable String title, @NonNull List<Address> members,
|
||||
@Nullable SignalServiceAttachmentPointer avatar, @Nullable String relay, @Nullable List<Address> admins, @NonNull Long formationTimestamp)
|
||||
{
|
||||
|
@ -206,22 +206,6 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long getIDForMessageAtIndex(long threadID, int index) {
|
||||
SQLiteDatabase database = databaseHelper.getReadableDatabase();
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
cursor = database.query(TABLE_NAME, null, THREAD_ID + " = ?", new String[] { threadID + "" }, null, null, null);
|
||||
if (cursor != null && cursor.moveToPosition(index)) {
|
||||
return cursor.getLong(0);
|
||||
}
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public void addFailures(long messageId, List<NetworkFailure> failure) {
|
||||
try {
|
||||
addToDocument(messageId, NETWORK_FAILURE, failure, NetworkFailureList.class);
|
||||
@ -367,17 +351,6 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
}
|
||||
}
|
||||
|
||||
public void markAsOutbox(long messageId) {
|
||||
long threadId = getThreadIdForMessage(messageId);
|
||||
updateMailboxBitmask(messageId, Types.BASE_TYPE_MASK, Types.BASE_OUTBOX_TYPE, Optional.of(threadId));
|
||||
}
|
||||
|
||||
public void markAsForcedSms(long messageId) {
|
||||
long threadId = getThreadIdForMessage(messageId);
|
||||
updateMailboxBitmask(messageId, Types.PUSH_MESSAGE_BIT, Types.MESSAGE_FORCE_SMS_BIT, Optional.of(threadId));
|
||||
notifyConversationListeners(threadId);
|
||||
}
|
||||
|
||||
public void markAsPendingInsecureSmsFallback(long messageId) {
|
||||
long threadId = getThreadIdForMessage(messageId);
|
||||
updateMailboxBitmask(messageId, Types.BASE_TYPE_MASK, Types.BASE_PENDING_INSECURE_SMS_FALLBACK, Optional.of(threadId));
|
||||
@ -403,47 +376,6 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
notifyConversationListeners(threadId);
|
||||
}
|
||||
|
||||
public void markDownloadState(long messageId, long state) {
|
||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(STATUS, state);
|
||||
|
||||
database.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {messageId + ""});
|
||||
notifyConversationListeners(getThreadIdForMessage(messageId));
|
||||
}
|
||||
|
||||
public void markAsNoSession(long messageId, long threadId) {
|
||||
updateMailboxBitmask(messageId, Types.ENCRYPTION_MASK, Types.ENCRYPTION_REMOTE_NO_SESSION_BIT, Optional.of(threadId));
|
||||
notifyConversationListeners(threadId);
|
||||
}
|
||||
|
||||
// public void markAsSecure(long messageId) {
|
||||
// updateMailboxBitmask(messageId, 0, Types.SECURE_MESSAGE_BIT, Optional.<Long>absent());
|
||||
// }
|
||||
|
||||
public void markAsInsecure(long messageId) {
|
||||
updateMailboxBitmask(messageId, Types.SECURE_MESSAGE_BIT, 0, Optional.<Long>absent());
|
||||
}
|
||||
|
||||
// public void markAsPush(long messageId) {
|
||||
// updateMailboxBitmask(messageId, 0, Types.PUSH_MESSAGE_BIT, Optional.<Long>absent());
|
||||
// }
|
||||
|
||||
public void markAsDecryptFailed(long messageId, long threadId) {
|
||||
updateMailboxBitmask(messageId, Types.ENCRYPTION_MASK, Types.ENCRYPTION_REMOTE_FAILED_BIT, Optional.of(threadId));
|
||||
notifyConversationListeners(threadId);
|
||||
}
|
||||
|
||||
public void markAsDecryptDuplicate(long messageId, long threadId) {
|
||||
updateMailboxBitmask(messageId, Types.ENCRYPTION_MASK, Types.ENCRYPTION_REMOTE_DUPLICATE_BIT, Optional.of(threadId));
|
||||
notifyConversationListeners(threadId);
|
||||
}
|
||||
|
||||
public void markAsLegacyVersion(long messageId, long threadId) {
|
||||
updateMailboxBitmask(messageId, Types.ENCRYPTION_MASK, Types.ENCRYPTION_REMOTE_LEGACY_BIT, Optional.of(threadId));
|
||||
notifyConversationListeners(threadId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markUnidentified(long messageId, boolean unidentified) {
|
||||
ContentValues contentValues = new ContentValues();
|
||||
@ -520,91 +452,6 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
return result;
|
||||
}
|
||||
|
||||
public List<Pair<Long, Long>> setTimestampRead(SyncMessageId messageId, long proposedExpireStarted) {
|
||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||
List<Pair<Long, Long>> expiring = new LinkedList<>();
|
||||
Cursor cursor = null;
|
||||
|
||||
try {
|
||||
cursor = database.query(TABLE_NAME, new String[] {ID, THREAD_ID, MESSAGE_BOX, EXPIRES_IN, EXPIRE_STARTED, ADDRESS}, DATE_SENT + " = ?", new String[] {String.valueOf(messageId.getTimetamp())}, null, null, null, null);
|
||||
|
||||
while (cursor.moveToNext()) {
|
||||
Address theirAddress = Address.fromSerialized(cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS)));
|
||||
Address ourAddress = messageId.getAddress();
|
||||
|
||||
if (ourAddress.equals(theirAddress) || theirAddress.isGroup()) {
|
||||
long id = cursor.getLong(cursor.getColumnIndexOrThrow(ID));
|
||||
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID));
|
||||
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRES_IN));
|
||||
long expireStarted = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRE_STARTED));
|
||||
|
||||
expireStarted = expireStarted > 0 ? Math.min(proposedExpireStarted, expireStarted) : proposedExpireStarted;
|
||||
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(READ, 1);
|
||||
|
||||
if (expiresIn > 0) {
|
||||
values.put(EXPIRE_STARTED, expireStarted);
|
||||
expiring.add(new Pair<>(id, expiresIn));
|
||||
}
|
||||
|
||||
database.update(TABLE_NAME, values, ID_WHERE, new String[]{String.valueOf(id)});
|
||||
|
||||
DatabaseFactory.getThreadDatabase(context).updateReadState(threadId);
|
||||
DatabaseFactory.getThreadDatabase(context).setLastSeen(threadId);
|
||||
notifyConversationListeners(threadId);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (cursor != null)
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
return expiring;
|
||||
}
|
||||
|
||||
public void updateMessageBody(long messageId, String body) {
|
||||
long type = 0;
|
||||
|
||||
updateMessageBodyAndType(messageId, body, Types.ENCRYPTION_MASK, type);
|
||||
}
|
||||
|
||||
private Pair<Long, Long> updateMessageBodyAndType(long messageId, String body, long maskOff, long maskOn) {
|
||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||
db.execSQL("UPDATE " + TABLE_NAME + " SET " + BODY + " = ?, " +
|
||||
MESSAGE_BOX + " = (" + MESSAGE_BOX + " & " + (Types.TOTAL_MASK - maskOff) + " | " + maskOn + ") " +
|
||||
"WHERE " + ID + " = ?",
|
||||
new String[] {body, messageId + ""});
|
||||
|
||||
long threadId = getThreadIdForMessage(messageId);
|
||||
|
||||
DatabaseFactory.getThreadDatabase(context).update(threadId, true);
|
||||
notifyConversationListeners(threadId);
|
||||
notifyConversationListListeners();
|
||||
|
||||
return new Pair<>(messageId, threadId);
|
||||
}
|
||||
|
||||
public Optional<MmsNotificationInfo> getNotification(long messageId) {
|
||||
Cursor cursor = null;
|
||||
|
||||
try {
|
||||
cursor = rawQuery(RAW_ID_WHERE, new String[] {String.valueOf(messageId)});
|
||||
|
||||
if (cursor != null && cursor.moveToNext()) {
|
||||
return Optional.of(new MmsNotificationInfo(cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS)),
|
||||
cursor.getString(cursor.getColumnIndexOrThrow(CONTENT_LOCATION)),
|
||||
cursor.getString(cursor.getColumnIndexOrThrow(TRANSACTION_ID)),
|
||||
cursor.getInt(cursor.getColumnIndexOrThrow(SUBSCRIPTION_ID))));
|
||||
} else {
|
||||
return Optional.absent();
|
||||
}
|
||||
} finally {
|
||||
if (cursor != null)
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
public OutgoingMediaMessage getOutgoingMessage(long messageId)
|
||||
throws MmsException, NoSuchMessageException
|
||||
{
|
||||
@ -766,56 +613,6 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
public long copyMessageInbox(long messageId) throws MmsException {
|
||||
try {
|
||||
OutgoingMediaMessage request = getOutgoingMessage(messageId);
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(ADDRESS, request.getRecipient().getAddress().serialize());
|
||||
contentValues.put(DATE_SENT, request.getSentTimeMillis());
|
||||
contentValues.put(MESSAGE_BOX, Types.BASE_INBOX_TYPE | Types.SECURE_MESSAGE_BIT);
|
||||
contentValues.put(THREAD_ID, getThreadIdForMessage(messageId));
|
||||
contentValues.put(READ, 1);
|
||||
contentValues.put(DATE_RECEIVED, contentValues.getAsLong(DATE_SENT));
|
||||
contentValues.put(EXPIRES_IN, request.getExpiresIn());
|
||||
|
||||
List<Attachment> attachments = new LinkedList<>();
|
||||
|
||||
for (Attachment attachment : request.getAttachments()) {
|
||||
DatabaseAttachment databaseAttachment = (DatabaseAttachment)attachment;
|
||||
attachments.add(new DatabaseAttachment(databaseAttachment.getAttachmentId(),
|
||||
databaseAttachment.getMmsId(),
|
||||
databaseAttachment.hasData(),
|
||||
databaseAttachment.hasThumbnail(),
|
||||
databaseAttachment.getContentType(),
|
||||
AttachmentDatabase.TRANSFER_PROGRESS_DONE,
|
||||
databaseAttachment.getSize(),
|
||||
databaseAttachment.getFileName(),
|
||||
databaseAttachment.getLocation(),
|
||||
databaseAttachment.getKey(),
|
||||
databaseAttachment.getRelay(),
|
||||
databaseAttachment.getDigest(),
|
||||
databaseAttachment.getFastPreflightId(),
|
||||
databaseAttachment.isVoiceNote(),
|
||||
databaseAttachment.getWidth(),
|
||||
databaseAttachment.getHeight(),
|
||||
databaseAttachment.isQuote(),
|
||||
databaseAttachment.getCaption(),
|
||||
databaseAttachment.getSticker(),
|
||||
databaseAttachment.getUrl()));
|
||||
}
|
||||
|
||||
return insertMediaMessage(request.getBody(),
|
||||
attachments,
|
||||
new LinkedList<>(),
|
||||
request.getSharedContacts(),
|
||||
request.getLinkPreviews(),
|
||||
contentValues,
|
||||
null);
|
||||
} catch (NoSuchMessageException e) {
|
||||
throw new MmsException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private Optional<InsertResult> insertMessageInbox(IncomingMediaMessage retrieved,
|
||||
String contentLocation,
|
||||
long threadId, long mailbox,
|
||||
@ -885,23 +682,6 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
return Optional.of(new InsertResult(messageId, threadId));
|
||||
}
|
||||
|
||||
public Optional<InsertResult> insertMessageInbox(IncomingMediaMessage retrieved,
|
||||
String contentLocation, long threadId)
|
||||
throws MmsException
|
||||
{
|
||||
long type = Types.BASE_INBOX_TYPE;
|
||||
|
||||
if (retrieved.isPushMessage()) {
|
||||
type |= Types.PUSH_MESSAGE_BIT;
|
||||
}
|
||||
|
||||
if (retrieved.isExpirationUpdate()) {
|
||||
type |= Types.EXPIRATION_TIMER_UPDATE_BIT;
|
||||
}
|
||||
|
||||
return insertMessageInbox(retrieved, contentLocation, threadId, type, 0);
|
||||
}
|
||||
|
||||
public Optional<InsertResult> insertSecureDecryptedMessageOutbox(OutgoingMediaMessage retrieved, long threadId, long serverTimestamp)
|
||||
throws MmsException
|
||||
{
|
||||
@ -938,52 +718,6 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
return insertSecureDecryptedMessageInbox(retrieved, threadId, 0);
|
||||
}
|
||||
|
||||
public Pair<Long, Long> insertMessageInbox(@NonNull NotificationInd notification, int subscriptionId) {
|
||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||
long threadId = getThreadIdFor(notification);
|
||||
ContentValues contentValues = new ContentValues();
|
||||
ContentValuesBuilder contentBuilder = new ContentValuesBuilder(contentValues);
|
||||
|
||||
Log.i(TAG, "Message received type: " + notification.getMessageType());
|
||||
|
||||
|
||||
contentBuilder.add(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());
|
||||
|
||||
if (notification.getFrom() != null) {
|
||||
contentValues.put(ADDRESS, Address.fromExternal(context, Util.toIsoString(notification.getFrom().getTextString())).serialize());
|
||||
}
|
||||
|
||||
contentValues.put(MESSAGE_BOX, Types.BASE_INBOX_TYPE);
|
||||
contentValues.put(THREAD_ID, threadId);
|
||||
contentValues.put(STATUS, Status.DOWNLOAD_INITIALIZED);
|
||||
contentValues.put(DATE_RECEIVED, generatePduCompatTimestamp());
|
||||
contentValues.put(READ, Util.isDefaultSmsProvider(context) ? 0 : 1);
|
||||
contentValues.put(SUBSCRIPTION_ID, subscriptionId);
|
||||
|
||||
if (!contentValues.containsKey(DATE_SENT))
|
||||
contentValues.put(DATE_SENT, contentValues.getAsLong(DATE_RECEIVED));
|
||||
|
||||
long messageId = db.insert(TABLE_NAME, null, contentValues);
|
||||
|
||||
return new Pair<>(messageId, threadId);
|
||||
}
|
||||
|
||||
public void markIncomingNotificationReceived(long threadId) {
|
||||
notifyConversationListeners(threadId);
|
||||
DatabaseFactory.getThreadDatabase(context).update(threadId, true);
|
||||
|
||||
if (Util.isDefaultSmsProvider(context)) {
|
||||
DatabaseFactory.getThreadDatabase(context).incrementUnread(threadId, 1);
|
||||
}
|
||||
|
||||
ApplicationContext.getInstance(context).getJobManager().add(new TrimThreadJob(threadId));
|
||||
}
|
||||
|
||||
public long insertMessageOutbox(@NonNull OutgoingMediaMessage message,
|
||||
long threadId, boolean forceSms,
|
||||
@Nullable SmsDatabase.InsertListener insertListener)
|
||||
@ -1283,21 +1017,6 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
database.delete(TABLE_NAME, null, null);
|
||||
}
|
||||
|
||||
public Cursor getCarrierMmsInformation(String apn) {
|
||||
Uri uri = Uri.withAppendedPath(Uri.parse("content://telephony/carriers"), "current");
|
||||
String selection = TextUtils.isEmpty(apn) ? null : "apn = ?";
|
||||
String[] selectionArgs = TextUtils.isEmpty(apn) ? null : new String[] {apn.trim()};
|
||||
|
||||
try {
|
||||
return context.getContentResolver().query(uri, null, selection, selectionArgs, null);
|
||||
} catch (NullPointerException npe) {
|
||||
// NOTE - This is dumb, but on some devices there's an NPE in the Android framework
|
||||
// for the provider of this call, which gets rethrown back to here through a binder
|
||||
// call.
|
||||
throw new IllegalArgumentException(npe);
|
||||
}
|
||||
}
|
||||
|
||||
public void beginTransaction() {
|
||||
databaseHelper.getWritableDatabase().beginTransaction();
|
||||
}
|
||||
@ -1322,39 +1041,6 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
public static final int DOWNLOAD_INITIALIZED = 1;
|
||||
public static final int DOWNLOAD_NO_CONNECTIVITY = 2;
|
||||
public static final int DOWNLOAD_CONNECTING = 3;
|
||||
public static final int DOWNLOAD_SOFT_FAILURE = 4;
|
||||
public static final int DOWNLOAD_HARD_FAILURE = 5;
|
||||
public static final int DOWNLOAD_APN_UNAVAILABLE = 6;
|
||||
}
|
||||
|
||||
public static class MmsNotificationInfo {
|
||||
private final Address from;
|
||||
private final String contentLocation;
|
||||
private final String transactionId;
|
||||
private final int subscriptionId;
|
||||
|
||||
MmsNotificationInfo(@Nullable String from, String contentLocation, String transactionId, int subscriptionId) {
|
||||
this.from = from == null ? null : Address.fromSerialized(from);
|
||||
this.contentLocation = contentLocation;
|
||||
this.transactionId = transactionId;
|
||||
this.subscriptionId = subscriptionId;
|
||||
}
|
||||
|
||||
public String getContentLocation() {
|
||||
return contentLocation;
|
||||
}
|
||||
|
||||
public String getTransactionId() {
|
||||
return transactionId;
|
||||
}
|
||||
|
||||
public int getSubscriptionId() {
|
||||
return subscriptionId;
|
||||
}
|
||||
|
||||
public @Nullable Address getFrom() {
|
||||
return from;
|
||||
}
|
||||
}
|
||||
|
||||
public class OutgoingMessageReader {
|
||||
@ -1567,9 +1253,4 @@ public class MmsDatabase extends MessagingDatabase {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private long generatePduCompatTimestamp() {
|
||||
final long time = System.currentTimeMillis();
|
||||
return time - (time % 1000);
|
||||
}
|
||||
}
|
||||
|
@ -248,11 +248,6 @@ public interface MmsSmsColumns {
|
||||
}
|
||||
|
||||
public static long translateFromSystemBaseType(long theirType) {
|
||||
// public static final int NONE_TYPE = 0;
|
||||
// public static final int INBOX_TYPE = 1;
|
||||
// public static final int SENT_TYPE = 2;
|
||||
// public static final int SENT_PENDING = 4;
|
||||
// public static final int FAILED_TYPE = 5;
|
||||
|
||||
switch ((int)theirType) {
|
||||
case 1: return BASE_INBOX_TYPE;
|
||||
@ -265,70 +260,6 @@ public interface MmsSmsColumns {
|
||||
|
||||
return BASE_INBOX_TYPE;
|
||||
}
|
||||
|
||||
public static int translateToSystemBaseType(long type) {
|
||||
if (isInboxType(type)) return 1;
|
||||
else if (isOutgoingMessageType(type)) return 2;
|
||||
else if (isFailedMessageType(type)) return 5;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
//
|
||||
//
|
||||
// public static final int NONE_TYPE = 0;
|
||||
// public static final int INBOX_TYPE = 1;
|
||||
// public static final int SENT_TYPE = 2;
|
||||
// public static final int SENT_PENDING = 4;
|
||||
// public static final int FAILED_TYPE = 5;
|
||||
//
|
||||
// public static final int OUTBOX_TYPE = 43; // Messages are stored local encrypted and need delivery.
|
||||
//
|
||||
//
|
||||
// public static final int ENCRYPTING_TYPE = 42; // Messages are stored local encrypted and need async encryption and delivery.
|
||||
// public static final int SECURE_SENT_TYPE = 44; // Messages were sent with async encryption.
|
||||
// public static final int SECURE_RECEIVED_TYPE = 45; // Messages were received with async decryption.
|
||||
// public static final int FAILED_DECRYPT_TYPE = 46; // Messages were received with async encryption and failed to decrypt.
|
||||
// public static final int DECRYPTING_TYPE = 47; // Messages are in the process of being asymmetricaly decrypted.
|
||||
// public static final int NO_SESSION_TYPE = 48; // Messages were received with async encryption but there is no session yet.
|
||||
//
|
||||
// public static final int OUTGOING_KEY_EXCHANGE_TYPE = 49;
|
||||
// public static final int INCOMING_KEY_EXCHANGE_TYPE = 50;
|
||||
// public static final int STALE_KEY_EXCHANGE_TYPE = 51;
|
||||
// public static final int PROCESSED_KEY_EXCHANGE_TYPE = 52;
|
||||
//
|
||||
// public static final int[] OUTGOING_MESSAGE_TYPES = {SENT_TYPE, SENT_PENDING, ENCRYPTING_TYPE,
|
||||
// OUTBOX_TYPE, SECURE_SENT_TYPE,
|
||||
// FAILED_TYPE, OUTGOING_KEY_EXCHANGE_TYPE};
|
||||
//
|
||||
// public static boolean isFailedMessageType(long type) {
|
||||
// return type == FAILED_TYPE;
|
||||
// }
|
||||
//
|
||||
// public static boolean isOutgoingMessageType(long type) {
|
||||
// for (int outgoingType : OUTGOING_MESSAGE_TYPES) {
|
||||
// if (type == outgoingType)
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// return false;
|
||||
// }
|
||||
//
|
||||
// public static boolean isPendingMessageType(long type) {
|
||||
// return type == SENT_PENDING || type == ENCRYPTING_TYPE || type == OUTBOX_TYPE;
|
||||
// }
|
||||
//
|
||||
// public static boolean isSecureType(long type) {
|
||||
// return
|
||||
// type == SECURE_SENT_TYPE || type == ENCRYPTING_TYPE ||
|
||||
// type == SECURE_RECEIVED_TYPE || type == DECRYPTING_TYPE;
|
||||
// }
|
||||
//
|
||||
// public static boolean isKeyExchangeType(long type) {
|
||||
// return type == OUTGOING_KEY_EXCHANGE_TYPE || type == INCOMING_KEY_EXCHANGE_TYPE;
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
|
@ -136,16 +136,6 @@ public class MmsSmsDatabase extends Database {
|
||||
return getConversation(threadId, 0, 0);
|
||||
}
|
||||
|
||||
public Cursor getIdentityConflictMessagesForThread(long threadId) {
|
||||
String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " ASC";
|
||||
String selection = MmsSmsColumns.THREAD_ID + " = " + threadId + " AND " + MmsSmsColumns.MISMATCHED_IDENTITIES + " IS NOT NULL";
|
||||
|
||||
Cursor cursor = queryTables(PROJECTION, selection, order, null);
|
||||
setNotifyConverationListeners(cursor, threadId);
|
||||
|
||||
return cursor;
|
||||
}
|
||||
|
||||
public Cursor getConversationSnippet(long threadId) {
|
||||
String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC";
|
||||
String selection = MmsSmsColumns.THREAD_ID + " = " + threadId;
|
||||
@ -228,26 +218,6 @@ public class MmsSmsDatabase extends Database {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the position of the message with the provided timestamp in the query results you'd
|
||||
* get from calling {@link #getConversation(long)}.
|
||||
*
|
||||
* Note: This could give back incorrect results in the situation where multiple messages have the
|
||||
* same received timestamp. However, because this was designed to determine where to scroll to,
|
||||
* you'll still wind up in about the right spot.
|
||||
*/
|
||||
public int getMessagePositionInConversation(long threadId, long receivedTimestamp) {
|
||||
String order = MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " DESC";
|
||||
String selection = MmsSmsColumns.THREAD_ID + " = " + threadId + " AND " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED + " > " + receivedTimestamp;
|
||||
|
||||
try (Cursor cursor = queryTables(new String[]{ "COUNT(*)" }, selection, order, null)) {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
return cursor.getInt(0);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private Cursor queryTables(String[] projection, String selection, String order, String limit) {
|
||||
String[] mmsProjection = {MmsDatabase.DATE_SENT + " AS " + MmsSmsColumns.NORMALIZED_DATE_SENT,
|
||||
MmsDatabase.DATE_RECEIVED + " AS " + MmsSmsColumns.NORMALIZED_DATE_RECEIVED,
|
||||
|
@ -1,4 +0,0 @@
|
||||
package org.thoughtcrime.securesms.database;
|
||||
|
||||
public class NotInDirectoryException extends Throwable {
|
||||
}
|
@ -104,17 +104,6 @@ public class RecipientDatabase extends Database {
|
||||
super(context, databaseHelper);
|
||||
}
|
||||
|
||||
public Cursor getBlocked() {
|
||||
SQLiteDatabase database = databaseHelper.getReadableDatabase();
|
||||
|
||||
return database.query(TABLE_NAME, new String[] {ID, ADDRESS}, BLOCK + " = 1",
|
||||
null, null, null, null, null);
|
||||
}
|
||||
|
||||
public RecipientReader readerForBlocked(Cursor cursor) {
|
||||
return new RecipientReader(context, cursor);
|
||||
}
|
||||
|
||||
public RecipientReader getRecipientsWithNotificationChannels() {
|
||||
SQLiteDatabase database = databaseHelper.getReadableDatabase();
|
||||
Cursor cursor = database.query(TABLE_NAME, new String[] {ID, ADDRESS}, NOTIFICATION_CHANNEL + " NOT NULL",
|
||||
@ -195,21 +184,6 @@ public class RecipientDatabase extends Database {
|
||||
forceSmsSelection));
|
||||
}
|
||||
|
||||
public BulkOperationsHandle resetAllSystemContactInfo() {
|
||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||
database.beginTransaction();
|
||||
|
||||
ContentValues contentValues = new ContentValues(1);
|
||||
contentValues.put(SYSTEM_DISPLAY_NAME, (String)null);
|
||||
contentValues.put(SYSTEM_PHOTO_URI, (String)null);
|
||||
contentValues.put(SYSTEM_PHONE_LABEL, (String)null);
|
||||
contentValues.put(SYSTEM_CONTACT_URI, (String)null);
|
||||
|
||||
database.update(TABLE_NAME, contentValues, null, null);
|
||||
|
||||
return new BulkOperationsHandle(database);
|
||||
}
|
||||
|
||||
public void setColor(@NonNull Recipient recipient, @NonNull MaterialColor color) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(COLOR, color.serialize());
|
||||
@ -238,34 +212,6 @@ public class RecipientDatabase extends Database {
|
||||
recipient.resolve().setBlocked(blocked);
|
||||
}
|
||||
|
||||
public void setMessageRingtone(@NonNull Recipient recipient, @Nullable Uri notification) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(NOTIFICATION, notification == null ? null : notification.toString());
|
||||
updateOrInsert(recipient.getAddress(), values);
|
||||
recipient.resolve().setMessageRingtone(notification);
|
||||
}
|
||||
|
||||
public void setCallRingtone(@NonNull Recipient recipient, @Nullable Uri ringtone) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(CALL_RINGTONE, ringtone == null ? null : ringtone.toString());
|
||||
updateOrInsert(recipient.getAddress(), values);
|
||||
recipient.resolve().setCallRingtone(ringtone);
|
||||
}
|
||||
|
||||
public void setMessageVibrate(@NonNull Recipient recipient, @NonNull VibrateState enabled) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(VIBRATE, enabled.getId());
|
||||
updateOrInsert(recipient.getAddress(), values);
|
||||
recipient.resolve().setMessageVibrate(enabled);
|
||||
}
|
||||
|
||||
public void setCallVibrate(@NonNull Recipient recipient, @NonNull VibrateState enabled) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(CALL_VIBRATE, enabled.getId());
|
||||
updateOrInsert(recipient.getAddress(), values);
|
||||
recipient.resolve().setCallVibrate(enabled);
|
||||
}
|
||||
|
||||
public void setMuted(@NonNull Recipient recipient, long until) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(MUTE_UNTIL, until);
|
||||
@ -296,13 +242,6 @@ public class RecipientDatabase extends Database {
|
||||
recipient.resolve().setProfileKey(profileKey);
|
||||
}
|
||||
|
||||
public void setProfileName(@NonNull Recipient recipient, @Nullable String profileName) {
|
||||
ContentValues contentValues = new ContentValues(1);
|
||||
contentValues.put(SIGNAL_PROFILE_NAME, profileName);
|
||||
updateOrInsert(recipient.getAddress(), contentValues);
|
||||
recipient.resolve().setProfileName(profileName);
|
||||
}
|
||||
|
||||
public void setProfileAvatar(@NonNull Recipient recipient, @Nullable String profileAvatar) {
|
||||
ContentValues contentValues = new ContentValues(1);
|
||||
contentValues.put(SIGNAL_PROFILE_AVATAR, profileAvatar);
|
||||
@ -324,19 +263,6 @@ public class RecipientDatabase extends Database {
|
||||
recipient.setNotificationChannel(notificationChannel);
|
||||
}
|
||||
|
||||
public Set<Address> getAllAddresses() {
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
Set<Address> results = new HashSet<>();
|
||||
|
||||
try (Cursor cursor = db.query(TABLE_NAME, new String[] {ADDRESS}, null, null, null, null, null)) {
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
results.add(Address.fromExternal(context, cursor.getString(0)));
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
public void setRegistered(@NonNull Recipient recipient, RegisteredState registeredState) {
|
||||
ContentValues contentValues = new ContentValues(1);
|
||||
contentValues.put(REGISTERED, registeredState.getId());
|
||||
@ -344,91 +270,6 @@ public class RecipientDatabase extends Database {
|
||||
recipient.setRegistered(registeredState);
|
||||
}
|
||||
|
||||
public void setRegistered(@NonNull List<Address> activeAddresses,
|
||||
@NonNull List<Address> inactiveAddresses)
|
||||
{
|
||||
for (Address activeAddress : activeAddresses) {
|
||||
ContentValues contentValues = new ContentValues(1);
|
||||
contentValues.put(REGISTERED, RegisteredState.REGISTERED.getId());
|
||||
|
||||
updateOrInsert(activeAddress, contentValues);
|
||||
Recipient.applyCached(activeAddress, recipient -> recipient.setRegistered(RegisteredState.REGISTERED));
|
||||
}
|
||||
|
||||
for (Address inactiveAddress : inactiveAddresses) {
|
||||
ContentValues contentValues = new ContentValues(1);
|
||||
contentValues.put(REGISTERED, RegisteredState.NOT_REGISTERED.getId());
|
||||
|
||||
updateOrInsert(inactiveAddress, contentValues);
|
||||
Recipient.applyCached(inactiveAddress, recipient -> recipient.setRegistered(RegisteredState.NOT_REGISTERED));
|
||||
}
|
||||
}
|
||||
|
||||
public List<Address> getRegistered() {
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
List<Address> results = new LinkedList<>();
|
||||
|
||||
try (Cursor cursor = db.query(TABLE_NAME, new String[] {ADDRESS}, REGISTERED + " = ?", new String[] {"1"}, null, null, null)) {
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
results.add(Address.fromSerialized(cursor.getString(0)));
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
public List<Address> getSystemContacts() {
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
List<Address> results = new LinkedList<>();
|
||||
|
||||
try (Cursor cursor = db.query(TABLE_NAME, new String[] {ADDRESS}, SYSTEM_DISPLAY_NAME + " IS NOT NULL AND " + SYSTEM_DISPLAY_NAME + " != \"\"", null, null, null, null)) {
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
results.add(Address.fromSerialized(cursor.getString(0)));
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
public void updateSystemContactColors(@NonNull ColorUpdater updater) {
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
Map<Address, MaterialColor> updates = new HashMap<>();
|
||||
|
||||
db.beginTransaction();
|
||||
try (Cursor cursor = db.query(TABLE_NAME, new String[] {ADDRESS, COLOR, SYSTEM_DISPLAY_NAME}, SYSTEM_DISPLAY_NAME + " IS NOT NULL AND " + SYSTEM_DISPLAY_NAME + " != \"\"", null, null, null, null)) {
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
Address address = Address.fromSerialized(cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS)));
|
||||
MaterialColor newColor = updater.update(cursor.getString(cursor.getColumnIndexOrThrow(SYSTEM_DISPLAY_NAME)),
|
||||
cursor.getString(cursor.getColumnIndexOrThrow(COLOR)));
|
||||
|
||||
ContentValues contentValues = new ContentValues(1);
|
||||
contentValues.put(COLOR, newColor.serialize());
|
||||
db.update(TABLE_NAME, contentValues, ADDRESS + " = ?", new String[]{address.serialize()});
|
||||
|
||||
updates.put(address, newColor);
|
||||
}
|
||||
} finally {
|
||||
db.setTransactionSuccessful();
|
||||
db.endTransaction();
|
||||
|
||||
Stream.of(updates.entrySet()).forEach(entry -> {
|
||||
Recipient.applyCached(entry.getKey(), recipient -> {
|
||||
recipient.setColor(entry.getValue());
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// XXX This shouldn't be here, and is just a temporary workaround
|
||||
public RegisteredState isRegistered(@NonNull Address address) {
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
|
||||
try (Cursor cursor = db.query(TABLE_NAME, new String[] {REGISTERED}, ADDRESS + " = ?", new String[] {address.serialize()}, null, null, null)) {
|
||||
if (cursor != null && cursor.moveToFirst()) return RegisteredState.fromId(cursor.getInt(0));
|
||||
else return RegisteredState.UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
private void updateOrInsert(Address address, ContentValues contentValues) {
|
||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||
|
||||
@ -446,45 +287,6 @@ public class RecipientDatabase extends Database {
|
||||
database.endTransaction();
|
||||
}
|
||||
|
||||
public class BulkOperationsHandle {
|
||||
|
||||
private final SQLiteDatabase database;
|
||||
|
||||
private final Map<Address, PendingContactInfo> pendingContactInfoMap = new HashMap<>();
|
||||
|
||||
BulkOperationsHandle(SQLiteDatabase database) {
|
||||
this.database = database;
|
||||
}
|
||||
|
||||
public void setSystemContactInfo(@NonNull Address address, @Nullable String displayName, @Nullable String photoUri, @Nullable String systemPhoneLabel, @Nullable String systemContactUri) {
|
||||
ContentValues contentValues = new ContentValues(1);
|
||||
contentValues.put(SYSTEM_DISPLAY_NAME, displayName);
|
||||
contentValues.put(SYSTEM_PHOTO_URI, photoUri);
|
||||
contentValues.put(SYSTEM_PHONE_LABEL, systemPhoneLabel);
|
||||
contentValues.put(SYSTEM_CONTACT_URI, systemContactUri);
|
||||
|
||||
updateOrInsert(address, contentValues);
|
||||
pendingContactInfoMap.put(address, new PendingContactInfo(displayName, photoUri, systemPhoneLabel, systemContactUri));
|
||||
}
|
||||
|
||||
public void finish() {
|
||||
database.setTransactionSuccessful();
|
||||
database.endTransaction();
|
||||
|
||||
Stream.of(pendingContactInfoMap.entrySet())
|
||||
.forEach(entry -> Recipient.applyCached(entry.getKey(), recipient -> {
|
||||
recipient.setName(entry.getValue().displayName);
|
||||
recipient.setSystemContactPhoto(Util.uri(entry.getValue().photoUri));
|
||||
recipient.setCustomLabel(entry.getValue().phoneLabel);
|
||||
recipient.setContactUri(Util.uri(entry.getValue().contactUri));
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
public interface ColorUpdater {
|
||||
MaterialColor update(@NonNull String name, @Nullable String color);
|
||||
}
|
||||
|
||||
public static class RecipientReader implements Closeable {
|
||||
|
||||
private final Context context;
|
||||
@ -512,20 +314,4 @@ public class RecipientDatabase extends Database {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
private static class PendingContactInfo {
|
||||
|
||||
private final String displayName;
|
||||
private final String photoUri;
|
||||
private final String phoneLabel;
|
||||
private final String contactUri;
|
||||
|
||||
private PendingContactInfo(String displayName, String photoUri, String phoneLabel, String contactUri) {
|
||||
this.displayName = displayName;
|
||||
this.photoUri = photoUri;
|
||||
this.phoneLabel = phoneLabel;
|
||||
this.contactUri = contactUri;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -149,21 +149,6 @@ public class SmsDatabase extends MessagingDatabase {
|
||||
}
|
||||
}
|
||||
|
||||
public int getMessageCount() {
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
Cursor cursor = null;
|
||||
|
||||
try {
|
||||
cursor = db.query(TABLE_NAME, new String[] {"COUNT(*)"}, null, null, null, null, null);
|
||||
|
||||
if (cursor != null && cursor.moveToFirst()) return cursor.getInt(0);
|
||||
else return 0;
|
||||
} finally {
|
||||
if (cursor != null)
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
public int getMessageCountForThread(long threadId) {
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
Cursor cursor = null;
|
||||
@ -182,95 +167,18 @@ public class SmsDatabase extends MessagingDatabase {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public long getIDForMessageAtIndex(long threadID, int index) {
|
||||
SQLiteDatabase database = databaseHelper.getReadableDatabase();
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
cursor = database.query(TABLE_NAME, null, THREAD_ID + " = ?", new String[] { threadID + "" }, null, null, null);
|
||||
if (cursor != null && cursor.moveToPosition(index)) {
|
||||
return cursor.getLong(0);
|
||||
}
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public Set<Long> getAllMessageIDs(long threadID) {
|
||||
SQLiteDatabase database = databaseHelper.getReadableDatabase();
|
||||
Cursor cursor = null;
|
||||
Set<Long> messageIDs = new HashSet<>();
|
||||
try {
|
||||
cursor = database.query(TABLE_NAME, null, THREAD_ID + " = ?", new String[] { threadID + "" }, null, null, null);
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
messageIDs.add(cursor.getLong(0));
|
||||
}
|
||||
} finally {
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
return messageIDs;
|
||||
}
|
||||
|
||||
public void markAsEndSession(long id) {
|
||||
updateTypeBitmask(id, Types.KEY_EXCHANGE_MASK, Types.END_SESSION_BIT);
|
||||
}
|
||||
|
||||
public void markAsPreKeyBundle(long id) {
|
||||
updateTypeBitmask(id, Types.KEY_EXCHANGE_MASK, Types.KEY_EXCHANGE_BIT | Types.KEY_EXCHANGE_BUNDLE_BIT);
|
||||
}
|
||||
|
||||
public void markAsInvalidVersionKeyExchange(long id) {
|
||||
updateTypeBitmask(id, 0, Types.KEY_EXCHANGE_INVALID_VERSION_BIT);
|
||||
}
|
||||
|
||||
public void markAsSecure(long id) {
|
||||
updateTypeBitmask(id, 0, Types.SECURE_MESSAGE_BIT);
|
||||
}
|
||||
|
||||
public void markAsInsecure(long id) {
|
||||
updateTypeBitmask(id, Types.SECURE_MESSAGE_BIT, 0);
|
||||
}
|
||||
|
||||
public void markAsPush(long id) {
|
||||
updateTypeBitmask(id, 0, Types.PUSH_MESSAGE_BIT);
|
||||
}
|
||||
|
||||
public void markAsForcedSms(long id) {
|
||||
updateTypeBitmask(id, Types.PUSH_MESSAGE_BIT, Types.MESSAGE_FORCE_SMS_BIT);
|
||||
}
|
||||
|
||||
public void markAsDecryptFailed(long id) {
|
||||
updateTypeBitmask(id, Types.ENCRYPTION_MASK, Types.ENCRYPTION_REMOTE_FAILED_BIT);
|
||||
}
|
||||
|
||||
public void markAsDecryptDuplicate(long id) {
|
||||
updateTypeBitmask(id, Types.ENCRYPTION_MASK, Types.ENCRYPTION_REMOTE_DUPLICATE_BIT);
|
||||
}
|
||||
|
||||
public void markAsNoSession(long id) {
|
||||
updateTypeBitmask(id, Types.ENCRYPTION_MASK, Types.ENCRYPTION_REMOTE_NO_SESSION_BIT);
|
||||
}
|
||||
|
||||
public void markAsSentLokiSessionRestorationRequest(long id) {
|
||||
updateTypeBitmask(id, Types.ENCRYPTION_MASK, Types.ENCRYPTION_LOKI_SESSION_RESTORE_SENT_BIT);
|
||||
}
|
||||
|
||||
public void markAsLokiSessionRestorationDone(long id) {
|
||||
updateTypeBitmask(id, Types.ENCRYPTION_MASK, Types.ENCRYPTION_LOKI_SESSION_RESTORE_DONE_BIT);
|
||||
}
|
||||
|
||||
public void markAsLegacyVersion(long id) {
|
||||
updateTypeBitmask(id, Types.ENCRYPTION_MASK, Types.ENCRYPTION_REMOTE_LEGACY_BIT);
|
||||
}
|
||||
|
||||
public void markAsOutbox(long id) {
|
||||
updateTypeBitmask(id, Types.BASE_TYPE_MASK, Types.BASE_OUTBOX_TYPE);
|
||||
}
|
||||
|
||||
public void markAsPendingInsecureSmsFallback(long id) {
|
||||
updateTypeBitmask(id, Types.BASE_TYPE_MASK, Types.BASE_PENDING_INSECURE_SMS_FALLBACK);
|
||||
}
|
||||
@ -284,10 +192,6 @@ public class SmsDatabase extends MessagingDatabase {
|
||||
updateTypeBitmask(id, Types.BASE_TYPE_MASK, Types.BASE_SENDING_TYPE);
|
||||
}
|
||||
|
||||
public void markAsMissedCall(long id) {
|
||||
updateTypeBitmask(id, Types.TOTAL_MASK, Types.MISSED_CALL_TYPE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markUnidentified(long id, boolean unidentified) {
|
||||
ContentValues contentValues = new ContentValues(1);
|
||||
@ -316,19 +220,6 @@ public class SmsDatabase extends MessagingDatabase {
|
||||
notifyConversationListeners(threadId);
|
||||
}
|
||||
|
||||
public void markStatus(long id, int status) {
|
||||
Log.i("MessageDatabase", "Updating ID: " + id + " to status: " + status);
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(STATUS, status);
|
||||
|
||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||
db.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {id+""});
|
||||
|
||||
long threadId = getThreadIdForMessage(id);
|
||||
DatabaseFactory.getThreadDatabase(context).update(threadId, false);
|
||||
notifyConversationListeners(threadId);
|
||||
}
|
||||
|
||||
public void markAsSentFailed(long id) {
|
||||
updateTypeBitmask(id, Types.BASE_TYPE_MASK, Types.BASE_SENT_FAILED_TYPE);
|
||||
}
|
||||
@ -406,50 +297,6 @@ public class SmsDatabase extends MessagingDatabase {
|
||||
}
|
||||
}
|
||||
|
||||
public List<Pair<Long, Long>> setTimestampRead(SyncMessageId messageId, long proposedExpireStarted) {
|
||||
SQLiteDatabase database = databaseHelper.getWritableDatabase();
|
||||
List<Pair<Long, Long>> expiring = new LinkedList<>();
|
||||
Cursor cursor = null;
|
||||
|
||||
try {
|
||||
cursor = database.query(TABLE_NAME, new String[] {ID, THREAD_ID, ADDRESS, TYPE, EXPIRES_IN, EXPIRE_STARTED},
|
||||
DATE_SENT + " = ?", new String[] {String.valueOf(messageId.getTimetamp())},
|
||||
null, null, null, null);
|
||||
|
||||
while (cursor.moveToNext()) {
|
||||
Address theirAddress = messageId.getAddress();
|
||||
Address ourAddress = Address.fromSerialized(cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS)));
|
||||
|
||||
if (ourAddress.equals(theirAddress)) {
|
||||
long id = cursor.getLong(cursor.getColumnIndexOrThrow(ID));
|
||||
long threadId = cursor.getLong(cursor.getColumnIndexOrThrow(THREAD_ID));
|
||||
long expiresIn = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRES_IN));
|
||||
long expireStarted = cursor.getLong(cursor.getColumnIndexOrThrow(EXPIRE_STARTED));
|
||||
|
||||
expireStarted = expireStarted > 0 ? Math.min(proposedExpireStarted, expireStarted) : proposedExpireStarted;
|
||||
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(READ, 1);
|
||||
|
||||
if (expiresIn > 0) {
|
||||
contentValues.put(EXPIRE_STARTED, expireStarted);
|
||||
expiring.add(new Pair<>(id, expiresIn));
|
||||
}
|
||||
|
||||
database.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {cursor.getLong(cursor.getColumnIndexOrThrow(ID)) + ""});
|
||||
|
||||
DatabaseFactory.getThreadDatabase(context).updateReadState(threadId);
|
||||
DatabaseFactory.getThreadDatabase(context).setLastSeen(threadId);
|
||||
notifyConversationListeners(threadId);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (cursor != null) cursor.close();
|
||||
}
|
||||
|
||||
return expiring;
|
||||
}
|
||||
|
||||
public List<MarkedMessageInfo> setMessagesRead(long threadId) {
|
||||
return setMessagesRead(THREAD_ID + " = ? AND " + READ + " = 0", new String[] {String.valueOf(threadId)});
|
||||
}
|
||||
@ -494,11 +341,6 @@ public class SmsDatabase extends MessagingDatabase {
|
||||
return updateMessageBodyAndType(messageId, body, Types.TOTAL_MASK, type);
|
||||
}
|
||||
|
||||
public void updateMessageBody(long messageId, String body) {
|
||||
long type = 0;
|
||||
updateMessageBodyAndType(messageId, body, Types.ENCRYPTION_MASK, type);
|
||||
}
|
||||
|
||||
private Pair<Long, Long> updateMessageBodyAndType(long messageId, String body, long maskOff, long maskOn) {
|
||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||
db.execSQL("UPDATE " + TABLE_NAME + " SET " + BODY + " = ?, " +
|
||||
@ -515,75 +357,6 @@ public class SmsDatabase extends MessagingDatabase {
|
||||
return new Pair<>(messageId, threadId);
|
||||
}
|
||||
|
||||
public Pair<Long, Long> copyMessageInbox(long messageId) {
|
||||
try {
|
||||
SmsMessageRecord record = getMessage(messageId);
|
||||
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(TYPE, (record.getType() & ~Types.BASE_TYPE_MASK) | Types.BASE_INBOX_TYPE);
|
||||
contentValues.put(ADDRESS, record.getIndividualRecipient().getAddress().serialize());
|
||||
contentValues.put(ADDRESS_DEVICE_ID, record.getRecipientDeviceId());
|
||||
contentValues.put(DATE_RECEIVED, System.currentTimeMillis());
|
||||
contentValues.put(DATE_SENT, record.getDateSent());
|
||||
contentValues.put(PROTOCOL, 31337);
|
||||
contentValues.put(READ, 0);
|
||||
contentValues.put(BODY, record.getBody());
|
||||
contentValues.put(THREAD_ID, record.getThreadId());
|
||||
contentValues.put(EXPIRES_IN, record.getExpiresIn());
|
||||
|
||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||
long newMessageId = db.insert(TABLE_NAME, null, contentValues);
|
||||
|
||||
DatabaseFactory.getThreadDatabase(context).update(record.getThreadId(), true);
|
||||
notifyConversationListeners(record.getThreadId());
|
||||
|
||||
ApplicationContext.getInstance(context).getJobManager().add(new TrimThreadJob(record.getThreadId()));
|
||||
|
||||
return new Pair<>(newMessageId, record.getThreadId());
|
||||
} catch (NoSuchMessageException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public @NonNull Pair<Long, Long> insertReceivedCall(@NonNull Address address) {
|
||||
return insertCallLog(address, Types.INCOMING_CALL_TYPE, false);
|
||||
}
|
||||
|
||||
public @NonNull Pair<Long, Long> insertOutgoingCall(@NonNull Address address) {
|
||||
return insertCallLog(address, Types.OUTGOING_CALL_TYPE, false);
|
||||
}
|
||||
|
||||
public @NonNull Pair<Long, Long> insertMissedCall(@NonNull Address address) {
|
||||
return insertCallLog(address, Types.MISSED_CALL_TYPE, true);
|
||||
}
|
||||
|
||||
private @NonNull Pair<Long, Long> insertCallLog(@NonNull Address address, long type, boolean unread) {
|
||||
Recipient recipient = Recipient.from(context, address, true);
|
||||
long threadId = DatabaseFactory.getThreadDatabase(context).getOrCreateThreadIdFor(recipient);
|
||||
|
||||
ContentValues values = new ContentValues(6);
|
||||
values.put(ADDRESS, address.serialize());
|
||||
values.put(ADDRESS_DEVICE_ID, 1);
|
||||
values.put(DATE_RECEIVED, System.currentTimeMillis());
|
||||
values.put(DATE_SENT, System.currentTimeMillis());
|
||||
values.put(READ, unread ? 0 : 1);
|
||||
values.put(TYPE, type);
|
||||
values.put(THREAD_ID, threadId);
|
||||
|
||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||
long messageId = db.insert(TABLE_NAME, null, values);
|
||||
|
||||
DatabaseFactory.getThreadDatabase(context).update(threadId, true);
|
||||
notifyConversationListeners(threadId);
|
||||
ApplicationContext.getInstance(context).getJobManager().add(new TrimThreadJob(threadId));
|
||||
|
||||
if (unread) {
|
||||
DatabaseFactory.getThreadDatabase(context).incrementUnread(threadId, 1);
|
||||
}
|
||||
|
||||
return new Pair<>(messageId, threadId);
|
||||
}
|
||||
|
||||
protected Optional<InsertResult> insertMessageInbox(IncomingTextMessage message, long type, long serverTimestamp) {
|
||||
if (message.isJoined()) {
|
||||
type = (type & (Types.TOTAL_MASK - Types.BASE_TYPE_MASK)) | Types.JOINED_TYPE;
|
||||
@ -750,17 +523,6 @@ public class SmsDatabase extends MessagingDatabase {
|
||||
return messageId;
|
||||
}
|
||||
|
||||
Cursor getMessages(int skip, int limit) {
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
return db.query(TABLE_NAME, MESSAGE_PROJECTION, null, null, null, null, ID, skip + "," + limit);
|
||||
}
|
||||
|
||||
Cursor getOutgoingMessages() {
|
||||
String outgoingSelection = TYPE + " & " + Types.BASE_TYPE_MASK + " = " + Types.BASE_OUTBOX_TYPE;
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
return db.query(TABLE_NAME, MESSAGE_PROJECTION, outgoingSelection, null, null, null, null);
|
||||
}
|
||||
|
||||
public Cursor getExpirationStartedMessages() {
|
||||
String where = EXPIRE_STARTED + " > 0";
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
@ -796,10 +558,6 @@ public class SmsDatabase extends MessagingDatabase {
|
||||
return threadDeleted;
|
||||
}
|
||||
|
||||
public void ensureMigration() {
|
||||
databaseHelper.getWritableDatabase();
|
||||
}
|
||||
|
||||
private boolean isDuplicate(IncomingTextMessage message, long threadId) {
|
||||
SQLiteDatabase database = databaseHelper.getReadableDatabase();
|
||||
Cursor cursor = database.query(TABLE_NAME, null, DATE_SENT + " = ? AND " + ADDRESS + " = ? AND " + THREAD_ID + " = ?",
|
||||
|
@ -1,275 +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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
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 net.sqlcipher.database.SQLiteDatabase;
|
||||
import net.sqlcipher.database.SQLiteStatement;
|
||||
|
||||
import org.session.libsignal.utilities.logging.Log;
|
||||
import org.session.libsession.messaging.threads.Address;
|
||||
import org.session.libsession.messaging.threads.recipients.Recipient;
|
||||
import org.session.libsession.utilities.TextSecurePreferences;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
public class SmsMigrator {
|
||||
|
||||
private static final String TAG = SmsMigrator.class.getSimpleName();
|
||||
|
||||
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, SmsDatabase.Types.BASE_INBOX_TYPE);
|
||||
} else {
|
||||
long theirType = cursor.getLong(columnIndex);
|
||||
statement.bindLong(index, SmsDatabase.Types.translateFromSystemBaseType(theirType));
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isAppropriateTypeForMigration(Cursor cursor, int columnIndex) {
|
||||
long systemType = cursor.getLong(columnIndex);
|
||||
long ourType = SmsDatabase.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 theirAddress = cursor.getString(cursor.getColumnIndexOrThrow(SmsDatabase.ADDRESS));
|
||||
statement.bindString(1, Address.fromExternal(context, theirAddress).serialize());
|
||||
|
||||
addIntToStatement(statement, cursor, 2, SmsDatabase.PERSON);
|
||||
addIntToStatement(statement, cursor, 3, SmsDatabase.DATE_RECEIVED);
|
||||
addIntToStatement(statement, cursor, 4, SmsDatabase.DATE_RECEIVED);
|
||||
addIntToStatement(statement, cursor, 5, SmsDatabase.PROTOCOL);
|
||||
addIntToStatement(statement, cursor, 6, SmsDatabase.READ);
|
||||
addIntToStatement(statement, cursor, 7, SmsDatabase.STATUS);
|
||||
addTranslatedTypeToStatement(statement, cursor, 8, SmsDatabase.TYPE);
|
||||
addIntToStatement(statement, cursor, 9, SmsDatabase.REPLY_PATH_PRESENT);
|
||||
addStringToStatement(statement, cursor, 10, SmsDatabase.SUBJECT);
|
||||
addStringToStatement(statement, cursor, 11, SmsDatabase.BODY);
|
||||
addStringToStatement(statement, cursor, 12, SmsDatabase.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("SmsMigrator", iae);
|
||||
return null;
|
||||
} finally {
|
||||
if (cursor != null)
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
private static @Nullable Set<Recipient> getOurRecipients(Context context, String theirRecipients) {
|
||||
StringTokenizer tokenizer = new StringTokenizer(theirRecipients.trim(), " ");
|
||||
Set<Recipient> recipientList = new HashSet<>();
|
||||
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
String theirRecipientId = tokenizer.nextToken();
|
||||
String address = getTheirCanonicalAddress(context, theirRecipientId);
|
||||
|
||||
if (address != null) {
|
||||
recipientList.add(Recipient.from(context, Address.fromExternal(context, address), true));
|
||||
}
|
||||
}
|
||||
|
||||
if (recipientList.isEmpty()) return null;
|
||||
else return recipientList;
|
||||
}
|
||||
|
||||
private static void migrateConversation(Context context, SmsMigrationProgressListener listener,
|
||||
ProgressDescription progress,
|
||||
long theirThreadId, long ourThreadId)
|
||||
{
|
||||
SmsDatabase ourSmsDatabase = DatabaseFactory.getSmsDatabase(context);
|
||||
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 typeColumn = cursor.getColumnIndex(SmsDatabase.TYPE);
|
||||
|
||||
if (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);
|
||||
DatabaseFactory.getThreadDatabase(context).update(ourThreadId, true);
|
||||
DatabaseFactory.getThreadDatabase(context).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;
|
||||
|
||||
ThreadDatabase threadDatabase = DatabaseFactory.getThreadDatabase(context);
|
||||
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<Recipient> ourRecipients = getOurRecipients(context, theirRecipients);
|
||||
ProgressDescription progress = new ProgressDescription(cursor.getCount(), cursor.getPosition(), 100, 0);
|
||||
|
||||
if (ourRecipients != null) {
|
||||
if (ourRecipients.size() == 1) {
|
||||
long ourThreadId = threadDatabase.getOrCreateThreadIdFor(ourRecipients.iterator().next());
|
||||
migrateConversation(context, listener, progress, theirThreadId, ourThreadId);
|
||||
} else if (ourRecipients.size() > 1) {
|
||||
ourRecipients.add(Recipient.from(context, Address.fromSerialized(TextSecurePreferences.getLocalNumber(context)), true));
|
||||
|
||||
List<Address> memberAddresses = new LinkedList<>();
|
||||
|
||||
for (Recipient recipient : ourRecipients) {
|
||||
memberAddresses.add(recipient.getAddress());
|
||||
}
|
||||
|
||||
String ourGroupId = DatabaseFactory.getGroupDatabase(context).getOrCreateGroupForMembers(memberAddresses, null);
|
||||
Recipient ourGroupRecipient = Recipient.from(context, Address.fromSerialized(ourGroupId), true);
|
||||
long ourThreadId = threadDatabase.getOrCreateThreadIdFor(ourGroupRecipient, ThreadDatabase.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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -265,25 +265,6 @@ public class ThreadDatabase extends Database {
|
||||
}
|
||||
}
|
||||
|
||||
public List<MarkedMessageInfo> setAllThreadsRead() {
|
||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||
ContentValues contentValues = new ContentValues(1);
|
||||
contentValues.put(READ, 1);
|
||||
contentValues.put(UNREAD_COUNT, 0);
|
||||
|
||||
db.update(TABLE_NAME, contentValues, null, null);
|
||||
|
||||
final List<MarkedMessageInfo> smsRecords = DatabaseFactory.getSmsDatabase(context).setAllMessagesRead();
|
||||
final List<MarkedMessageInfo> mmsRecords = DatabaseFactory.getMmsDatabase(context).setAllMessagesRead();
|
||||
|
||||
notifyConversationListListeners();
|
||||
|
||||
return new LinkedList<MarkedMessageInfo>() {{
|
||||
addAll(smsRecords);
|
||||
addAll(mmsRecords);
|
||||
}};
|
||||
}
|
||||
|
||||
public List<MarkedMessageInfo> setRead(long threadId, boolean lastSeen) {
|
||||
ContentValues contentValues = new ContentValues(1);
|
||||
contentValues.put(READ, 1);
|
||||
@ -401,43 +382,6 @@ public class ThreadDatabase extends Database {
|
||||
return db.rawQuery(query, null);
|
||||
}
|
||||
|
||||
public int getArchivedConversationListCount() {
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
Cursor cursor = null;
|
||||
|
||||
try {
|
||||
cursor = db.query(TABLE_NAME, new String[] {"COUNT(*)"}, ARCHIVED + " = ?",
|
||||
new String[] {"1"}, null, null, null);
|
||||
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
return cursor.getInt(0);
|
||||
}
|
||||
|
||||
} finally {
|
||||
if (cursor != null) cursor.close();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void archiveConversation(long threadId) {
|
||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||
ContentValues contentValues = new ContentValues(1);
|
||||
contentValues.put(ARCHIVED, 1);
|
||||
|
||||
db.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {threadId + ""});
|
||||
notifyConversationListListeners();
|
||||
}
|
||||
|
||||
public void unarchiveConversation(long threadId) {
|
||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||
ContentValues contentValues = new ContentValues(1);
|
||||
contentValues.put(ARCHIVED, 0);
|
||||
|
||||
db.update(TABLE_NAME, contentValues, ID_WHERE, new String[] {threadId + ""});
|
||||
notifyConversationListListeners();
|
||||
}
|
||||
|
||||
public void setLastSeen(long threadId) {
|
||||
SQLiteDatabase db = databaseHelper.getWritableDatabase();
|
||||
ContentValues contentValues = new ContentValues(1);
|
||||
@ -471,22 +415,6 @@ public class ThreadDatabase extends Database {
|
||||
notifyConversationListListeners();
|
||||
}
|
||||
|
||||
public void deleteConversations(Set<Long> selectedConversations) {
|
||||
DatabaseFactory.getSmsDatabase(context).deleteThreads(selectedConversations);
|
||||
DatabaseFactory.getMmsDatabase(context).deleteThreads(selectedConversations);
|
||||
DatabaseFactory.getDraftDatabase(context).clearDrafts(selectedConversations);
|
||||
deleteThreads(selectedConversations);
|
||||
notifyConversationListeners(selectedConversations);
|
||||
notifyConversationListListeners();
|
||||
}
|
||||
|
||||
public void deleteAllConversations() {
|
||||
DatabaseFactory.getSmsDatabase(context).deleteAllThreads();
|
||||
DatabaseFactory.getMmsDatabase(context).deleteAllThreads();
|
||||
DatabaseFactory.getDraftDatabase(context).clearAllDrafts();
|
||||
deleteAllThreads();
|
||||
}
|
||||
|
||||
public boolean hasThread(long threadId) {
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
Cursor cursor = db.query(TABLE_NAME, new String[]{ ID }, ID_WHERE, new String[]{ String.valueOf(threadId) }, null, null, null);
|
||||
@ -578,19 +506,6 @@ public class ThreadDatabase extends Database {
|
||||
notifyConversationListeners(threadId);
|
||||
}
|
||||
|
||||
void updateReadState(long threadId) {
|
||||
int unreadCount = DatabaseFactory.getMmsSmsDatabase(context).getUnreadCount(threadId);
|
||||
|
||||
ContentValues contentValues = new ContentValues();
|
||||
contentValues.put(READ, unreadCount == 0);
|
||||
contentValues.put(UNREAD_COUNT, unreadCount);
|
||||
|
||||
databaseHelper.getWritableDatabase().update(TABLE_NAME, contentValues,ID_WHERE,
|
||||
new String[] {String.valueOf(threadId)});
|
||||
|
||||
notifyConversationListListeners();
|
||||
}
|
||||
|
||||
public boolean update(long threadId, boolean unarchive) {
|
||||
MmsSmsDatabase mmsSmsDatabase = DatabaseFactory.getMmsSmsDatabase(context);
|
||||
long count = mmsSmsDatabase.getConversationCount(threadId);
|
||||
@ -624,34 +539,6 @@ public class ThreadDatabase extends Database {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A lightweight utility method to retrieve the complete list of non-archived threads coupled with their recipient address.
|
||||
* @return a tuple with non-null values: thread id, recipient address.
|
||||
*/
|
||||
public @NonNull List<Tuple2<Long, String>> getConversationListQuick() {
|
||||
SQLiteDatabase db = databaseHelper.getReadableDatabase();
|
||||
|
||||
ArrayList<Tuple2<Long, String>> result = new ArrayList<>();
|
||||
|
||||
try (Cursor cursor = db.query(
|
||||
TABLE_NAME,
|
||||
new String[]{ID, ADDRESS},
|
||||
ARCHIVED + " = 0 AND " + MESSAGE_COUNT + " != 0 AND " + ADDRESS + " IS NOT NULL",
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null)) {
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
result.add(new Tuple2<>(
|
||||
cursor.getLong(cursor.getColumnIndexOrThrow(ID)),
|
||||
cursor.getString(cursor.getColumnIndexOrThrow(ADDRESS))
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private @NonNull String getFormattedBodyFor(@NonNull MessageRecord messageRecord) {
|
||||
if (messageRecord.isMms()) {
|
||||
MmsMessageRecord record = (MmsMessageRecord) messageRecord;
|
||||
|
@ -1,221 +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.thoughtcrime.securesms.database.SmsMigrator;
|
||||
import org.thoughtcrime.securesms.database.SmsMigrator.ProgressDescription;
|
||||
import org.thoughtcrime.securesms.loki.activities.HomeActivity;
|
||||
import org.thoughtcrime.securesms.notifications.NotificationChannels;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import network.loki.messenger.R;
|
||||
|
||||
// FIXME: This class is nuts.
|
||||
public class ApplicationMigrationService extends Service
|
||||
implements SmsMigrator.SmsMigrationProgressListener
|
||||
{
|
||||
private static final String TAG = ApplicationMigrationService.class.getSimpleName();
|
||||
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> 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(4242, 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);
|
||||
builder.setContentIntent(PendingIntent.getActivity(this, 0, new Intent(this, HomeActivity.class), 0));
|
||||
|
||||
stopForeground(true);
|
||||
startForeground(4242, 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));
|
||||
builder.setContentIntent(PendingIntent.getActivity(context, 0, new Intent(context, HomeActivity.class), 0));
|
||||
builder.setWhen(System.currentTimeMillis());
|
||||
builder.setDefaults(Notification.DEFAULT_VIBRATE);
|
||||
builder.setAutoCancel(true);
|
||||
|
||||
Notification notification = builder.build();
|
||||
((NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE)).notify(31337, 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();
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user