ConversationsFileObserver.java

  1package eu.siacs.conversations.utils;
  2
  3
  4import android.os.FileObserver;
  5import android.util.Log;
  6
  7import java.io.File;
  8import java.util.ArrayList;
  9import java.util.List;
 10import java.util.Stack;
 11
 12import eu.siacs.conversations.Config;
 13
 14/**
 15 * Copyright (C) 2012 Bartek Przybylski
 16 * Copyright (C) 2015 ownCloud Inc.
 17 * Copyright (C) 2016 Daniel Gultsch
 18 */
 19
 20public abstract class ConversationsFileObserver {
 21
 22    private final String path;
 23    private final List<SingleFileObserver> mObservers = new ArrayList<>();
 24
 25    protected ConversationsFileObserver(String path) {
 26        this.path = path;
 27    }
 28
 29    public synchronized void startWatching() {
 30        Stack<String> stack = new Stack<>();
 31        stack.push(path);
 32
 33        while (!stack.empty()) {
 34            String parent = stack.pop();
 35            mObservers.add(new SingleFileObserver(parent, FileObserver.DELETE| FileObserver.MOVED_FROM));
 36            final File path = new File(parent);
 37            final File[] files = path.listFiles();
 38            if (files == null) {
 39                continue;
 40            }
 41            for(File file : files) {
 42                if (file.isDirectory() && file.getName().charAt(0) != '.') {
 43                    final String currentPath = file.getAbsolutePath();
 44                    if (depth(file) <= 8 && !stack.contains(currentPath) && !observing(currentPath)) {
 45                        stack.push(currentPath);
 46                    }
 47                }
 48            }
 49        }
 50        for(FileObserver observer : mObservers) {
 51            observer.startWatching();
 52        }
 53    }
 54
 55    private static int depth(File file) {
 56        int depth = 0;
 57        while((file = file.getParentFile()) != null) {
 58            depth++;
 59        }
 60        return depth;
 61    }
 62
 63    private boolean observing(String path) {
 64        for(SingleFileObserver observer : mObservers) {
 65            if(path.equals(observer.path)) {
 66                return true;
 67            }
 68        }
 69        return false;
 70    }
 71
 72    public synchronized void stopWatching() {
 73        for(FileObserver observer : mObservers) {
 74            observer.stopWatching();
 75        }
 76        mObservers.clear();
 77    }
 78
 79    abstract public void onEvent(int event, String path);
 80
 81    public void restartWatching() {
 82        stopWatching();
 83        startWatching();
 84    }
 85
 86    private class SingleFileObserver extends FileObserver {
 87        private final String path;
 88
 89        SingleFileObserver(String path, int mask) {
 90            super(path, mask);
 91            this.path = path;
 92        }
 93
 94        @Override
 95        public void onEvent(int event, String filename) {
 96            if (filename == null) {
 97                Log.d(Config.LOGTAG,"ignored file event with NULL filename (event="+event+")");
 98                return;
 99            }
100            ConversationsFileObserver.this.onEvent(event, path+'/'+filename);
101        }
102
103    }
104}