Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 61776be7 authored by Vincent Bourgmayer's avatar Vincent Bourgmayer
Browse files

Merge branch '5-add-FileObserver' into '1-epic-refactoring-p1'

Add FileObserver to detect local file change

See merge request !78
parents 7fa69d9c 70541120
Loading
Loading
Loading
Loading
Loading
+29 −0
Original line number Diff line number Diff line
@@ -13,8 +13,11 @@ import android.accounts.AccountManager;
import android.app.Application;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Environment;
import android.util.Log;

import foundation.e.drive.FileObservers.FileEventListener;
import foundation.e.drive.FileObservers.RecursiveFileObserver;
import foundation.e.drive.utils.AppConstants;
import foundation.e.drive.utils.CommonUtils;

@@ -25,6 +28,8 @@ import foundation.e.drive.utils.CommonUtils;
public class EdriveApplication extends Application {

    private static final String TAG = "EdriveApplication";
    private RecursiveFileObserver mFileObserver = null;


    @Override
    public void onCreate() {
@@ -33,9 +38,14 @@ public class EdriveApplication extends Application {
        Log.i(TAG, "Starting");
        resetOperationManagerSetting();

        final String pathForObserver = Environment.getExternalStorageDirectory().getAbsolutePath();
        mFileObserver = new RecursiveFileObserver(getApplicationContext(), pathForObserver, new FileEventListener());

        SharedPreferences prefs = getSharedPreferences(AppConstants.SHARED_PREFERENCE_NAME, Context.MODE_PRIVATE);

        if (prefs.getString(AccountManager.KEY_ACCOUNT_NAME, null) != null) {
            Log.d(TAG, "Account already registered");
            startRecursiveFileObserver();
        } else {
            Account mAccount = CommonUtils.getAccount(getString(R.string.eelo_account_type), AccountManager.get(this));
            if (mAccount != null) {
@@ -56,6 +66,25 @@ public class EdriveApplication extends Application {
                .apply();
    }


    /**
     * Start Recursive FileObserver if not already watching
     */
    public void startRecursiveFileObserver(){
        if (!mFileObserver.isWatching()) {
            mFileObserver.startWatching();
            Log.d(TAG, "Starting RecursiveFileObserver on media's root folder");
        }
        else {
            Log.w(TAG, "RecursiveFileObserver (for media's root folder) was already running");
        }
    }

    public void stopRecursiveFileObserver(){
        mFileObserver.stopWatching();
        Log.d(TAG, "RecursiveFileObserver on media's root folder stops watching ");
    }

    @Override
    public void onLowMemory() {
        super.onLowMemory();
+30 −0
Original line number Diff line number Diff line
/*
 * Copyright © Narinder Rana (/e/ foundation).
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v3.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/gpl.html
 */

package foundation.e.drive.FileObservers;

import android.os.FileObserver;
import android.util.Log;

import java.io.File;

/**
 * @author Narinder Rana
 * @author vincent Bourgmayer
 */
public class FileEventListener  {
    private final static String TAG = FileEventListener.class.getSimpleName();

    public void onEvent(int event, File file) {
        if (event == FileObserver.CLOSE_WRITE) { //Event triggered after modification/creation
            Log.d(TAG, "CLOSE_WRITE event for :" + file.getName());
        } else if (event == FileObserver.DELETE) {
            Log.d(TAG, "DELETE event for :" + file.getName());
        }
    }
}
+174 −0
Original line number Diff line number Diff line
/*
 * Copyright © Narinder Rana (/e/ foundation).
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v3.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/gpl.html
 */

package foundation.e.drive.FileObservers;

import android.content.Context;
import android.os.FileObserver;

import java.io.File;
import java.io.FileFilter;
import java.util.HashMap;
import java.util.List;
import java.util.Stack;

import foundation.e.drive.database.DbHelper;
import foundation.e.drive.models.SyncedFolder;

/**
 * @author Narinder Rana
 * @author Vincent Bourgmayer
 */
public class RecursiveFileObserver extends FileObserver {
    private final HashMap<String, FileObserver> observers = new HashMap<>();
    private static final  FileFilter WATCHABLE_DIRECTORIES_FILTER = new FileFilter() {
        @Override
        public boolean accept(File file) {
            return file.isDirectory() && !file.getName().startsWith(".");
        }
    };

    private boolean watching = false;
    private final Context applicationContext;
    private String path;
    private int mask;
    private FileEventListener listener;

    public RecursiveFileObserver(Context applicationContext, String path, FileEventListener listener) {
        this(applicationContext, path, ALL_EVENTS, listener);
    }

    public RecursiveFileObserver(Context applicationContext, String path, int mask, FileEventListener listener) {
        super(path, mask);
        this.path = path;
        this.mask = mask | FileObserver.CREATE | FileObserver.DELETE_SELF;
        this.listener = listener;
        this.applicationContext = applicationContext;
    }


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

        notify(event, file);
    }

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

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

        List<SyncedFolder> mSyncedFolders = DbHelper.getAllSyncedFolders(applicationContext);
        if (!mSyncedFolders.isEmpty()){
            for (SyncedFolder syncedFolder:mSyncedFolders){
                stack.push(syncedFolder.getLocalFolder());
                stack.push(syncedFolder.getRemoteFolder());
            }
            watching = true;
        }

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

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

    /**
     * Start watching a single file
     * @param path
     */
    private void startWatching(String path) {
        synchronized (observers) {
            FileObserver observer = observers.remove(path);
            if (observer != null) {
                observer.stopWatching();
            }
            observer = new SingleFileObserver(path, mask);
            observer.startWatching();
            observers.put(path, observer);
        }
    }

    @Override
    public void stopWatching() {
        for (FileObserver observer : observers.values()) {
            observer.stopWatching();
        }
        observers.clear();
        watching = false;
    }

    /**
     * Stop watching a single file
     * @param path
     */
    private void stopWatching(String path) {
        synchronized (observers) {
            FileObserver observer = observers.remove(path);
            if (observer != null) {
                observer.stopWatching();
            }
        }
    }

    public boolean isWatching(){
        return watching;
    }

    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 (WATCHABLE_DIRECTORIES_FILTER.accept(file)) {
                        RecursiveFileObserver.this.startWatching(file.getAbsolutePath());
                    }
                    break;
            }

            RecursiveFileObserver.this.notify(event, file);
        }
    }
}
+33 −0
Original line number Diff line number Diff line
/*
 * Copyright © Narinder Rana (/e/ foundation).
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v3.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/gpl.html
 */

package foundation.e.drive.models;

import java.io.File;
import java.io.Serializable;
import java.util.List;

/**
 * @author Narinder Rana
 */
public class FileObserver implements Serializable {

    private List<File> files;
    public FileObserver(List<File> files) {
        this.files = files;

    }

    public List<File> getFiles() {
        return files;
    }

    public void setFiles(List<File> files) {
        this.files = files;
    }
}
+2 −1
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import foundation.e.drive.EdriveApplication;
import foundation.e.drive.models.SyncedFolder;
import foundation.e.drive.operations.CreateInitialFolderRemoteOperation;
import foundation.e.drive.utils.AppConstants;
@@ -280,7 +281,7 @@ public class InitializerService extends Service implements OnRemoteOperationList
        CommonUtils.registerPeriodicFullScanWorker(WorkManager.getInstance(appContext));

        //all folder have been created

        ((EdriveApplication) this.getApplication() ).startRecursiveFileObserver();

        //Immediatly start ObserverService to not have to wait 30 minutes.
        Intent observersServiceIntent = new Intent(getApplicationContext(), foundation.e.drive.services.ObserverService.class);
Loading