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}