From 52afcac230e0950d1bd862faab9673deb3899689 Mon Sep 17 00:00:00 2001 From: Daniel Gultsch Date: Thu, 10 Jan 2019 14:52:27 +0100 Subject: [PATCH] mark deleted files in database and not query them when querying for media --- .../crypto/PgpDecryptionService.java | 4 +- .../conversations/entities/Conversation.java | 13 ++++ .../entities/IndividualMessage.java | 7 +- .../siacs/conversations/entities/Message.java | 18 ++++- .../conversations/entities/Transferable.java | 2 - .../http/HttpDownloadConnection.java | 5 +- .../persistance/DatabaseBackend.java | 68 +++++++++++++++++- .../persistance/FileBackend.java | 10 +++ .../services/NotificationService.java | 1 + .../services/XmppConnectionService.java | 72 +++++++++---------- .../ui/ConversationFragment.java | 9 ++- .../ui/adapter/ConversationAdapter.java | 2 +- .../ui/adapter/MessageAdapter.java | 6 +- .../siacs/conversations/utils/UIHelper.java | 6 +- 14 files changed, 162 insertions(+), 61 deletions(-) diff --git a/src/main/java/eu/siacs/conversations/crypto/PgpDecryptionService.java b/src/main/java/eu/siacs/conversations/crypto/PgpDecryptionService.java index 18efe1497a530c7dcdd658f70013f76925b672c3..67075ff1d4ec9923ccd2e5192425a2ad2f1ebf0c 100644 --- a/src/main/java/eu/siacs/conversations/crypto/PgpDecryptionService.java +++ b/src/main/java/eu/siacs/conversations/crypto/PgpDecryptionService.java @@ -209,7 +209,9 @@ public class PgpDecryptionService { URL url = message.getFileParams().url; mXmppConnectionService.getFileBackend().updateFileParams(message, url); message.setEncryption(Message.ENCRYPTION_DECRYPTED); - inputFile.delete(); + if (!inputFile.delete()) { + Log.w(Config.LOGTAG,"unable to delete pgp encrypted source file "+inputFile.getAbsolutePath()); + } mXmppConnectionService.updateMessage(message); skipNotificationPush = true; mXmppConnectionService.getFileBackend().updateMediaScanner(outputFile, () -> notifyIfPending(message)); diff --git a/src/main/java/eu/siacs/conversations/entities/Conversation.java b/src/main/java/eu/siacs/conversations/entities/Conversation.java index 06be3c8f822582954058350d2773cf6da968755c..b0d37706df55e85142ba048c927b4105ace4291f 100644 --- a/src/main/java/eu/siacs/conversations/entities/Conversation.java +++ b/src/main/java/eu/siacs/conversations/entities/Conversation.java @@ -206,6 +206,19 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl return null; } + public boolean markAsDeleted(final List uuids) { + boolean deleted = false; + synchronized (this.messages) { + for(Message message : this.messages) { + if (uuids.contains(message.getUuid())) { + message.setDeleted(true); + deleted = true; + } + } + } + return deleted; + } + public void clearMessages() { synchronized (this.messages) { this.messages.clear(); diff --git a/src/main/java/eu/siacs/conversations/entities/IndividualMessage.java b/src/main/java/eu/siacs/conversations/entities/IndividualMessage.java index 9794376383dc41a73c63e36e6f6a8b928f064697..42496e4eb9eafe9084c2634191c53311bef730e5 100644 --- a/src/main/java/eu/siacs/conversations/entities/IndividualMessage.java +++ b/src/main/java/eu/siacs/conversations/entities/IndividualMessage.java @@ -43,8 +43,8 @@ public class IndividualMessage extends Message { super(conversation); } - private IndividualMessage(Conversational conversation, String uuid, String conversationUUid, Jid counterpart, Jid trueCounterpart, String body, long timeSent, int encryption, int status, int type, boolean carbon, String remoteMsgId, String relativeFilePath, String serverMsgId, String fingerprint, boolean read, String edited, boolean oob, String errorMessage, Set readByMarkers, boolean markable) { - super(conversation, uuid, conversationUUid, counterpart, trueCounterpart, body, timeSent, encryption, status, type, carbon, remoteMsgId, relativeFilePath, serverMsgId, fingerprint, read, edited, oob, errorMessage, readByMarkers, markable); + private IndividualMessage(Conversational conversation, String uuid, String conversationUUid, Jid counterpart, Jid trueCounterpart, String body, long timeSent, int encryption, int status, int type, boolean carbon, String remoteMsgId, String relativeFilePath, String serverMsgId, String fingerprint, boolean read, String edited, boolean oob, String errorMessage, Set readByMarkers, boolean markable, boolean deleted) { + super(conversation, uuid, conversationUUid, counterpart, trueCounterpart, body, timeSent, encryption, status, type, carbon, remoteMsgId, relativeFilePath, serverMsgId, fingerprint, read, edited, oob, errorMessage, readByMarkers, markable, deleted); } @Override @@ -115,6 +115,7 @@ public class IndividualMessage extends Message { cursor.getInt(cursor.getColumnIndex(OOB)) > 0, cursor.getString(cursor.getColumnIndex(ERROR_MESSAGE)), ReadByMarker.fromJsonString(cursor.getString(cursor.getColumnIndex(READ_BY_MARKERS))), - cursor.getInt(cursor.getColumnIndex(MARKABLE)) > 0); + cursor.getInt(cursor.getColumnIndex(MARKABLE)) > 0, + cursor.getInt(cursor.getColumnIndex(DELETED)) > 0); } } diff --git a/src/main/java/eu/siacs/conversations/entities/Message.java b/src/main/java/eu/siacs/conversations/entities/Message.java index fae17458ff455269c0c433d485cf36586709eb80..44ba3627065b6de655f9fe3f29f4d64a81f7543f 100644 --- a/src/main/java/eu/siacs/conversations/entities/Message.java +++ b/src/main/java/eu/siacs/conversations/entities/Message.java @@ -74,6 +74,7 @@ public class Message extends AbstractEntity { public static final String ERROR_MESSAGE = "errorMsg"; public static final String READ_BY_MARKERS = "readByMarkers"; public static final String MARKABLE = "markable"; + public static final String DELETED = "deleted"; public static final String ME_COMMAND = "/me "; public static final String ERROR_MESSAGE_CANCELLED = "eu.siacs.conversations.cancelled"; @@ -89,6 +90,7 @@ public class Message extends AbstractEntity { protected int encryption; protected int status; protected int type; + protected boolean deleted = false; protected boolean carbon = false; protected boolean oob = false; protected List edits = new ArrayList<>(); @@ -139,6 +141,7 @@ public class Message extends AbstractEntity { false, null, null, + false, false); } @@ -148,7 +151,7 @@ public class Message extends AbstractEntity { final String remoteMsgId, final String relativeFilePath, final String serverMsgId, final String fingerprint, final boolean read, final String edited, final boolean oob, final String errorMessage, final Set readByMarkers, - final boolean markable) { + final boolean markable, final boolean deleted) { this.conversation = conversation; this.uuid = uuid; this.conversationUuid = conversationUUid; @@ -170,6 +173,7 @@ public class Message extends AbstractEntity { this.errorMessage = errorMessage; this.readByMarkers = readByMarkers == null ? new HashSet<>() : readByMarkers; this.markable = markable; + this.deleted = deleted; } public static Message fromCursor(Cursor cursor, Conversation conversation) { @@ -217,7 +221,8 @@ public class Message extends AbstractEntity { cursor.getInt(cursor.getColumnIndex(OOB)) > 0, cursor.getString(cursor.getColumnIndex(ERROR_MESSAGE)), ReadByMarker.fromJsonString(cursor.getString(cursor.getColumnIndex(READ_BY_MARKERS))), - cursor.getInt(cursor.getColumnIndex(MARKABLE)) > 0); + cursor.getInt(cursor.getColumnIndex(MARKABLE)) > 0, + cursor.getInt(cursor.getColumnIndex(DELETED)) > 0); } public static Message createStatusMessage(Conversation conversation, String body) { @@ -270,6 +275,7 @@ public class Message extends AbstractEntity { values.put(ERROR_MESSAGE, errorMessage); values.put(READ_BY_MARKERS, ReadByMarker.toJson(readByMarkers).toString()); values.put(MARKABLE, markable ? 1 : 0); + values.put(DELETED, deleted ? 1 : 0); return values; } @@ -386,6 +392,14 @@ public class Message extends AbstractEntity { return this.read; } + public boolean isDeleted() { + return this.deleted; + } + + public void setDeleted(boolean deleted) { + this.deleted = deleted; + } + public void markRead() { this.read = true; } diff --git a/src/main/java/eu/siacs/conversations/entities/Transferable.java b/src/main/java/eu/siacs/conversations/entities/Transferable.java index 204c702404790f05691a895614b94dc4d988d33e..df18f3a2d89220c2e4979eb77d083d4bd4953a2d 100644 --- a/src/main/java/eu/siacs/conversations/entities/Transferable.java +++ b/src/main/java/eu/siacs/conversations/entities/Transferable.java @@ -7,14 +7,12 @@ public interface Transferable { List VALID_IMAGE_EXTENSIONS = Arrays.asList("webp", "jpeg", "jpg", "png", "jpe"); List VALID_CRYPTO_EXTENSIONS = Arrays.asList("pgp", "gpg"); - List WELL_KNOWN_EXTENSIONS = Arrays.asList("pdf","m4a","mp4","3gp","aac","amr","mp3"); int STATUS_UNKNOWN = 0x200; int STATUS_CHECKING = 0x201; int STATUS_FAILED = 0x202; int STATUS_OFFER = 0x203; int STATUS_DOWNLOADING = 0x204; - int STATUS_DELETED = 0x205; int STATUS_OFFER_CHECK_FILESIZE = 0x206; int STATUS_UPLOADING = 0x207; diff --git a/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java b/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java index ec99a44ac4bc5f1054d09c70c0bf3fddaf7e480e..9dc233fc21608d094ee9d3cb65c55195d8c67863 100644 --- a/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java +++ b/src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java @@ -131,10 +131,9 @@ public class HttpDownloadConnection implements Transferable { public void cancel() { this.canceled = true; mHttpConnectionManager.finishConnection(this); + message.setTransferable(null); if (message.isFileOrImage()) { - message.setTransferable(new TransferablePlaceholder(Transferable.STATUS_DELETED)); - } else { - message.setTransferable(null); + message.setDeleted(true); } mHttpConnectionManager.updateConversationUi(true); } diff --git a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java index 2962d41c72065dd8069d03d29349f68cf5e71f98..8dcd8a9d487672d5ca1fcb20d4b03039bd29d2f2 100644 --- a/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java +++ b/src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java @@ -28,6 +28,7 @@ import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -63,7 +64,7 @@ import rocks.xmpp.addr.Jid; public class DatabaseBackend extends SQLiteOpenHelper { private static final String DATABASE_NAME = "history"; - private static final int DATABASE_VERSION = 43; + private static final int DATABASE_VERSION = 44; private static DatabaseBackend instance = null; private static String CREATE_CONTATCS_STATEMENT = "create table " + Contact.TABLENAME + "(" + Contact.ACCOUNT + " TEXT, " @@ -165,6 +166,9 @@ public class DatabaseBackend extends SQLiteOpenHelper { private static String CREATE_MESSAGE_TIME_INDEX = "create INDEX message_time_index ON " + Message.TABLENAME + "(" + Message.TIME_SENT + ")"; private static String CREATE_MESSAGE_CONVERSATION_INDEX = "create INDEX message_conversation_index ON " + Message.TABLENAME + "(" + Message.CONVERSATION + ")"; + private static String CREATE_MESSAGE_DELETED_INDEX = "create index message_deleted_index ON "+ Message.TABLENAME + "(" + Message.DELETED + ")"; + private static String CREATE_MESSAGE_RELATIVE_FILE_PATH_INDEX = "create INDEX message_file_path_index ON " + Message.TABLENAME + "(" + Message.RELATIVE_FILE_PATH + ")"; + private static String CREATE_MESSAGE_TYPE_INDEX = "create INDEX message_type_index ON " + Message.TABLENAME + "(" + Message.TYPE + ")"; private static String CREATE_MESSAGE_INDEX_TABLE = "CREATE VIRTUAL TABLE messages_index USING FTS4(uuid TEXT PRIMARY KEY, body TEXT)"; private static String CREATE_MESSAGE_INSERT_TRIGGER = "CREATE TRIGGER after_message_insert AFTER INSERT ON " + Message.TABLENAME + " BEGIN INSERT INTO messages_index (uuid,body) VALUES (new.uuid,new.body); END;"; @@ -236,12 +240,16 @@ public class DatabaseBackend extends SQLiteOpenHelper { + Message.ERROR_MESSAGE + " TEXT," + Message.READ_BY_MARKERS + " TEXT," + Message.MARKABLE + " NUMBER DEFAULT 0," + + Message.DELETED + " NUMBER DEFAULT 0," + Message.REMOTE_MSG_ID + " TEXT, FOREIGN KEY(" + Message.CONVERSATION + ") REFERENCES " + Conversation.TABLENAME + "(" + Conversation.UUID + ") ON DELETE CASCADE);"); db.execSQL(CREATE_MESSAGE_TIME_INDEX); db.execSQL(CREATE_MESSAGE_CONVERSATION_INDEX); + db.execSQL(CREATE_MESSAGE_DELETED_INDEX); + db.execSQL(CREATE_MESSAGE_RELATIVE_FILE_PATH_INDEX); + db.execSQL(CREATE_MESSAGE_TYPE_INDEX); db.execSQL(CREATE_CONTATCS_STATEMENT); db.execSQL(CREATE_DISCOVERY_RESULTS_STATEMENT); db.execSQL(CREATE_SESSIONS_STATEMENT); @@ -527,6 +535,13 @@ public class DatabaseBackend extends SQLiteOpenHelper { + "=?", new String[]{account.getUuid()}); } } + + if (oldVersion < 44 && newVersion >= 44) { + db.execSQL("ALTER TABLE " + Message.TABLENAME + " ADD COLUMN " + Message.DELETED + " NUMBER DEFAULT 0"); + db.execSQL(CREATE_MESSAGE_DELETED_INDEX); + db.execSQL(CREATE_MESSAGE_RELATIVE_FILE_PATH_INDEX); + db.execSQL(CREATE_MESSAGE_TYPE_INDEX); + } } private void canonicalizeJids(SQLiteDatabase db) { @@ -790,9 +805,58 @@ public class DatabaseBackend extends SQLiteOpenHelper { }; } + public List markFileAsDeleted(final File file, final boolean internal) { + SQLiteDatabase db = this.getReadableDatabase(); + String selection; + String[] selectionArgs; + if (internal) { + selection = Message.RELATIVE_FILE_PATH+" IN(?,?) and type in (1,2)"; + selectionArgs = new String[]{file.getAbsolutePath(),file.getName()}; + } else { + selection = Message.RELATIVE_FILE_PATH+"=? and type in (1,2)"; + selectionArgs = new String[]{file.getAbsolutePath()}; + } + final List uuids = new ArrayList<>(); + Cursor cursor = db.query(Message.TABLENAME,new String[]{Message.UUID},selection,selectionArgs,null,null,null); + while(cursor != null && cursor.moveToNext()) { + uuids.add(cursor.getString(0)); + } + if (cursor != null) { + cursor.close(); + } + markFileAsDeleted(uuids); + return uuids; + } + + public void markFileAsDeleted(List uuids) { + SQLiteDatabase db = this.getReadableDatabase(); + final ContentValues contentValues = new ContentValues(); + final String where = Message.UUID+"=?"; + contentValues.put(Message.DELETED,1); + db.beginTransaction(); + for(String uuid : uuids) { + db.update(Message.TABLENAME, contentValues, where, new String[]{uuid}); + } + db.setTransactionSuccessful(); + db.endTransaction(); + } + + public List getAllNonDeletedFilePath() { + final SQLiteDatabase db = this.getReadableDatabase(); + final Cursor cursor = db.query(Message.TABLENAME,new String[]{Message.UUID,Message.RELATIVE_FILE_PATH},"type in (1,2) and deleted=0",null,null,null,null); + final List list = new ArrayList<>(); + while (cursor != null && cursor.moveToNext()) { + list.add(new FilePath(cursor.getString(0),cursor.getString(1))); + } + if (cursor != null) { + cursor.close(); + } + return list; + } + public List getRelativeFilePaths(String account, Jid jid, int limit) { SQLiteDatabase db = this.getReadableDatabase(); - final String SQL = "select uuid,relativeFilePath from messages where type in (1,2) and conversationUuid=(select uuid from conversations where accountUuid=? and (contactJid=? or contactJid like ?)) order by timeSent desc"; + final String SQL = "select uuid,relativeFilePath from messages where type in (1,2) and deleted=0 and conversationUuid=(select uuid from conversations where accountUuid=? and (contactJid=? or contactJid like ?)) order by timeSent desc"; final String[] args = {account, jid.toEscapedString(), jid.toEscapedString()+"/%"}; Cursor cursor = db.rawQuery(SQL+(limit > 0 ? " limit "+String.valueOf(limit) : ""), args); List filesPaths = new ArrayList<>(); diff --git a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java index 9bdcc0a18191833453311e65cc864f772e4be415..012ad119166b7c059559ae89d24f986d090077b1 100644 --- a/src/main/java/eu/siacs/conversations/persistance/FileBackend.java +++ b/src/main/java/eu/siacs/conversations/persistance/FileBackend.java @@ -473,6 +473,10 @@ public class FileBackend { return getFile(message, true); } + public DownloadableFile getFileForPath(String path) { + return getFileForPath(path,MimeUtils.guessMimeTypeFromExtension(MimeUtils.extractRelevantExtension(path))); + } + public DownloadableFile getFileForPath(String path, String mime) { final DownloadableFile file; if (path.startsWith("/")) { @@ -489,6 +493,11 @@ public class FileBackend { return file; } + public boolean isInternalFile(final File file) { + final File internalFile = getFileForPath(file.getName()); + return file.getAbsolutePath().equals(internalFile.getAbsolutePath()); + } + public DownloadableFile getFile(Message message, boolean decrypted) { final boolean encrypted = !decrypted && (message.getEncryption() == Message.ENCRYPTION_PGP @@ -1187,6 +1196,7 @@ public class FileBackend { body.append("|0|0|").append(getMediaRuntime(file)); } message.setBody(body.toString()); + message.setDeleted(false); } public int getMediaRuntime(Uri uri) { diff --git a/src/main/java/eu/siacs/conversations/services/NotificationService.java b/src/main/java/eu/siacs/conversations/services/NotificationService.java index 60f503cabb550c546b5baa2937bc684df396c378..1ea7b18f9408e111f569d954498969eeec84fe4f 100644 --- a/src/main/java/eu/siacs/conversations/services/NotificationService.java +++ b/src/main/java/eu/siacs/conversations/services/NotificationService.java @@ -726,6 +726,7 @@ public class NotificationService { private static boolean isImageMessage(Message message) { return message.getType() != Message.TYPE_TEXT && message.getTransferable() == null + && !message.isDeleted() && message.getEncryption() != Message.ENCRYPTION_PGP && message.getFileParams().height > 0; } diff --git a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java index 2708ea386f6aab0d7b1718ed167351844ef67be1..99484bd0c1d5b46f9ef9021a2adb33074507788f 100644 --- a/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java +++ b/src/main/java/eu/siacs/conversations/services/XmppConnectionService.java @@ -45,6 +45,7 @@ import org.openintents.openpgp.IOpenPgpService2; import org.openintents.openpgp.util.OpenPgpApi; import org.openintents.openpgp.util.OpenPgpServiceConnection; +import java.io.File; import java.net.URL; import java.security.SecureRandom; import java.security.Security; @@ -84,7 +85,6 @@ import eu.siacs.conversations.entities.Bookmark; import eu.siacs.conversations.entities.Contact; import eu.siacs.conversations.entities.Conversation; import eu.siacs.conversations.entities.Conversational; -import eu.siacs.conversations.entities.DownloadableFile; import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.MucOptions; import eu.siacs.conversations.entities.MucOptions.OnRenameListener; @@ -92,8 +92,6 @@ import eu.siacs.conversations.entities.Presence; import eu.siacs.conversations.entities.PresenceTemplate; import eu.siacs.conversations.entities.Roster; import eu.siacs.conversations.entities.ServiceDiscoveryResult; -import eu.siacs.conversations.entities.Transferable; -import eu.siacs.conversations.entities.TransferablePlaceholder; import eu.siacs.conversations.generator.AbstractGenerator; import eu.siacs.conversations.generator.IqGenerator; import eu.siacs.conversations.generator.MessageGenerator; @@ -235,7 +233,6 @@ public class XmppConnectionService extends Service { ) { @Override public void onEvent(int event, String path) { - Log.d(Config.LOGTAG,"event "+event+" path="+path); markFileDeleted(path); } }; @@ -1010,6 +1007,7 @@ public class XmppConnectionService extends Service { if (Compatibility.hasStoragePermission(this)) { Log.d(Config.LOGTAG, "starting file observer"); new Thread(fileObserver::startWatching).start(); + mFileAddingExecutor.execute(this::checkForDeletedFiles); } if (Config.supportOpenPgp()) { this.pgpServiceConnection = new OpenPgpServiceConnection(this, "org.sufficientlysecure.keychain", new OpenPgpServiceConnection.OnBound() { @@ -1047,6 +1045,22 @@ public class XmppConnectionService extends Service { } } + private void checkForDeletedFiles() { + final List deletedUuids = new ArrayList<>(); + final List relativeFilePaths = databaseBackend.getAllNonDeletedFilePath(); + for(final DatabaseBackend.FilePath filePath : relativeFilePaths) { + final File file = fileBackend.getFileForPath(filePath.path); + if (!file.exists()) { + deletedUuids.add(filePath.uuid.toString()); + } + } + Log.d(Config.LOGTAG,"found "+deletedUuids.size()+" deleted files on start up. total="+relativeFilePaths.size()); + if (deletedUuids.size() > 0) { + databaseBackend.markFileAsDeleted(deletedUuids); + markUuidsAsDeletedFiles(deletedUuids); + } + } + public void startContactObserver() { getContentResolver().registerContentObserver(ContactsContract.Contacts.CONTENT_URI, true, new ContentObserver(null) { @Override @@ -1081,6 +1095,7 @@ public class XmppConnectionService extends Service { public void restartFileObserver() { Log.d(Config.LOGTAG, "restarting file observer"); + mFileAddingExecutor.execute(this::checkForDeletedFiles); new Thread(fileObserver::restartWatching).start(); } @@ -1575,7 +1590,6 @@ public class XmppConnectionService extends Service { private void restoreMessages(Conversation conversation) { conversation.addAll(0, databaseBackend.getMessages(conversation, Config.PAGE_SIZE)); - checkDeletedFiles(conversation); conversation.findUnsentTextMessages(message -> markMessage(message, Message.STATUS_WAITING)); conversation.findUnreadMessages(message -> mNotificationService.pushFromBacklog(message)); } @@ -1617,40 +1631,24 @@ public class XmppConnectionService extends Service { return this.conversations; } - private void checkDeletedFiles(Conversation conversation) { - conversation.findMessagesWithFiles(message -> { - if (!getFileBackend().isFileAvailable(message)) { - message.setTransferable(new TransferablePlaceholder(Transferable.STATUS_DELETED)); - final int s = message.getStatus(); - if (s == Message.STATUS_WAITING || s == Message.STATUS_OFFERED || s == Message.STATUS_UNSEND) { - markMessage(message, Message.STATUS_SEND_FAILED); - } - } - }); - } - private void markFileDeleted(final String path) { - Log.d(Config.LOGTAG, "deleted file " + path); - for (Conversation conversation : getConversations()) { - conversation.findMessagesWithFiles(message -> { - DownloadableFile file = fileBackend.getFile(message); - if (file.getAbsolutePath().equals(path)) { - if (!file.exists()) { - message.setTransferable(new TransferablePlaceholder(Transferable.STATUS_DELETED)); - final int s = message.getStatus(); - if (s == Message.STATUS_WAITING || s == Message.STATUS_OFFERED || s == Message.STATUS_UNSEND) { - markMessage(message, Message.STATUS_SEND_FAILED); - } else { - updateConversationUi(); - } - } else { - Log.d(Config.LOGTAG, "found matching message for file " + path + " but file still exists"); - } - } - }); - } + final File file = new File(path); + final boolean isInternalFile = fileBackend.isInternalFile(file); + final List uuids = databaseBackend.markFileAsDeleted(file, isInternalFile); + Log.d(Config.LOGTAG, "deleted file " + path+" internal="+isInternalFile+", database hits="+uuids.size()); + markUuidsAsDeletedFiles(uuids); } + private void markUuidsAsDeletedFiles(List uuids) { + boolean deleted = false; + for (Conversation conversation : getConversations()) { + deleted |= conversation.markAsDeleted(uuids); + } + if (deleted) { + updateConversationUi(); + } + } + public void populateWithOrderedConversations(final List list) { populateWithOrderedConversations(list, true); } @@ -1686,7 +1684,6 @@ public class XmppConnectionService extends Service { List messages = databaseBackend.getMessages(conversation, 50, timestamp); if (messages.size() > 0) { conversation.addAll(0, messages); - checkDeletedFiles(conversation); callback.onMoreMessagesLoaded(messages.size(), conversation); } else if (conversation.hasMessagesLeftOnServer() && account.isOnlineAndConnected() @@ -1835,7 +1832,6 @@ public class XmppConnectionService extends Service { } } } - checkDeletedFiles(c); if (joinAfterCreate) { joinMuc(c); } diff --git a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java index d70bfe6b6c75f4432f0efe75a443ce1d3340b242..d5156b1acef1139d94c793c5c9a7da0e9ba0b99f 100644 --- a/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java +++ b/src/main/java/eu/siacs/conversations/ui/ConversationFragment.java @@ -1059,7 +1059,7 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke return; } - final boolean deleted = t != null && t instanceof TransferablePlaceholder; + final boolean deleted = m.isDeleted(); final boolean encrypted = m.getEncryption() == Message.ENCRYPTION_DECRYPTION_FAILED || m.getEncryption() == Message.ENCRYPTION_PGP; final boolean receiving = m.getStatus() == Message.STATUS_RECEIVED && (t instanceof JingleConnection || t instanceof HttpDownloadConnection); @@ -1638,7 +1638,8 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke builder.setMessage(R.string.delete_file_dialog_msg); builder.setPositiveButton(R.string.confirm, (dialog, which) -> { if (activity.xmppConnectionService.getFileBackend().deleteFile(message)) { - message.setTransferable(new TransferablePlaceholder(Transferable.STATUS_DELETED)); + message.setDeleted(true); + activity.xmppConnectionService.updateMessage(message, false); activity.onConversationsListItemUpdated(); refresh(); } @@ -1672,7 +1673,9 @@ public class ConversationFragment extends XmppFragment implements EditMessage.Ke } } else { Toast.makeText(activity, R.string.file_deleted, Toast.LENGTH_SHORT).show(); - message.setTransferable(new TransferablePlaceholder(Transferable.STATUS_DELETED)); + //TODO check if we have storage permission + message.setDeleted(true); + activity.xmppConnectionService.updateMessage(message, false); activity.onConversationsListItemUpdated(); refresh(); return; diff --git a/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java b/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java index 8e53caea6aaedb965ff5b73dd71b76d969448dae..39bb3ba32bd0e18328de178b6017d62f04750cbe 100644 --- a/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java +++ b/src/main/java/eu/siacs/conversations/ui/adapter/ConversationAdapter.java @@ -122,7 +122,7 @@ public class ConversationAdapter extends RecyclerView.Adapter implements CopyTextVie }); final Transferable transferable = message.getTransferable(); - if (transferable != null && transferable.getStatus() != Transferable.STATUS_UPLOADING) { - if (transferable.getStatus() == Transferable.STATUS_OFFER) { + if (message.isDeleted() || (transferable != null && transferable.getStatus() != Transferable.STATUS_UPLOADING)) { + if (transferable != null && transferable.getStatus() == Transferable.STATUS_OFFER) { displayDownloadableMessage(viewHolder, message, activity.getString(R.string.download_x_file, UIHelper.getFileDescriptionString(activity, message))); - } else if (transferable.getStatus() == Transferable.STATUS_OFFER_CHECK_FILESIZE) { + } else if (transferable != null && transferable.getStatus() == Transferable.STATUS_OFFER_CHECK_FILESIZE) { displayDownloadableMessage(viewHolder, message, activity.getString(R.string.check_x_filesize, UIHelper.getFileDescriptionString(activity, message))); } else { displayInfoMessage(viewHolder, UIHelper.getMessagePreview(activity, message).first, darkBackground); diff --git a/src/main/java/eu/siacs/conversations/utils/UIHelper.java b/src/main/java/eu/siacs/conversations/utils/UIHelper.java index d7afd2bbcb58f53906a1e37705ffeb948a8ddaca..5d8098c2b69546995a0f135019819dc2def10fa9 100644 --- a/src/main/java/eu/siacs/conversations/utils/UIHelper.java +++ b/src/main/java/eu/siacs/conversations/utils/UIHelper.java @@ -271,8 +271,6 @@ public class UIHelper { case Transferable.STATUS_OFFER_CHECK_FILESIZE: return new Pair<>(context.getString(R.string.x_file_offered_for_download, getFileDescriptionString(context, message)), true); - case Transferable.STATUS_DELETED: - return new Pair<>(context.getString(R.string.file_deleted), true); case Transferable.STATUS_FAILED: return new Pair<>(context.getString(R.string.file_transmission_failed), true); case Transferable.STATUS_UPLOADING: @@ -286,6 +284,8 @@ public class UIHelper { default: return new Pair<>("", false); } + } else if (message.isFileOrImage() && message.isDeleted()) { + return new Pair<>(context.getString(R.string.file_deleted), true); } else if (message.getEncryption() == Message.ENCRYPTION_PGP) { return new Pair<>(context.getString(R.string.pgp_message), true); } else if (message.getEncryption() == Message.ENCRYPTION_DECRYPTION_FAILED) { @@ -294,7 +294,7 @@ public class UIHelper { return new Pair<>(context.getString(R.string.not_encrypted_for_this_device), true); } else if (message.getEncryption() == Message.ENCRYPTION_AXOLOTL_FAILED) { return new Pair<>(context.getString(R.string.omemo_decryption_failed), true); - } else if (message.getType() == Message.TYPE_FILE || message.getType() == Message.TYPE_IMAGE) { + } else if (message.isFileOrImage()) { return new Pair<>(getFileDescriptionString(context, message), true); } else { final String body = MessageUtils.filterLtrRtl(message.getBody());