refactored deleted file detection to monitor entire sd card. fixes #1968

This commit is contained in:
Daniel Gultsch 2016-07-23 16:12:45 +02:00
parent 3d372cb339
commit 89a05265ea
2 changed files with 95 additions and 19 deletions

View file

@ -18,7 +18,7 @@ import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.FileObserver;
import android.os.Environment;
import android.os.IBinder;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
@ -70,6 +70,7 @@ import eu.siacs.conversations.entities.Blockable;
import eu.siacs.conversations.entities.Bookmark;
import eu.siacs.conversations.entities.Contact;
import eu.siacs.conversations.entities.Conversation;
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;
@ -91,6 +92,7 @@ import eu.siacs.conversations.parser.PresenceParser;
import eu.siacs.conversations.persistance.DatabaseBackend;
import eu.siacs.conversations.persistance.FileBackend;
import eu.siacs.conversations.ui.UiCallback;
import eu.siacs.conversations.utils.ConversationsFileObserver;
import eu.siacs.conversations.utils.CryptoHelper;
import eu.siacs.conversations.utils.ExceptionHelper;
import eu.siacs.conversations.utils.OnPhoneContactsLoadedListener;
@ -211,14 +213,14 @@ public class XmppConnectionService extends Service {
private MessageArchiveService mMessageArchiveService = new MessageArchiveService(this);
private PushManagementService mPushManagementService = new PushManagementService(this);
private OnConversationUpdate mOnConversationUpdate = null;
private final FileObserver fileObserver = new FileObserver(
FileBackend.getConversationsImageDirectory()) {
private final ConversationsFileObserver fileObserver = new ConversationsFileObserver(
Environment.getExternalStorageDirectory().getAbsolutePath()
) {
@Override
public void onEvent(int event, String path) {
if (event == FileObserver.DELETE) {
markFileDeleted(path.split("\\.")[0]);
}
markFileDeleted(path);
}
};
private final OnJinglePacketReceived jingleListener = new OnJinglePacketReceived() {
@ -768,7 +770,6 @@ public class XmppConnectionService extends Service {
getContentResolver().registerContentObserver(ContactsContract.Contacts.CONTENT_URI, true, contactObserver);
this.fileObserver.startWatching();
if (Config.supportOpenPgp()) {
this.pgpServiceConnection = new OpenPgpServiceConnection(getApplicationContext(), "org.sufficientlysecure.keychain", new OpenPgpServiceConnection.OnBound() {
@Override
@ -814,6 +815,7 @@ public class XmppConnectionService extends Service {
} catch (IllegalArgumentException e) {
//ignored
}
fileObserver.stopWatching();
super.onDestroy();
}
@ -1284,21 +1286,23 @@ public class XmppConnectionService extends Service {
});
}
private void markFileDeleted(String uuid) {
private void markFileDeleted(final String path) {
for (Conversation conversation : getConversations()) {
Message message = conversation.findMessageWithFileAndUuid(uuid);
if (message != null) {
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);
} else {
updateConversationUi();
conversation.findMessagesWithFiles(new Conversation.OnMessageFound() {
@Override
public void onMessageFound(Message message) {
DownloadableFile file = fileBackend.getFile(message);
if (file.getAbsolutePath().equals(path) && !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();
}
}
}
return;
}
});
}
}

View file

@ -0,0 +1,72 @@
package eu.siacs.conversations.utils;
import android.os.FileObserver;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
/**
* Copyright (C) 2012 Bartek Przybylski
* Copyright (C) 2015 ownCloud Inc.
* Copyright (C) 2016 Daniel Gultsch
*/
public abstract class ConversationsFileObserver {
private final String path;
private final List<SingleFileObserver> mObservers = new ArrayList<>();
public ConversationsFileObserver(String path) {
this.path = path;
}
public synchronized void startWatching() {
Stack<String> stack = new Stack<>();
stack.push(path);
while (!stack.empty()) {
String parent = stack.pop();
mObservers.add(new SingleFileObserver(parent, FileObserver.DELETE));
final File path = new File(parent);
final File[] files = path.listFiles();
if (files == null) {
continue;
}
for(File file : files) {
if (file.isDirectory() && !file.getName().equals(".") && !file.getName().equals("..")) {
stack.push(file.getPath());
}
}
}
for(FileObserver observer : mObservers) {
observer.startWatching();
}
}
public synchronized void stopWatching() {
for(FileObserver observer : mObservers) {
observer.stopWatching();
}
mObservers.clear();
}
abstract public void onEvent(int event, String path);
private class SingleFileObserver extends FileObserver {
private final String path;
public SingleFileObserver(String path, int mask) {
super(path, mask);
this.path = path;
}
@Override
public void onEvent(int event, String filename) {
ConversationsFileObserver.this.onEvent(event, path+'/'+filename);
}
}
}