Unable to copy file to designated path before its deletion through RecursiveFileObserver

27 views Asked by At

FileObserverService.java

package com.example.statussaver.Utils;


import static android.os.FileObserver.ALL_EVENTS;
import static android.os.FileObserver.DELETE;
import static android.os.FileObserver.DELETE_SELF;
import static android.os.FileObserver.MOVED_FROM;
import static android.os.FileObserver.MOVED_TO;

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.FileObserver;
import android.os.Handler;
import android.os.IBinder;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.util.Log;
import android.widget.Toast;

import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;

import com.example.statussaver.R;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;

public class FileObserverService extends NotificationListenerService {
    private RecursiveFileObserver fileObserver;
    private String targetDirectory;

    @Override
    public void onCreate() {
        super.onCreate();
        setupFileObserver();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return START_STICKY;
    }

    @Override
    public void onNotificationPosted(StatusBarNotification sbn) {
        super.onNotificationPosted(sbn);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    String TAG = "de_ser";

    private void setupFileObserver() {
        targetDirectory = Consts.CPY_FILES_DIR;

        fileObserver = new RecursiveFileObserver(Consts.WHATSAPP_DIRECTORY, new RecursiveFileObserver.EventListener() {
            @Override
            public void onEvent(int event, File file) {
                if (file.exists()) {
                    Log.e("file_chk", "File: " + file);
                } else {
                    Log.e("file_chk", "File not found");
                }
                switch (event) {
                    case DELETE: {
                        Log.d(TAG, "onEvent: DELETE " + file.exists());
                        handleFileDelete(file);
                    }
                    break;
                    default:
                        break;
                }
            }
        });

        fileObserver.startWatching();
            }

    private void handleFileDelete(File deletedFile) {
        File fileDirectory = new File(Consts.CPY_FILES_DIR);
        if (!fileDirectory.exists()) {
            fileDirectory.mkdirs();
        }

        if (deletedFile.exists()) {
            try {
                String fileName = deletedFile.getName();

                File destDirectory;
                if (fileName.contains(".mp4")) {
                    destDirectory = new File(Consts.VID_FILE_DIR);
                } else if (fileName.contains(".jpg") || fileName.contains(".jpeg") || fileName.contains(".png") || fileName.contains(".webp")) {
                    destDirectory = new File(Consts.IMG_FILE_DIR);
                } else if (fileName.contains(".aac") || fileName.contains(".mp3")) {
                    destDirectory = new File(Consts.AUD_FILE_DIR);
                } else if (fileName.contains(".opus") || fileName.contains(".ogg")) {
                    destDirectory = new File(Consts.VOICE_FILE_DIR);
                } else {
                    destDirectory = new File(Consts.DOC_FILE_DIR);
                }

                if (!destDirectory.exists()) {
                    destDirectory.mkdirs();
                }

                File destFile = new File(destDirectory, fileName);

                // Copy the file before deletion
                copyFile(deletedFile, destFile);

                // Now you can delete the file
                boolean isDeleted = deletedFile.delete();
                if (isDeleted) {
                    Log.e(TAG, "File deleted: " + deletedFile.getAbsolutePath());
                } else {
                    Log.e(TAG, "Failed to delete file: " + deletedFile.getAbsolutePath());
                }

            } catch (IOException e) {
                e.printStackTrace();
                Log.e(TAG, "Error copying file: " + e.getMessage());
            }
        }else {
            Log.e(TAG, "File does not exist anymore: " + deletedFile.getAbsolutePath());
        }
    }

            private void copyFile(File sourceFile, File destFile) throws IOException {

                try (FileInputStream fis = new FileInputStream(sourceFile);
                     FileOutputStream fos = new FileOutputStream(destFile);
                     FileChannel source = fis.getChannel();
                     FileChannel destination = fos.getChannel()) {
                    destination.transferFrom(source, 0, source.size());
                }
                Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
                mediaScanIntent.setData(Uri.fromFile(destFile));
                sendBroadcast(mediaScanIntent);
            }

    }

RecursiveFileObserver.java

package com.example.statussaver.Utils;

import android.os.FileObserver;

import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;

public class RecursiveFileObserver extends FileObserver{

    private final Map<String, FileObserver> mObservers = new HashMap<>();

    private String mPath;

    private int mMask;

    private EventListener mListener;

    public interface EventListener {
        void onEvent(int event, File file);
    }

    public RecursiveFileObserver(String path, EventListener listener) {
        this(path, ALL_EVENTS, listener);
    }

    public RecursiveFileObserver(String path, int mask, EventListener listener) {
        super(path, mask);
        mPath = path;
        mMask = mask | FileObserver.CREATE | FileObserver.DELETE_SELF;
        mListener = listener;
    }

    private void startWatching(String path) {
        synchronized (mObservers) {
            FileObserver observer = mObservers.remove(path);
            if (observer != null) {
                observer.stopWatching();
            }
            observer = new SingleFileObserver(path, mMask);
            observer.startWatching();
            mObservers.put(path, observer);
        }
    }

    @Override
    public void startWatching() {
        Stack<String> stack = new Stack<>();
        stack.push(mPath);

        // Recursively watch all child directories
        while (!stack.empty()) {
            String parent = stack.pop();
            startWatching(parent);

            File path = new File(parent);
            File[] files = path.listFiles();
            if (files != null) {
                for (File file : files) {
                    if (watch(file)) {
                        stack.push(file.getAbsolutePath());
                    }
                }
            }
        }
    }

    private boolean watch(File file) {
        return file.isDirectory() && !file.getName().equals(".") && !file.getName().equals("..");
    }

    private void stopWatching(String path) {
        synchronized (mObservers) {
            FileObserver observer = mObservers.remove(path);
            if (observer != null) {
                observer.stopWatching();
            }
        }
    }

    @Override
    public void stopWatching() {
        synchronized (mObservers) {
            for (FileObserver observer : mObservers.values()) {
                observer.stopWatching();
            }
            mObservers.clear();
        }
    }

    @Override
    public void onEvent(int event, String path) {
        File file;
        if (path == null) {
            file = new File(mPath);
        } else {
            file = new File(mPath, path);
        }
        notify(event, file);
    }

    private void notify(int event, File file) {
        if (mListener != null) {
            mListener.onEvent(event & FileObserver.ALL_EVENTS, file);
        }
    }

    private class SingleFileObserver extends FileObserver {
        private String filePath;

        public SingleFileObserver(String path, int mask) {
            super(path, mask);
            filePath = path;
        }

        @Override
        public void onEvent(int event, String path) {
            File file;
            if (path == null) {
                file = new File(filePath);
            } else {
                file = new File(filePath, path);
            }

            switch (event & FileObserver.ALL_EVENTS) {
                case DELETE_SELF:
                    RecursiveFileObserver.this.stopWatching(filePath);
                    break;
                case CREATE:
                    if (watch(file)) {
                        RecursiveFileObserver.this.startWatching(file.getAbsolutePath());
                    }
                    break;
            }

            RecursiveFileObserver.this.notify(event, file);
        }
    }
}

Consts.java

package com.example.statussaver.Utils;

import android.os.Environment;

import java.io.File;

public class Consts {
    public static final File STATUS_DIRECTORY = new File(Environment.getExternalStorageDirectory()
            + File.separator + "WhatsApp/Media/.Statuses");
 public static final String WHATSAPP_DIRECTORY = Environment.getExternalStorageDirectory()
            + File.separator + "WhatsApp/Media";
 public static final String WHATSAPP_IMG_DIRECTORY = Environment.getExternalStorageDirectory()
            + File.separator + "Pictures";

    public static final File STATUS_DIRECTORY_BUSINESS = new File(Environment.getExternalStorageDirectory()
            + File.separator + "WhatsApp Business/Media/.Statuses");

    public static final String APP_DIR = Environment.getExternalStorageDirectory()
            + File.separator + "StatusSaverDir";
    public static final String CPY_FILES_DIR = Environment.getExternalStorageDirectory()
            + File.separator + "WhatsWebCpyFiles";
    public static final String VID_FILE_DIR = Environment.getExternalStorageDirectory()
            + File.separator + "Videos";
    public static final String IMG_FILE_DIR = Environment.getExternalStorageDirectory()
            + File.separator + "Images";
    public static final String AUD_FILE_DIR = Environment.getExternalStorageDirectory()
            + File.separator + "Audios";
    public static final String DOC_FILE_DIR = Environment.getExternalStorageDirectory()
            + File.separator + "Documents";
    public static final String VOICE_FILE_DIR = Environment.getExternalStorageDirectory()
            + File.separator + "Voices";
    public static final String APP_DIR_BUSINESS = Environment.getExternalStorageDirectory()
            + File.separator + "BusinessStatusSaverDir";

    public static final File APP_DIR_SAVED = new File(Environment.getExternalStorageDirectory()
            + File.separator + "StatusSaverDir");

    public static final int THUMBSIZE = 128;
}

I am trying to copy file to a designated path when Delete event is triggered, but the file is being deleted before copy. I have tried to delay the delete event as well but it is not working. I want to copy the file that is being deleted to the designated first, and then execute the deletion process

0

There are 0 answers