aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java/de/pixart/messenger/utils/ConversationsFileObserver.java
blob: 5e2948b5bbdad352bfeef548a3fdb01874a57464 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package de.pixart.messenger.utils;


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

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
import java.util.concurrent.atomic.AtomicBoolean;

import de.pixart.messenger.Config;

/**
 * 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<>();
    private final AtomicBoolean shouldStop = new AtomicBoolean(true);

    protected ConversationsFileObserver(String path) {
        this.path = path;
    }

    public void startWatching() {
        shouldStop.set(false);
        startWatchingInternal();
    }

    private synchronized void startWatchingInternal() {
        Stack<String> stack = new Stack<>();
        stack.push(path);

        while (!stack.empty()) {
            if (shouldStop.get()) {
                Log.d(Config.LOGTAG, "file observer received command to stop");
                return;
            }
            String parent = stack.pop();
            mObservers.add(new SingleFileObserver(parent, FileObserver.DELETE | FileObserver.MOVED_FROM));
            final File path = new File(parent);
            File[] files = new File[0];
            try {
                files = path.listFiles();
            } catch (OutOfMemoryError e) {
                e.printStackTrace();
            }
            if (files == null) {
                continue;
            }
            for (File file : files) {
                if (shouldStop.get()) {
                    Log.d(Config.LOGTAG, "file observer received command to stop");
                    return;
                }
                if (file.isDirectory() && file.getName().charAt(0) != '.') {
                    final String currentPath = file.getAbsolutePath();
                    if (depth(file) <= 8 && !stack.contains(currentPath) && !observing(currentPath)) {
                        stack.push(currentPath);
                    }
                }
            }
        }
        for (FileObserver observer : mObservers) {
            observer.startWatching();
        }
    }

    private static int depth(File file) {
        int depth = 0;
        while ((file = file.getParentFile()) != null) {
            depth++;
        }
        return depth;
    }

    private boolean observing(String path) {
        for (SingleFileObserver observer : mObservers) {
            if (path.equals(observer.path)) {
                return true;
            }
        }
        return false;
    }

    public void stopWatching() {
        shouldStop.set(true);
        stopWatchingInternal();
    }

    private synchronized void stopWatchingInternal() {
        for (FileObserver observer : mObservers) {
            observer.stopWatching();
        }
        mObservers.clear();
    }

    abstract public void onEvent(int event, String path);

    public void restartWatching() {
        stopWatching();
        startWatching();
    }

    private class SingleFileObserver extends FileObserver {
        private final String path;

        SingleFileObserver(String path, int mask) {
            super(path, mask);
            this.path = path;
        }

        @Override
        public void onEvent(int event, String filename) {
            if (filename == null) {
                Log.d(Config.LOGTAG, "ignored file event with NULL filename (event=" + event + ")");
                return;
            }
            ConversationsFileObserver.this.onEvent(event, path + '/' + filename);
        }

    }
}